diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 83f8e1b0d5..afc43930fd 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -1,15278 +1,15278 @@
-/*
- * 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.Diagnostics;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.Runtime.Remoting.Lifetime;
-using System.Text;
-using System.Threading;
-using System.Text.RegularExpressions;
-using Nini.Config;
-using log4net;
-using OpenMetaverse;
-using OpenMetaverse.Assets;
-using OpenMetaverse.Packets;
-using OpenMetaverse.Rendering;
-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;
-using System.Linq;
-using PermissionMask = OpenSim.Framework.PermissionMask;
-
-namespace OpenSim.Region.ScriptEngine.Shared.Api
-{
- // MUST be a ref type
- public class UserInfoCacheEntry
- {
- public int time;
- public UserAccount account;
- public PresenceInfo pinfo;
- }
-
- ///
- /// Contains all LSL ll-functions. This class will be in Default AppDomain.
- ///
- public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
- {
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- public int LlRequestAgentDataCacheTimeoutMs { get; set; }
-
- protected IScriptEngine m_ScriptEngine;
- protected SceneObjectPart m_host;
-
- ///
- /// Used for script sleeps when we are using co-operative script termination.
- ///
- /// null if co-operative script termination is not active
- WaitHandle m_coopSleepHandle;
-
- ///
- /// The timer used by the ScriptInstance to measure how long the script has executed.
- ///
- private Stopwatch m_executionTimer;
-
- ///
- /// The item that hosts this script
- ///
- protected TaskInventoryItem m_item;
-
- protected bool throwErrorOnNotImplemented = false;
- 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 m_userInfoCache = new Dictionary();
- protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp.
- protected int m_sleepMsOnSetTexture = 200;
- protected int m_sleepMsOnSetLinkTexture = 200;
- protected int m_sleepMsOnScaleTexture = 200;
- protected int m_sleepMsOnOffsetTexture = 200;
- protected int m_sleepMsOnRotateTexture = 200;
- protected int m_sleepMsOnSetPos = 200;
- protected int m_sleepMsOnSetRot = 200;
- protected int m_sleepMsOnSetLocalRot = 200;
- protected int m_sleepMsOnPreloadSound = 1000;
- protected int m_sleepMsOnMakeExplosion = 100;
- protected int m_sleepMsOnMakeFountain = 100;
- protected int m_sleepMsOnMakeSmoke = 100;
- protected int m_sleepMsOnMakeFire = 100;
- protected int m_sleepMsOnRezAtRoot = 100;
- protected int m_sleepMsOnInstantMessage = 2000;
- protected int m_sleepMsOnEmail = 20000;
- protected int m_sleepMsOnCreateLink = 1000;
- protected int m_sleepMsOnGiveInventory = 3000;
- protected int m_sleepMsOnRequestAgentData = 100;
- protected int m_sleepMsOnRequestInventoryData = 1000;
- protected int m_sleepMsOnSetDamage = 5000;
- protected int m_sleepMsOnTextBox = 1000;
- protected int m_sleepMsOnAdjustSoundVolume = 100;
- protected int m_sleepMsOnEjectFromLand = 5000;
- protected int m_sleepMsOnAddToLandPassList = 100;
- protected int m_sleepMsOnDialog = 1000;
- protected int m_sleepMsOnRemoteLoadScript = 3000;
- protected int m_sleepMsOnRemoteLoadScriptPin = 3000;
- protected int m_sleepMsOnOpenRemoteDataChannel = 1000;
- protected int m_sleepMsOnSendRemoteData = 3000;
- protected int m_sleepMsOnRemoteDataReply = 3000;
- protected int m_sleepMsOnCloseRemoteDataChannel = 1000;
- protected int m_sleepMsOnSetPrimitiveParams = 200;
- protected int m_sleepMsOnSetLinkPrimitiveParams = 200;
- protected int m_sleepMsOnXorBase64Strings = 300;
- protected int m_sleepMsOnSetParcelMusicURL = 2000;
- protected int m_sleepMsOnGetPrimMediaParams = 1000;
- protected int m_sleepMsOnGetLinkMedia = 1000;
- protected int m_sleepMsOnSetPrimMediaParams = 1000;
- protected int m_sleepMsOnSetLinkMedia = 1000;
- protected int m_sleepMsOnClearPrimMedia = 1000;
- protected int m_sleepMsOnClearLinkMedia = 1000;
- protected int m_sleepMsOnRequestSimulatorData = 1000;
- protected int m_sleepMsOnLoadURL = 10000;
- protected int m_sleepMsOnParcelMediaCommandList = 2000;
- protected int m_sleepMsOnParcelMediaQuery = 2000;
- protected int m_sleepMsOnModPow = 1000;
- protected int m_sleepMsOnSetPrimURL = 2000;
- protected int m_sleepMsOnRefreshPrimURL = 20000;
- protected int m_sleepMsOnMapDestination = 1000;
- protected int m_sleepMsOnAddToLandBanList = 100;
- protected int m_sleepMsOnRemoveFromLandPassList = 100;
- protected int m_sleepMsOnRemoveFromLandBanList = 100;
- protected int m_sleepMsOnResetLandBanList = 100;
- protected int m_sleepMsOnResetLandPassList = 100;
- protected int m_sleepMsOnGetParcelPrimOwners = 2000;
- protected int m_sleepMsOnGetNumberOfNotecardLines = 100;
- protected int m_sleepMsOnGetNotecardLine = 100;
- protected string m_internalObjectHost = "lsl.opensim.local";
- protected bool m_restrictEmail = false;
- protected ISoundModule m_SoundModule = null;
-
- protected float m_avatarHeightCorrection = 0.2f;
- protected bool m_useSimpleBoxesInGetBoundingBox = false;
- protected bool m_addStatsInGetBoundingBox = false;
-
- //LSL Avatar Bounding Box (lABB), lower (1) and upper (2),
- //standing (Std), Groundsitting (Grs), Sitting (Sit),
- //along X, Y and Z axes, constants (0) and coefficients (1)
- protected float m_lABB1StdX0 = -0.275f;
- protected float m_lABB2StdX0 = 0.275f;
- protected float m_lABB1StdY0 = -0.35f;
- protected float m_lABB2StdY0 = 0.35f;
- protected float m_lABB1StdZ0 = -0.1f;
- protected float m_lABB1StdZ1 = -0.5f;
- protected float m_lABB2StdZ0 = 0.1f;
- protected float m_lABB2StdZ1 = 0.5f;
- protected float m_lABB1GrsX0 = -0.3875f;
- protected float m_lABB2GrsX0 = 0.3875f;
- protected float m_lABB1GrsY0 = -0.5f;
- protected float m_lABB2GrsY0 = 0.5f;
- protected float m_lABB1GrsZ0 = -0.05f;
- protected float m_lABB1GrsZ1 = -0.375f;
- protected float m_lABB2GrsZ0 = 0.5f;
- protected float m_lABB2GrsZ1 = 0.0f;
- protected float m_lABB1SitX0 = -0.5875f;
- protected float m_lABB2SitX0 = 0.1875f;
- protected float m_lABB1SitY0 = -0.35f;
- protected float m_lABB2SitY0 = 0.35f;
- protected float m_lABB1SitZ0 = -0.35f;
- protected float m_lABB1SitZ1 = -0.375f;
- protected float m_lABB2SitZ0 = -0.25f;
- protected float m_lABB2SitZ1 = 0.25f;
-
- protected float m_primSafetyCoeffX = 2.414214f;
- protected float m_primSafetyCoeffY = 2.414214f;
- protected float m_primSafetyCoeffZ = 1.618034f;
- protected bool m_useCastRayV3 = false;
- protected float m_floatToleranceInCastRay = 0.00001f;
- protected float m_floatTolerance2InCastRay = 0.001f;
- protected DetailLevel m_primLodInCastRay = DetailLevel.Medium;
- protected DetailLevel m_sculptLodInCastRay = DetailLevel.Medium;
- protected DetailLevel m_meshLodInCastRay = DetailLevel.Highest;
- protected DetailLevel m_avatarLodInCastRay = DetailLevel.Medium;
- protected int m_maxHitsInCastRay = 16;
- protected int m_maxHitsPerPrimInCastRay = 16;
- protected int m_maxHitsPerObjectInCastRay = 16;
- protected bool m_detectExitsInCastRay = false;
- protected bool m_filterPartsInCastRay = false;
- protected bool m_doAttachmentsInCastRay = false;
- protected int m_msThrottleInCastRay = 200;
- protected int m_msPerRegionInCastRay = 40;
- protected int m_msPerAvatarInCastRay = 10;
- protected int m_msMinInCastRay = 2;
- protected int m_msMaxInCastRay = 40;
- protected static List m_castRayCalls = new List();
- protected bool m_useMeshCacheInCastRay = true;
- protected static Dictionary m_cachedMeshes = new Dictionary();
-
- //An array of HTTP/1.1 headers that are not allowed to be used
- //as custom headers by llHTTPRequest.
- private string[] HttpStandardHeaders =
- {
- "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language",
- "Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control",
- "Connection", "Content-Encoding", "Content-Language",
- "Content-Length", "Content-Location", "Content-MD5",
- "Content-Range", "Content-Type", "Date", "ETag", "Expect",
- "Expires", "From", "Host", "If-Match", "If-Modified-Since",
- "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified",
- "Location", "Max-Forwards", "Pragma", "Proxy-Authenticate",
- "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server",
- "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent",
- "Vary", "Via", "Warning", "WWW-Authenticate"
- };
-
- public void Initialize(
- IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle,
- Stopwatch executionTimer)
- {
- m_ScriptEngine = scriptEngine;
- m_host = host;
- m_item = item;
- m_coopSleepHandle = coopSleepHandle;
- m_executionTimer = executionTimer;
-
- LoadConfig();
-
- m_TransferModule =
- m_ScriptEngine.World.RequestModuleInterface();
- m_UrlModule = m_ScriptEngine.World.RequestModuleInterface();
- m_SoundModule = m_ScriptEngine.World.RequestModuleInterface();
-
- AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
- }
-
- ///
- /// Load configuration items that affect script, object and run-time behavior. */
- ///
- private void LoadConfig()
- {
- LlRequestAgentDataCacheTimeoutMs = 20000;
-
- IConfig seConfig = m_ScriptEngine.Config;
-
- if (seConfig != null)
- {
- m_ScriptDelayFactor =
- seConfig.GetFloat("ScriptDelayFactor", m_ScriptDelayFactor);
- m_ScriptDistanceFactor =
- seConfig.GetFloat("ScriptDistanceLimitFactor", m_ScriptDistanceFactor);
- m_MinTimerInterval =
- seConfig.GetFloat("MinTimerInterval", m_MinTimerInterval);
- m_automaticLinkPermission =
- seConfig.GetBoolean("AutomaticLinkPermission", m_automaticLinkPermission);
- m_notecardLineReadCharsMax =
- seConfig.GetInt("NotecardLineReadCharsMax", m_notecardLineReadCharsMax);
-
- // 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);
- }
-
- if (m_notecardLineReadCharsMax > 65535)
- m_notecardLineReadCharsMax = 65535;
-
- // load limits for particular subsystems.
- IConfigSource seConfigSource = m_ScriptEngine.ConfigSource;
-
- if (seConfigSource != null)
- {
- IConfig lslConfig = seConfigSource.Configs["LL-Functions"];
- if (lslConfig != null)
- {
- m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail);
- m_avatarHeightCorrection = lslConfig.GetFloat("AvatarHeightCorrection", m_avatarHeightCorrection);
- m_useSimpleBoxesInGetBoundingBox = lslConfig.GetBoolean("UseSimpleBoxesInGetBoundingBox", m_useSimpleBoxesInGetBoundingBox);
- m_addStatsInGetBoundingBox = lslConfig.GetBoolean("AddStatsInGetBoundingBox", m_addStatsInGetBoundingBox);
- m_lABB1StdX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingXconst", m_lABB1StdX0);
- m_lABB2StdX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingXconst", m_lABB2StdX0);
- m_lABB1StdY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingYconst", m_lABB1StdY0);
- m_lABB2StdY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingYconst", m_lABB2StdY0);
- m_lABB1StdZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZconst", m_lABB1StdZ0);
- m_lABB1StdZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZcoeff", m_lABB1StdZ1);
- m_lABB2StdZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZconst", m_lABB2StdZ0);
- m_lABB2StdZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZcoeff", m_lABB2StdZ1);
- m_lABB1GrsX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingXconst", m_lABB1GrsX0);
- m_lABB2GrsX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingXconst", m_lABB2GrsX0);
- m_lABB1GrsY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingYconst", m_lABB1GrsY0);
- m_lABB2GrsY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingYconst", m_lABB2GrsY0);
- m_lABB1GrsZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZconst", m_lABB1GrsZ0);
- m_lABB1GrsZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZcoeff", m_lABB1GrsZ1);
- m_lABB2GrsZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZconst", m_lABB2GrsZ0);
- m_lABB2GrsZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZcoeff", m_lABB2GrsZ1);
- m_lABB1SitX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingXconst", m_lABB1SitX0);
- m_lABB2SitX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingXconst", m_lABB2SitX0);
- m_lABB1SitY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingYconst", m_lABB1SitY0);
- m_lABB2SitY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingYconst", m_lABB2SitY0);
- m_lABB1SitZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZconst", m_lABB1SitZ0);
- m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1);
- m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0);
- m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1);
- m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX);
- m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY);
- m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ);
- m_useCastRayV3 = lslConfig.GetBoolean("UseLlCastRayV3", m_useCastRayV3);
- m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay);
- m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay);
- m_primLodInCastRay = (DetailLevel)lslConfig.GetInt("PrimDetailLevelInLlCastRay", (int)m_primLodInCastRay);
- m_sculptLodInCastRay = (DetailLevel)lslConfig.GetInt("SculptDetailLevelInLlCastRay", (int)m_sculptLodInCastRay);
- m_meshLodInCastRay = (DetailLevel)lslConfig.GetInt("MeshDetailLevelInLlCastRay", (int)m_meshLodInCastRay);
- m_avatarLodInCastRay = (DetailLevel)lslConfig.GetInt("AvatarDetailLevelInLlCastRay", (int)m_avatarLodInCastRay);
- m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay);
- m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay);
- m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay);
- m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay);
- m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay);
- m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay);
- m_msThrottleInCastRay = lslConfig.GetInt("ThrottleTimeInMsInLlCastRay", m_msThrottleInCastRay);
- m_msPerRegionInCastRay = lslConfig.GetInt("AvailableTimeInMsPerRegionInLlCastRay", m_msPerRegionInCastRay);
- m_msPerAvatarInCastRay = lslConfig.GetInt("AvailableTimeInMsPerAvatarInLlCastRay", m_msPerAvatarInCastRay);
- m_msMinInCastRay = lslConfig.GetInt("RequiredAvailableTimeInMsInLlCastRay", m_msMinInCastRay);
- m_msMaxInCastRay = lslConfig.GetInt("MaximumAvailableTimeInMsInLlCastRay", m_msMaxInCastRay);
- m_useMeshCacheInCastRay = lslConfig.GetBoolean("UseMeshCacheInLlCastRay", m_useMeshCacheInCastRay);
- }
-
- IConfig smtpConfig = seConfigSource.Configs["SMTP"];
- if (smtpConfig != null)
- {
- // there's an smtp config, so load in the snooze time.
- EMAIL_PAUSE_TIME = smtpConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME);
-
- m_internalObjectHost = smtpConfig.GetString("internal_object_host", m_internalObjectHost);
- }
- }
- m_sleepMsOnEmail = EMAIL_PAUSE_TIME * 1000;
- }
-
- 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_executionTimer != null)
- m_executionTimer.Stop(); // sleep time doesn't count as execution time, since it doesn't use the CPU
-
- try
- {
- if (m_coopSleepHandle == null)
- System.Threading.Thread.Sleep(delay);
- else
- CheckForCoopTermination(delay);
- }
- finally
- {
- if (m_executionTimer != null)
- m_executionTimer.Start();
- }
- }
-
- ///
- /// Check for co-operative termination.
- ///
- /// If called with 0, then just the check is performed with no wait.
- 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);
- }
-
- ///
- /// Reset the named script. The script must be present
- /// in the same prim.
- ///
- 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
- Error("llResetOtherScript", "Can't find script '" + name + "'");
- }
-
- 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;
- }
-
- Error("llGetScriptState", "Can't find script '" + name + "'");
-
- // 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
- {
- Error("llSetScriptState", "Can't find script '" + name + "'");
- }
- }
-
- ///
- /// Get a given link entity from a linkset (linked objects and any sitting avatars).
- ///
- ///
- /// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then
- /// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset.
- /// The ScenePresences receive linknums in the order in which they sat.
- ///
- ///
- /// The link entity. null if not found.
- ///
- ///
- ///
- /// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4).
- /// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned.
- /// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any
- /// positive integer is given in this case then null is returned.
- /// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number
- /// of entities, then the entity which corresponds to that linknum is returned.
- /// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then
- /// null is returned.
- ///
- public ISceneEntity GetLinkEntity(SceneObjectPart part, int linknum)
- {
- if (linknum < 0)
- {
- if (linknum == ScriptBaseClass.LINK_THIS)
- return part;
- else
- return null;
- }
-
- int actualPrimCount = part.ParentGroup.PrimCount;
- List sittingAvatars = part.ParentGroup.GetSittingAvatars();
- int adjustedPrimCount = actualPrimCount + sittingAvatars.Count;
-
- // Special case for a single prim. In this case the linknum is zero. However, this will not match a single
- // prim that has any avatars sat upon it (in which case the root prim is link 1).
- if (linknum == 0)
- {
- if (actualPrimCount == 1 && sittingAvatars.Count == 0)
- return part;
-
- return null;
- }
- // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
- // here we must match 1 (ScriptBaseClass.LINK_ROOT).
- else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1)
- {
- if (sittingAvatars.Count > 0)
- return part.ParentGroup.RootPart;
- else
- return null;
- }
- else if (linknum <= adjustedPrimCount)
- {
- if (linknum <= actualPrimCount)
- {
- return part.ParentGroup.GetLinkNumPart(linknum);
- }
- else
- {
- return sittingAvatars[linknum - actualPrimCount - 1];
- }
- }
- else
- {
- return null;
- }
- }
-
- public List GetLinkParts(int linkType)
- {
- return GetLinkParts(m_host, linkType);
- }
-
- public static List GetLinkParts(SceneObjectPart part, int linkType)
- {
- List ret = new List();
- ret.Add(part);
-
- switch (linkType)
- {
- case ScriptBaseClass.LINK_SET:
- return new List(part.ParentGroup.Parts);
-
- case ScriptBaseClass.LINK_ROOT:
- ret = new List();
- ret.Add(part.ParentGroup.RootPart);
- return ret;
-
- case ScriptBaseClass.LINK_ALL_OTHERS:
- ret = new List(part.ParentGroup.Parts);
-
- if (ret.Contains(part))
- ret.Remove(part);
-
- return ret;
-
- case ScriptBaseClass.LINK_ALL_CHILDREN:
- ret = new List(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 target = part.ParentGroup.GetLinkNumPart(linkType);
- if (target == null)
- return new List();
- ret = new List();
- ret.Add(target);
- return ret;
- }
- }
-
- public List GetLinkEntities(int linkType)
- {
- return GetLinkEntities(m_host, linkType);
- }
-
- public List GetLinkEntities(SceneObjectPart part, int linkType)
- {
- List ret;
-
- switch (linkType)
- {
- case ScriptBaseClass.LINK_SET:
- return new List(part.ParentGroup.Parts);
-
- case ScriptBaseClass.LINK_ROOT:
- return new List() { part.ParentGroup.RootPart };
-
- case ScriptBaseClass.LINK_ALL_OTHERS:
- ret = new List(part.ParentGroup.Parts);
-
- if (ret.Contains(part))
- ret.Remove(part);
-
- return ret;
-
- case ScriptBaseClass.LINK_ALL_CHILDREN:
- ret = new List(part.ParentGroup.Parts);
-
- if (ret.Contains(part.ParentGroup.RootPart))
- ret.Remove(part.ParentGroup.RootPart);
-
- return ret;
-
- case ScriptBaseClass.LINK_THIS:
- return new List() { part };
-
- default:
- if (linkType < 0)
- return new List();
-
- ISceneEntity target = GetLinkEntity(part, linkType);
- if (target == null)
- return new List();
-
- return new List() { target };
- }
- }
-
- //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);
-
- 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
-
- ///
- /// Convert an LSL rotation to a Euler vector.
- ///
- ///
- /// 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
- ///
- ///
- ///
- 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()=<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();
- 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();
- 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();
- 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)
- {
- Error("llRegionSay", "Cannot use on channel 0");
- return;
- }
-
- if (text.Length > 1023)
- text = text.Substring(0, 1023);
-
- m_host.AddScriptLPS(1);
-
- World.SimChat(Utils.StringToBytes(text),
- ChatTypeEnum.Region, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
-
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface();
- 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);
-
- World.SimChatToAgent(TargetID, Utils.StringToBytes(msg),
- channel, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true);
-
- IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface();
- 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();
- 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();
- 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();
- 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();
- 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);
- }
-
- ///
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchBinormal for details
- ///
- 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;
- }
-
- ///
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchFace for details
- ///
- 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);
- }
-
- ///
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchNormal for details
- ///
- 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;
- }
-
- ///
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchPos for details
- ///
- 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;
- }
-
- ///
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchST for details
- ///
- 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;
- }
-
- ///
- /// See http://wiki.secondlife.com/wiki/LlDetectedTouchUV for details
- ///
- 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();
- 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();
- 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)
- m_host.BlockGrab = value != 0;
-
- if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT) == ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT)
- m_host.ParentGroup.BlockGrabOverride = value != 0;
-
- 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:
- return m_host.BlockGrab ? 1 : 0;
-
- case ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT:
- return m_host.ParentGroup.BlockGrabOverride ? 1 : 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;
-
- case ScriptBaseClass.STATUS_SANDBOX:
- if (m_host.GetStatusSandbox())
- return 1;
- else
- return 0;
- }
- return 0;
- }
-
- public void llSetScale(LSL_Vector scale)
- {
- m_host.AddScriptLPS(1);
- SetScale(m_host, scale);
- }
-
- protected void SetScale(SceneObjectPart part, LSL_Vector scale)
- {
- // TODO: this needs to trigger a persistance save as well
- if (part == null || part.ParentGroup.IsDeleted)
- return;
-
- // First we need to check whether or not we need to clamp the size of a physics-enabled prim
- PhysicsActor pa = part.ParentGroup.RootPart.PhysActor;
- if (pa != null && pa.IsPhysical)
- {
- scale.x = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.x));
- scale.y = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.y));
- scale.z = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.z));
- }
- else
- {
- // If not physical, then we clamp the scale to the non-physical min/max
- scale.x = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.x));
- scale.y = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.y));
- scale.z = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.z));
- }
-
- Vector3 tmp = part.Scale;
- tmp.X = (float)scale.x;
- tmp.Y = (float)scale.y;
- tmp.Z = (float)scale.z;
- part.Scale = tmp;
- part.SendFullUpdateToAllClients();
- }
-
- public LSL_Vector llGetScale()
- {
- m_host.AddScriptLPS(1);
- return new LSL_Vector(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
- }
-
- public void llSetClickAction(int action)
- {
- m_host.AddScriptLPS(1);
- m_host.ClickAction = (byte)action;
- m_host.ParentGroup.HasGroupChanged = true;
- m_host.ScheduleFullUpdate();
- return;
- }
-
- public void llSetColor(LSL_Vector color, int face)
- {
- m_host.AddScriptLPS(1);
-
- if (face == ScriptBaseClass.ALL_SIDES)
- face = SceneObjectPart.ALL_SIDES;
-
- m_host.SetFaceColorAlpha(face, color, null);
- }
-
- public void llSetContentType(LSL_Key id, LSL_Integer type)
- {
- m_host.AddScriptLPS(1);
-
- if (m_UrlModule == null)
- return;
-
- // Make sure the content type is text/plain to start with
- m_UrlModule.HttpContentType(new UUID(id), "text/plain");
-
- // Is the object owner online and in the region
- ScenePresence agent = World.GetScenePresence(m_host.ParentGroup.OwnerID);
- if (agent == null || agent.IsChildAgent)
- return; // Fail if the owner is not in the same region
-
- // Is it the embeded browser?
- string userAgent = m_UrlModule.GetHttpHeader(new UUID(id), "user-agent");
- if (userAgent.IndexOf("SecondLife") < 0)
- return; // Not the embedded browser. Is this check good enough?
-
- // Use the IP address of the client and check against the request
- // seperate logins from the same IP will allow all of them to get non-text/plain as long
- // as the owner is in the region. Same as SL!
- string logonFromIPAddress = agent.ControllingClient.RemoteEndPoint.Address.ToString();
- string requestFromIPAddress = m_UrlModule.GetHttpHeader(new UUID(id), "remote_addr");
- //m_log.Debug("IP from header='" + requestFromIPAddress + "' IP from endpoint='" + logonFromIPAddress + "'");
- if (requestFromIPAddress == null || requestFromIPAddress.Trim() == "")
- return;
- if (logonFromIPAddress == null || logonFromIPAddress.Trim() == "")
- return;
-
- // If the request isnt from the same IP address then the request cannot be from the owner
- if (!requestFromIPAddress.Trim().Equals(logonFromIPAddress.Trim()))
- return;
-
- switch (type)
- {
- case ScriptBaseClass.CONTENT_TYPE_HTML:
- m_UrlModule.HttpContentType(new UUID(id), "text/html");
- break;
- case ScriptBaseClass.CONTENT_TYPE_XML:
- m_UrlModule.HttpContentType(new UUID(id), "application/xml");
- break;
- case ScriptBaseClass.CONTENT_TYPE_XHTML:
- m_UrlModule.HttpContentType(new UUID(id), "application/xhtml+xml");
- break;
- case ScriptBaseClass.CONTENT_TYPE_ATOM:
- m_UrlModule.HttpContentType(new UUID(id), "application/atom+xml");
- break;
- case ScriptBaseClass.CONTENT_TYPE_JSON:
- m_UrlModule.HttpContentType(new UUID(id), "application/json");
- break;
- case ScriptBaseClass.CONTENT_TYPE_LLSD:
- m_UrlModule.HttpContentType(new UUID(id), "application/llsd+xml");
- break;
- case ScriptBaseClass.CONTENT_TYPE_FORM:
- m_UrlModule.HttpContentType(new UUID(id), "application/x-www-form-urlencoded");
- break;
- case ScriptBaseClass.CONTENT_TYPE_RSS:
- m_UrlModule.HttpContentType(new UUID(id), "application/rss+xml");
- break;
- default:
- m_UrlModule.HttpContentType(new UUID(id), "text/plain");
- break;
- }
- }
-
- public void SetTexGen(SceneObjectPart part, int face,int style)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- MappingType textype;
- textype = MappingType.Default;
- if (style == (int)ScriptBaseClass.PRIM_TEXGEN_PLANAR)
- textype = MappingType.Planar;
-
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- tex.CreateFace((uint) face);
- tex.FaceTextures[face].TexMapType = textype;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- else if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (uint i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- tex.FaceTextures[i].TexMapType = textype;
- }
- tex.DefaultTexture.TexMapType = textype;
- }
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- public void SetGlow(SceneObjectPart part, int face, float glow)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- tex.CreateFace((uint) face);
- tex.FaceTextures[face].Glow = glow;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- else if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (uint i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- tex.FaceTextures[i].Glow = glow;
- }
- tex.DefaultTexture.Glow = glow;
- }
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
- {
-
- Shininess sval = new Shininess();
-
- switch (shiny)
- {
- case 0:
- sval = Shininess.None;
- break;
- case 1:
- sval = Shininess.Low;
- break;
- case 2:
- sval = Shininess.Medium;
- break;
- case 3:
- sval = Shininess.High;
- break;
- default:
- sval = Shininess.None;
- break;
- }
-
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- tex.CreateFace((uint) face);
- tex.FaceTextures[face].Shiny = sval;
- tex.FaceTextures[face].Bump = bump;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- else if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (uint i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- tex.FaceTextures[i].Shiny = sval;
- tex.FaceTextures[i].Bump = bump;
- }
- tex.DefaultTexture.Shiny = sval;
- tex.DefaultTexture.Bump = bump;
- }
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- public void SetFullBright(SceneObjectPart part, int face, bool bright)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- tex.CreateFace((uint) face);
- tex.FaceTextures[face].Fullbright = bright;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- else if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (uint i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- tex.FaceTextures[i].Fullbright = bright;
- }
- }
- tex.DefaultTexture.Fullbright = bright;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- public LSL_Float llGetAlpha(int face)
- {
- m_host.AddScriptLPS(1);
-
- return GetAlpha(m_host, face);
- }
-
- protected LSL_Float GetAlpha(SceneObjectPart part, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face == ScriptBaseClass.ALL_SIDES)
- {
- int i;
- double sum = 0.0;
- for (i = 0 ; i < GetNumberOfSides(part); i++)
- sum += (double)tex.GetFace((uint)i).RGBA.A;
- return sum;
- }
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- return (double)tex.GetFace((uint)face).RGBA.A;
- }
- return 0.0;
- }
-
- public void llSetAlpha(double alpha, int face)
- {
- m_host.AddScriptLPS(1);
-
- SetAlpha(m_host, alpha, face);
- }
-
- public void llSetLinkAlpha(int linknumber, double alpha, int face)
- {
- m_host.AddScriptLPS(1);
-
- List parts = GetLinkParts(linknumber);
-
- foreach (SceneObjectPart part in parts)
- SetAlpha(part, alpha, face);
- }
-
- protected void SetAlpha(SceneObjectPart part, double alpha, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- Color4 texcolor;
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- texcolor = tex.CreateFace((uint)face).RGBA;
- texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
- tex.FaceTextures[face].RGBA = texcolor;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- else if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (int i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- texcolor = tex.FaceTextures[i].RGBA;
- texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
- tex.FaceTextures[i].RGBA = texcolor;
- }
- }
-
- // In some cases, the default texture can be null, eg when every face
- // has a unique texture
- if (tex.DefaultTexture != null)
- {
- texcolor = tex.DefaultTexture.RGBA;
- texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
- tex.DefaultTexture.RGBA = texcolor;
- }
-
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- ///
- /// Set flexi parameters of a part.
- ///
- /// FIXME: Much of this code should probably be within the part itself.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
- float wind, float tension, LSL_Vector Force)
- {
- if (part == null)
- return;
-
- if (flexi)
- {
- part.Shape.FlexiEntry = true; // this setting flexi true isn't working, but the below parameters do
- // work once the prim is already flexi
- part.Shape.FlexiSoftness = softness;
- part.Shape.FlexiGravity = gravity;
- part.Shape.FlexiDrag = friction;
- part.Shape.FlexiWind = wind;
- part.Shape.FlexiTension = tension;
- part.Shape.FlexiForceX = (float)Force.x;
- part.Shape.FlexiForceY = (float)Force.y;
- part.Shape.FlexiForceZ = (float)Force.z;
- part.Shape.PathCurve = (byte)Extrusion.Flexible;
- }
- else
- {
- // Other values not set, they do not seem to be sent to the viewer
- // Setting PathCurve appears to be what actually toggles the check box and turns Flexi on and off
- part.Shape.PathCurve = (byte)Extrusion.Straight;
- part.Shape.FlexiEntry = false;
- }
- part.ParentGroup.HasGroupChanged = true;
- part.ScheduleFullUpdate();
- }
-
- ///
- /// Set a light point on a part
- ///
- /// FIXME: Much of this code should probably be in SceneObjectGroup
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
- {
- if (part == null)
- return;
-
- if (light)
- {
- part.Shape.LightEntry = true;
- part.Shape.LightColorR = Util.Clip((float)color.x, 0.0f, 1.0f);
- part.Shape.LightColorG = Util.Clip((float)color.y, 0.0f, 1.0f);
- part.Shape.LightColorB = Util.Clip((float)color.z, 0.0f, 1.0f);
- part.Shape.LightIntensity = Util.Clip((float)intensity, 0.0f, 1.0f);
- part.Shape.LightRadius = Util.Clip((float)radius, 0.1f, 20.0f);
- part.Shape.LightFalloff = Util.Clip((float)falloff, 0.01f, 2.0f);
- }
- else
- {
- part.Shape.LightEntry = false;
- }
-
- part.ParentGroup.HasGroupChanged = true;
- part.ScheduleFullUpdate();
- }
-
- public LSL_Vector llGetColor(int face)
- {
- m_host.AddScriptLPS(1);
- return GetColor(m_host, face);
- }
-
- protected LSL_Vector GetColor(SceneObjectPart part, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- Color4 texcolor;
- LSL_Vector rgb = new LSL_Vector();
- if (face == ScriptBaseClass.ALL_SIDES)
- {
- int i;
-
- for (i = 0 ; i < GetNumberOfSides(part); i++)
- {
- texcolor = tex.GetFace((uint)i).RGBA;
- rgb.x += texcolor.R;
- rgb.y += texcolor.G;
- rgb.z += texcolor.B;
- }
-
- rgb.x /= (float)GetNumberOfSides(part);
- rgb.y /= (float)GetNumberOfSides(part);
- rgb.z /= (float)GetNumberOfSides(part);
-
- return rgb;
- }
-
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- texcolor = tex.GetFace((uint)face).RGBA;
- rgb.x = texcolor.R;
- rgb.y = texcolor.G;
- rgb.z = texcolor.B;
-
- return rgb;
- }
- else
- {
- return new LSL_Vector();
- }
- }
-
- public void llSetTexture(string texture, int face)
- {
- m_host.AddScriptLPS(1);
- SetTexture(m_host, texture, face);
- ScriptSleep(m_sleepMsOnSetTexture);
- }
-
- public void llSetLinkTexture(int linknumber, string texture, int face)
- {
- m_host.AddScriptLPS(1);
-
- List parts = GetLinkParts(linknumber);
-
- foreach (SceneObjectPart part in parts)
- SetTexture(part, texture, face);
-
- ScriptSleep(m_sleepMsOnSetLinkTexture);
- }
-
- protected void SetTexture(SceneObjectPart part, string texture, int face)
- {
- UUID textureID = new UUID();
-
- textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture);
- if (textureID == UUID.Zero)
- {
- if (!UUID.TryParse(texture, out textureID))
- return;
- }
-
- Primitive.TextureEntry tex = part.Shape.Textures;
-
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
- texface.TextureID = textureID;
- tex.FaceTextures[face] = texface;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- else if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (uint i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- tex.FaceTextures[i].TextureID = textureID;
- }
- }
- tex.DefaultTexture.TextureID = textureID;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- public void llScaleTexture(double u, double v, int face)
- {
- m_host.AddScriptLPS(1);
-
- ScaleTexture(m_host, u, v, face);
- ScriptSleep(m_sleepMsOnScaleTexture);
- }
-
- protected void ScaleTexture(SceneObjectPart part, double u, double v, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
- texface.RepeatU = (float)u;
- texface.RepeatV = (float)v;
- tex.FaceTextures[face] = texface;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (int i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- tex.FaceTextures[i].RepeatU = (float)u;
- tex.FaceTextures[i].RepeatV = (float)v;
- }
- }
- tex.DefaultTexture.RepeatU = (float)u;
- tex.DefaultTexture.RepeatV = (float)v;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- public void llOffsetTexture(double u, double v, int face)
- {
- m_host.AddScriptLPS(1);
- OffsetTexture(m_host, u, v, face);
- ScriptSleep(m_sleepMsOnOffsetTexture);
- }
-
- protected void OffsetTexture(SceneObjectPart part, double u, double v, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
- texface.OffsetU = (float)u;
- texface.OffsetV = (float)v;
- tex.FaceTextures[face] = texface;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (int i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- tex.FaceTextures[i].OffsetU = (float)u;
- tex.FaceTextures[i].OffsetV = (float)v;
- }
- }
- tex.DefaultTexture.OffsetU = (float)u;
- tex.DefaultTexture.OffsetV = (float)v;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- public void llRotateTexture(double rotation, int face)
- {
- m_host.AddScriptLPS(1);
- RotateTexture(m_host, rotation, face);
- ScriptSleep(m_sleepMsOnRotateTexture);
- }
-
- protected void RotateTexture(SceneObjectPart part, double rotation, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
- texface.Rotation = (float)rotation;
- tex.FaceTextures[face] = texface;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- if (face == ScriptBaseClass.ALL_SIDES)
- {
- for (int i = 0; i < GetNumberOfSides(part); i++)
- {
- if (tex.FaceTextures[i] != null)
- {
- tex.FaceTextures[i].Rotation = (float)rotation;
- }
- }
- tex.DefaultTexture.Rotation = (float)rotation;
- part.UpdateTextureEntry(tex.GetBytes());
- return;
- }
- }
-
- public LSL_String llGetTexture(int face)
- {
- m_host.AddScriptLPS(1);
- return GetTexture(m_host, face);
- }
-
- protected LSL_String GetTexture(SceneObjectPart part, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face == ScriptBaseClass.ALL_SIDES)
- {
- face = 0;
- }
-
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- Primitive.TextureEntryFace texface;
- texface = tex.GetFace((uint)face);
- string texture = texface.TextureID.ToString();
-
- lock (part.TaskInventory)
- {
- foreach (KeyValuePair inv in part.TaskInventory)
- {
- if (inv.Value.AssetID == texface.TextureID)
- {
- texture = inv.Value.Name.ToString();
- break;
- }
- }
- }
-
- return texture;
- }
- else
- {
- return UUID.Zero.ToString();
- }
- }
-
- public void llSetPos(LSL_Vector pos)
- {
- m_host.AddScriptLPS(1);
-
- SetPos(m_host, pos, true);
-
- ScriptSleep(m_sleepMsOnSetPos);
- }
-
- ///
- /// Tries to move the entire object so that the root prim is within 0.1m of position. http://wiki.secondlife.com/wiki/LlSetRegionPos
- /// 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.
- /// 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.
- ///
- ///
- /// 1 if successful, 0 otherwise.
- public LSL_Integer llSetRegionPos(LSL_Vector pos)
- {
- m_host.AddScriptLPS(1);
-
- // BEGIN WORKAROUND
- // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND.
- //
- // This workaround is to prevent silent failure of this function.
- // According to the specification on the SL Wiki, providing a position outside of the
- if (pos.x < 0 || pos.x > World.RegionInfo.RegionSizeX || pos.y < 0 || pos.y > World.RegionInfo.RegionSizeY)
- {
- return 0;
- }
- // END WORK AROUND
- else if ( // this is not part of the workaround if-block because it's not related to the workaround.
- IsPhysical() ||
- m_host.ParentGroup.IsAttachment || // return FALSE if attachment
- (
- pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region.
- pos.x > (World.RegionInfo.RegionSizeX + 10) || // return FALSE if more than 10 meters into a east-adjacent region.
- pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region.
- pos.y > (World.RegionInfo.RegionSizeY + 10) || // return FALSE if more than 10 meters into a north-adjacent region.
- pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m
- )
- )
- {
- return 0;
- }
-
- // if we reach this point, then the object is not physical, it's not an attachment, and the destination is within the valid range.
- // 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.
-
- Vector3 objectPos = m_host.ParentGroup.RootPart.AbsolutePosition;
- LandData here = World.GetLandData(objectPos);
- LandData there = World.GetLandData(pos);
-
- // 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.
-
- bool sameParcel = here.GlobalID == there.GlobalID;
-
- if (!sameParcel && !World.Permissions.CanRezObject(
- m_host.ParentGroup.PrimCount, m_host.ParentGroup.OwnerID, pos))
- {
- return 0;
- }
-
- SetPos(m_host.ParentGroup.RootPart, pos, false);
-
- return VecDist(pos, llGetRootPosition()) <= 0.1 ? 1 : 0;
- }
-
- // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
- // note linked setpos is capped "differently"
- private LSL_Vector SetPosAdjust(LSL_Vector start, LSL_Vector end)
- {
- if (llVecDist(start, end) > 10.0f * m_ScriptDistanceFactor)
- return start + m_ScriptDistanceFactor * 10.0f * llVecNorm(end - start);
- else
- return end;
- }
-
- protected LSL_Vector GetSetPosTarget(SceneObjectPart part, LSL_Vector targetPos, LSL_Vector fromPos)
- {
- if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
- return fromPos;
-
- // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
-
-
- float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
- bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
-
- if (part.ParentGroup.RootPart == part)
- {
- if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
- targetPos.z = ground;
- }
- LSL_Vector real_vec = SetPosAdjust(fromPos, targetPos);
-
- return real_vec;
- }
-
- ///
- /// set object position, optionally capping the distance.
- ///
- ///
- ///
- /// if TRUE, will cap the distance to 10m.
- protected void SetPos(SceneObjectPart part, LSL_Vector targetPos, bool adjust)
- {
- // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
- LSL_Vector currentPos = GetPartLocalPos(part);
-
- float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
- bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
-
- if (part.ParentGroup.RootPart == part)
- {
- if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
- targetPos.z = ground;
- SceneObjectGroup parent = part.ParentGroup;
- parent.UpdateGroupPosition(!adjust ? targetPos :
- SetPosAdjust(currentPos, targetPos));
- }
- else
- {
- part.OffsetPosition = !adjust ? targetPos :
- SetPosAdjust(currentPos, targetPos);
- SceneObjectGroup parent = part.ParentGroup;
- parent.HasGroupChanged = true;
- parent.ScheduleGroupForTerseUpdate();
- }
- }
-
- public LSL_Vector llGetPos()
- {
- m_host.AddScriptLPS(1);
- return m_host.GetWorldPosition();
- }
-
- public LSL_Vector llGetLocalPos()
- {
- m_host.AddScriptLPS(1);
- return GetPartLocalPos(m_host);
- }
-
- protected LSL_Vector GetPartLocalPos(SceneObjectPart part)
- {
- m_host.AddScriptLPS(1);
-
- Vector3 pos;
-
- if (!part.IsRoot)
- {
- pos = part.OffsetPosition;
- }
- else
- {
- if (part.ParentGroup.IsAttachment)
- {
- pos = part.AttachedPos;
- }
- else
- {
- pos = part.AbsolutePosition;
- }
- }
-
-// m_log.DebugFormat("[LSL API]: Returning {0} in GetPartLocalPos()", pos);
-
- return new LSL_Vector(pos);
- }
-
- public void llSetRot(LSL_Rotation rot)
- {
- m_host.AddScriptLPS(1);
-
- // try to let this work as in SL...
- if (m_host.ParentID == 0)
- {
- // special case: If we are root, rotate complete SOG to new rotation
- SetRot(m_host, rot);
- }
- else
- {
- // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
- SceneObjectPart rootPart = m_host.ParentGroup.RootPart;
- if (rootPart != null) // better safe than sorry
- {
- SetRot(m_host, rootPart.RotationOffset * (Quaternion)rot);
- }
- }
-
- ScriptSleep(m_sleepMsOnSetRot);
- }
-
- public void llSetLocalRot(LSL_Rotation rot)
- {
- m_host.AddScriptLPS(1);
- SetRot(m_host, rot);
- ScriptSleep(m_sleepMsOnSetLocalRot);
- }
-
- protected void SetRot(SceneObjectPart part, Quaternion rot)
- {
- part.UpdateRotation(rot);
- // Update rotation does not move the object in the physics scene if it's a linkset.
-
-//KF: Do NOT use this next line if using ODE physics engine. This need a switch based on .ini Phys Engine type
-// part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
-
- // So, after thinking about this for a bit, the issue with the part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition line
- // is it isn't compatible with vehicles because it causes the vehicle body to have to be broken down and rebuilt
- // It's perfectly okay when the object is not an active physical body though.
- // So, part.ParentGroup.ResetChildPrimPhysicsPositions(); does the thing that Kitto is warning against
- // but only if the object is not physial and active. This is important for rotating doors.
- // without the absoluteposition = absoluteposition happening, the doors do not move in the physics
- // scene
- PhysicsActor pa = part.PhysActor;
-
- if (pa != null && !pa.IsPhysical)
- {
- part.ParentGroup.ResetChildPrimPhysicsPositions();
- }
- }
-
- ///
- /// See http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
- ///
- public LSL_Rotation llGetRot()
- {
- // unlinked or root prim then use llRootRotation
- // see llRootRotaion for references.
- if (m_host.LinkNum == 0 || m_host.LinkNum == 1)
- {
- return llGetRootRotation();
- }
-
- m_host.AddScriptLPS(1);
- Quaternion q = m_host.GetWorldRotation();
- return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
- }
-
- private LSL_Rotation GetPartRot(SceneObjectPart part)
- {
- Quaternion q;
- if (part.LinkNum == 0 || part.LinkNum == 1) // unlinked or root prim
- {
- if (part.ParentGroup.AttachmentPoint != 0)
- {
- ScenePresence avatar = World.GetScenePresence(part.ParentGroup.AttachedAvatar);
- if (avatar != null)
- {
- if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
- q = avatar.CameraRotation; // Mouselook
- else
- q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
- }
- else
- q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
- }
- else
- q = part.ParentGroup.GroupRotation; // just the group rotation
-
- return new LSL_Rotation(q);
- }
-
- return new LSL_Rotation(part.GetWorldRotation());
- }
-
- public LSL_Rotation llGetLocalRot()
- {
- m_host.AddScriptLPS(1);
-
- return new LSL_Rotation(m_host.RotationOffset);
- }
-
- public void llSetForce(LSL_Vector force, int local)
- {
- m_host.AddScriptLPS(1);
-
- if (!m_host.ParentGroup.IsDeleted)
- {
- if (local != 0)
- force *= llGetRot();
-
- m_host.ParentGroup.RootPart.SetForce(force);
- }
- }
-
- public LSL_Vector llGetForce()
- {
- LSL_Vector force = new LSL_Vector(0.0, 0.0, 0.0);
-
- m_host.AddScriptLPS(1);
-
- if (!m_host.ParentGroup.IsDeleted)
- {
- force = m_host.ParentGroup.RootPart.GetForce();
- }
-
- return force;
- }
-
- public void llSetVelocity(LSL_Vector velocity, int local)
- {
- m_host.AddScriptLPS(1);
-
- if (!m_host.ParentGroup.IsDeleted)
- {
- if (local != 0)
- velocity *= llGetRot();
-
- m_host.ParentGroup.RootPart.Velocity = velocity;
- }
- }
-
- public void llSetAngularVelocity(LSL_Vector angularVelocity, int local)
- {
- m_host.AddScriptLPS(1);
-
- if (!m_host.ParentGroup.IsDeleted)
- {
- if (local != 0)
- angularVelocity *= llGetRot();
-
- m_host.ParentGroup.RootPart.AngularVelocity = angularVelocity;
- }
- }
-
- public LSL_Integer llTarget(LSL_Vector position, double range)
- {
- m_host.AddScriptLPS(1);
- return m_host.ParentGroup.registerTargetWaypoint(position,
- (float)range);
- }
-
- public void llTargetRemove(int number)
- {
- m_host.AddScriptLPS(1);
- m_host.ParentGroup.unregisterTargetWaypoint(number);
- }
-
- public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
- {
- m_host.AddScriptLPS(1);
- return m_host.ParentGroup.registerRotTargetWaypoint(rot, (float)error);
- }
-
- public void llRotTargetRemove(int number)
- {
- m_host.AddScriptLPS(1);
- m_host.ParentGroup.unregisterRotTargetWaypoint(number);
- }
-
- public void llMoveToTarget(LSL_Vector target, double tau)
- {
- m_host.AddScriptLPS(1);
- m_host.MoveToTarget(target, (float)tau);
- }
-
- public void llStopMoveToTarget()
- {
- m_host.AddScriptLPS(1);
- m_host.StopMoveToTarget();
- }
-
- public void llApplyImpulse(LSL_Vector force, int local)
- {
- m_host.AddScriptLPS(1);
- //No energy force yet
- Vector3 v = force;
- if (v.Length() > 20000.0f)
- {
- v.Normalize();
- v = v * 20000.0f;
- }
- m_host.ApplyImpulse(v, local != 0);
- }
-
- public void llApplyRotationalImpulse(LSL_Vector force, int local)
- {
- m_host.AddScriptLPS(1);
- m_host.ApplyAngularImpulse(force, local != 0);
- }
-
- public void llSetTorque(LSL_Vector torque, int local)
- {
- m_host.AddScriptLPS(1);
- m_host.SetAngularImpulse(torque, local != 0);
- }
-
- public LSL_Vector llGetTorque()
- {
- m_host.AddScriptLPS(1);
-
- return new LSL_Vector(m_host.ParentGroup.GetTorque());
- }
-
- public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
- {
- m_host.AddScriptLPS(1);
- llSetForce(force, local);
- llSetTorque(torque, local);
- }
-
- public LSL_Vector llGetVel()
- {
- m_host.AddScriptLPS(1);
-
- Vector3 vel;
-
- if (m_host.ParentGroup.IsAttachment)
- {
- ScenePresence avatar = m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
- vel = avatar.GetWorldVelocity();
- }
- else
- {
- vel = m_host.Velocity;
- }
-
- return new LSL_Vector(vel);
- }
-
- public LSL_Vector llGetAccel()
- {
- m_host.AddScriptLPS(1);
-
- return new LSL_Vector(m_host.Acceleration);
- }
-
- public LSL_Vector llGetOmega()
- {
- m_host.AddScriptLPS(1);
-
- return new LSL_Vector(m_host.AngularVelocity);
- }
-
- public LSL_Float llGetTimeOfDay()
- {
- m_host.AddScriptLPS(1);
- return (double)((DateTime.Now.TimeOfDay.TotalMilliseconds / 1000) % (3600 * 4));
- }
-
- public LSL_Float llGetWallclock()
- {
- m_host.AddScriptLPS(1);
- return DateTime.Now.TimeOfDay.TotalSeconds;
- }
-
- public LSL_Float llGetTime()
- {
- m_host.AddScriptLPS(1);
- TimeSpan ScriptTime = DateTime.Now - m_timer;
- return (double)(ScriptTime.TotalMilliseconds / 1000);
- }
-
- public void llResetTime()
- {
- m_host.AddScriptLPS(1);
- m_timer = DateTime.Now;
- }
-
- public LSL_Float llGetAndResetTime()
- {
- m_host.AddScriptLPS(1);
- TimeSpan ScriptTime = DateTime.Now - m_timer;
- m_timer = DateTime.Now;
- return (double)(ScriptTime.TotalMilliseconds / 1000);
- }
-
- public void llSound(string sound, double volume, int queue, int loop)
- {
- m_host.AddScriptLPS(1);
- Deprecated("llSound", "Use llPlaySound instead");
- }
-
- // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
- // 20080530 Updated to remove code duplication
- public void llPlaySound(string sound, double volume)
- {
- m_host.AddScriptLPS(1);
-
- // send the sound, once, to all clients in range
- if (m_SoundModule != null)
- {
- m_SoundModule.SendSound(
- m_host.UUID,
- ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound),
- volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None,
- 0, false, false);
- }
- }
-
- public void llLoopSound(string sound, double volume)
- {
- m_host.AddScriptLPS(1);
- if (m_SoundModule != null)
- {
- m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
- volume, 20, false);
- }
- }
-
- public void llLoopSoundMaster(string sound, double volume)
- {
- m_host.AddScriptLPS(1);
- if (m_SoundModule != null)
- {
- m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
- volume, 20, true);
- }
- }
-
- public void llLoopSoundSlave(string sound, double volume)
- {
- m_host.AddScriptLPS(1);
- lock (m_host.ParentGroup.LoopSoundSlavePrims)
- {
- m_host.ParentGroup.LoopSoundSlavePrims.Add(m_host);
- }
- }
-
- public void llPlaySoundSlave(string sound, double volume)
- {
- m_host.AddScriptLPS(1);
-
- // send the sound, once, to all clients in range
- if (m_SoundModule != null)
- {
- m_SoundModule.SendSound(m_host.UUID,
- ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0,
- 0, true, false);
- }
- }
-
- public void llTriggerSound(string sound, double volume)
- {
- m_host.AddScriptLPS(1);
- // send the sound, once, to all clients in rangeTrigger or play an attached sound in this part's inventory.
- if (m_SoundModule != null)
- {
- m_SoundModule.SendSound(m_host.UUID,
- ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, true, 0, 0,
- false, false);
- }
- }
-
- public void llStopSound()
- {
- m_host.AddScriptLPS(1);
-
- if (m_SoundModule != null)
- m_SoundModule.StopSound(m_host.UUID);
- }
-
- public void llPreloadSound(string sound)
- {
- m_host.AddScriptLPS(1);
- if (m_SoundModule != null)
- m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0);
- ScriptSleep(m_sleepMsOnPreloadSound);
- }
-
- ///
- /// Return a portion of the designated string bounded by
- /// inclusive indices (start and end). As usual, the negative
- /// indices, and the tolerance for out-of-bound values, makes
- /// this more complicated than it might otherwise seem.
- ///
- public LSL_String llGetSubString(string src, int start, int end)
- {
- m_host.AddScriptLPS(1);
-
- // Normalize indices (if negative).
- // After normlaization they may still be
- // negative, but that is now relative to
- // the start, rather than the end, of the
- // sequence.
-
- if (start < 0)
- {
- start = src.Length+start;
- }
- if (end < 0)
- {
- end = src.Length+end;
- }
-
- // Conventional substring
- if (start <= end)
- {
- // Implies both bounds are out-of-range.
- if (end < 0 || start >= src.Length)
- {
- return String.Empty;
- }
- // If end is positive, then it directly
- // corresponds to the lengt of the substring
- // needed (plus one of course). BUT, it
- // must be within bounds.
- if (end >= src.Length)
- {
- end = src.Length-1;
- }
-
- if (start < 0)
- {
- return src.Substring(0,end+1);
- }
- // Both indices are positive
- return src.Substring(start, (end+1) - start);
- }
-
- // Inverted substring (end < start)
- else
- {
- // Implies both indices are below the
- // lower bound. In the inverted case, that
- // means the entire string will be returned
- // unchanged.
- if (start < 0)
- {
- return src;
- }
- // If both indices are greater than the upper
- // bound the result may seem initially counter
- // intuitive.
- if (end >= src.Length)
- {
- return src;
- }
-
- if (end < 0)
- {
- if (start < src.Length)
- {
- return src.Substring(start);
- }
- else
- {
- return String.Empty;
- }
- }
- else
- {
- if (start < src.Length)
- {
- return src.Substring(0,end+1) + src.Substring(start);
- }
- else
- {
- return src.Substring(0,end+1);
- }
- }
- }
- }
-
- ///
- /// Delete substring removes the specified substring bounded
- /// by the inclusive indices start and end. Indices may be
- /// negative (indicating end-relative) and may be inverted,
- /// i.e. end < start.
- ///
- public LSL_String llDeleteSubString(string src, int start, int end)
- {
- m_host.AddScriptLPS(1);
-
- // Normalize indices (if negative).
- // After normlaization they may still be
- // negative, but that is now relative to
- // the start, rather than the end, of the
- // sequence.
- if (start < 0)
- {
- start = src.Length+start;
- }
- if (end < 0)
- {
- end = src.Length+end;
- }
- // Conventionally delimited substring
- if (start <= end)
- {
- // If both bounds are outside of the existing
- // string, then return unchanges.
- if (end < 0 || start >= src.Length)
- {
- return src;
- }
- // At least one bound is in-range, so we
- // need to clip the out-of-bound argument.
- if (start < 0)
- {
- start = 0;
- }
-
- if (end >= src.Length)
- {
- end = src.Length-1;
- }
-
- return src.Remove(start,end-start+1);
- }
- // Inverted substring
- else
- {
- // In this case, out of bounds means that
- // the existing string is part of the cut.
- if (start < 0 || end >= src.Length)
- {
- return String.Empty;
- }
-
- if (end > 0)
- {
- if (start < src.Length)
- {
- return src.Remove(start).Remove(0,end+1);
- }
- else
- {
- return src.Remove(0,end+1);
- }
- }
- else
- {
- if (start < src.Length)
- {
- return src.Remove(start);
- }
- else
- {
- return src;
- }
- }
- }
- }
-
- ///
- /// Insert string inserts the specified string identified by src
- /// at the index indicated by index. Index may be negative, in
- /// which case it is end-relative. The index may exceed either
- /// string bound, with the result being a concatenation.
- ///
- public LSL_String llInsertString(string dest, int index, string src)
- {
- m_host.AddScriptLPS(1);
-
- // Normalize indices (if negative).
- // After normlaization they may still be
- // negative, but that is now relative to
- // the start, rather than the end, of the
- // sequence.
- if (index < 0)
- {
- index = dest.Length+index;
-
- // Negative now means it is less than the lower
- // bound of the string.
-
- if (index < 0)
- {
- return src+dest;
- }
-
- }
-
- if (index >= dest.Length)
- {
- return dest+src;
- }
-
- // The index is in bounds.
- // In this case the index refers to the index that will
- // be assigned to the first character of the inserted string.
- // So unlike the other string operations, we do not add one
- // to get the correct string length.
- return dest.Substring(0,index)+src+dest.Substring(index);
-
- }
-
- public LSL_String llToUpper(string src)
- {
- m_host.AddScriptLPS(1);
- return src.ToUpper();
- }
-
- public LSL_String llToLower(string src)
- {
- m_host.AddScriptLPS(1);
- return src.ToLower();
- }
-
- public void llGiveMoney(string destination, int amount)
- {
- Util.FireAndForget(x =>
- {
- m_host.AddScriptLPS(1);
-
- if (m_item.PermsGranter == UUID.Zero)
- return;
-
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
- {
- Error("llGiveMoney", "No permissions to give money");
- return;
- }
-
- UUID toID = new UUID();
-
- if (!UUID.TryParse(destination, out toID))
- {
- Error("llGiveMoney", "Bad key in llGiveMoney");
- return;
- }
-
- IMoneyModule money = World.RequestModuleInterface();
-
- if (money == null)
- {
- NotImplemented("llGiveMoney");
- return;
- }
-
- money.ObjectGiveMoney(
- m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
- }, null, "LSL_Api.llGiveMoney");
- }
-
- public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
- {
- m_host.AddScriptLPS(1);
- Deprecated("llMakeExplosion", "Use llParticleSystem instead");
- ScriptSleep(m_sleepMsOnMakeExplosion);
- }
-
- public void llMakeFountain(int particles, double scale, double vel, double lifetime, double arc, int bounce, string texture, LSL_Vector offset, double bounce_offset)
- {
- m_host.AddScriptLPS(1);
- Deprecated("llMakeFountain", "Use llParticleSystem instead");
- ScriptSleep(m_sleepMsOnMakeFountain);
- }
-
- public void llMakeSmoke(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
- {
- m_host.AddScriptLPS(1);
- Deprecated("llMakeSmoke", "Use llParticleSystem instead");
- ScriptSleep(m_sleepMsOnMakeSmoke);
- }
-
- public void llMakeFire(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
- {
- m_host.AddScriptLPS(1);
- Deprecated("llMakeFire", "Use llParticleSystem instead");
- ScriptSleep(m_sleepMsOnMakeFire);
- }
-
- public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
- {
- m_host.AddScriptLPS(1);
-
- Util.FireAndForget(x =>
- {
- if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
- return;
-
- float dist = (float)llVecDist(llGetPos(), pos);
-
- if (dist > m_ScriptDistanceFactor * 10.0f)
- return;
-
- TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
-
- if (item == null)
- {
- Error("llRezAtRoot", "Can't find object '" + inventory + "'");
- return;
- }
-
- if (item.InvType != (int)InventoryType.Object)
- {
- Error("llRezAtRoot", "Can't create requested object; object is missing from database");
- return;
- }
-
- // need the magnitude later
- // float velmag = (float)Util.GetMagnitude(llvel);
-
- List new_groups = World.RezObject(m_host, item, pos, rot, vel, param);
-
- // If either of these are null, then there was an unknown error.
- if (new_groups == null)
- return;
-
- foreach (SceneObjectGroup group in new_groups)
- {
- // objects rezzed with this method are die_at_edge by default.
- group.RootPart.SetDieAtEdge(true);
-
- group.ResumeScripts();
-
- m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
- "object_rez", new Object[] {
- new LSL_String(
- group.RootPart.UUID.ToString()) },
- new DetectParams[0]));
-
- float groupmass = group.GetMass();
-
- PhysicsActor pa = group.RootPart.PhysActor;
-
- //Recoil.
- if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero)
- {
- Vector3 recoil = -vel * groupmass * m_recoilScaleFactor;
- if (recoil != Vector3.Zero)
- {
- llApplyImpulse(recoil, 0);
- }
- }
- // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
- }
- }, null, "LSL_Api.llRezAtRoot");
-
- //ScriptSleep((int)((groupmass * velmag) / 10));
- ScriptSleep(m_sleepMsOnRezAtRoot);
- }
-
- public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
- {
- llRezAtRoot(inventory, pos, vel, rot, param);
- }
-
- public void llLookAt(LSL_Vector target, double strength, double damping)
- {
- m_host.AddScriptLPS(1);
- // Determine where we are looking from
- LSL_Vector from = llGetPos();
-
- // normalized direction to target
- LSL_Vector dir = llVecNorm(target - from);
- // use vertical to help compute left axis
- LSL_Vector up = new LSL_Vector(0.0, 0.0, 1.0);
- // find normalized left axis parallel to horizon
- LSL_Vector left = llVecNorm(LSL_Vector.Cross(up, dir));
- // make up orthogonal to left and dir
- up = LSL_Vector.Cross(dir, left);
-
- // compute rotation based on orthogonal axes
- LSL_Rotation rot = new LSL_Rotation(0.0, 0.707107, 0.0, 0.707107) * llAxes2Rot(dir, left, up);
-
- // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
- // set the rotation of the object, copy that behavior
- PhysicsActor pa = m_host.PhysActor;
-
- if (m_host.ParentGroup.IsAttachment || strength == 0 || pa == null || !pa.IsPhysical)
- {
- llSetRot(rot);
- }
- else
- {
- m_host.StartLookAt(rot, (float)strength, (float)damping);
- }
- }
-
- public void llStopLookAt()
- {
- m_host.AddScriptLPS(1);
- m_host.StopLookAt();
- }
-
- public void llSetTimerEvent(double sec)
- {
- if (sec != 0.0 && sec < m_MinTimerInterval)
- sec = m_MinTimerInterval;
- m_host.AddScriptLPS(1);
- // Setting timer repeat
- AsyncCommands.TimerPlugin.SetTimerEvent(m_host.LocalId, m_item.ItemID, sec);
- }
-
- public virtual void llSleep(double sec)
- {
-// m_log.Info("llSleep snoozing " + sec + "s.");
- m_host.AddScriptLPS(1);
-
- Sleep((int)(sec * 1000));
- }
-
- public LSL_Float llGetMass()
- {
- m_host.AddScriptLPS(1);
-
- if (m_host.ParentGroup.IsAttachment)
- {
- ScenePresence attachedAvatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
-
- if (attachedAvatar != null)
- {
- return attachedAvatar.GetMass();
- }
- else
- {
- return 0;
- }
- }
- else
- {
- if (m_host.IsRoot)
- {
- return m_host.ParentGroup.GetMass();
- }
- else
- {
- return m_host.GetMass();
- }
- }
- }
-
- public LSL_Float llGetMassMKS()
- {
- // this is what the wiki says it does!
- // http://wiki.secondlife.com/wiki/LlGetMassMKS
- return llGetMass() * 100.0;
- }
-
- public void llCollisionFilter(string name, string id, int accept)
- {
- m_host.AddScriptLPS(1);
- m_host.CollisionFilter.Clear();
- UUID objectID;
-
- if (!UUID.TryParse(id, out objectID))
- objectID = UUID.Zero;
-
- if (objectID == UUID.Zero && name == "")
- return;
-
- m_host.CollisionFilter.Add(accept,objectID.ToString() + name);
- }
-
- public void llTakeControls(int controls, int accept, int pass_on)
- {
- if (m_item.PermsGranter != UUID.Zero)
- {
- ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
-
- if (presence != null)
- {
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
- {
- presence.RegisterControlEventsToScript(controls, accept, pass_on, m_host.LocalId, m_item.ItemID);
- }
- }
- }
-
- m_host.AddScriptLPS(1);
- }
-
- public void llReleaseControls()
- {
- m_host.AddScriptLPS(1);
-
- if (m_item.PermsGranter != UUID.Zero)
- {
- ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
-
- if (presence != null)
- {
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
- {
- // Unregister controls from Presence
- presence.UnRegisterControlEventsToScript(m_host.LocalId, m_item.ItemID);
- // Remove Take Control permission.
- m_item.PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
- }
- }
- }
- }
-
- public void llReleaseURL(string url)
- {
- m_host.AddScriptLPS(1);
- if (m_UrlModule != null)
- m_UrlModule.ReleaseURL(url);
- }
-
- ///
- /// Attach the object containing this script to the avatar that owns it.
- ///
- ///
- /// The attachment point (e.g. ATTACH_CHEST)
- ///
- /// true if the attach suceeded, false if it did not
- public bool AttachToAvatar(int attachmentPoint)
- {
- SceneObjectGroup grp = m_host.ParentGroup;
- ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
-
- IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
-
- if (attachmentsModule != null)
- return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, true);
- else
- return false;
- }
-
- ///
- /// Detach the object containing this script from the avatar it is attached to.
- ///
- ///
- /// Nothing happens if the object is not attached.
- ///
- public void DetachFromAvatar()
- {
- Util.FireAndForget(DetachWrapper, m_host, "LSL_Api.DetachFromAvatar");
- }
-
- private void DetachWrapper(object o)
- {
- if (World.AttachmentsModule != null)
- {
- SceneObjectPart host = (SceneObjectPart)o;
- ScenePresence presence = World.GetScenePresence(host.OwnerID);
- World.AttachmentsModule.DetachSingleAttachmentToInv(presence, host.ParentGroup);
- }
- }
-
- public void llAttachToAvatar(int attachmentPoint)
- {
- m_host.AddScriptLPS(1);
-
-// if (m_host.ParentGroup.RootPart.AttachmentPoint == 0)
-// return;
-
- if (m_item.PermsGranter != m_host.OwnerID)
- return;
-
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
- AttachToAvatar(attachmentPoint);
- }
-
- public void llDetachFromAvatar()
- {
- m_host.AddScriptLPS(1);
-
- if (m_host.ParentGroup.AttachmentPoint == 0)
- return;
-
- if (m_item.PermsGranter != m_host.OwnerID)
- return;
-
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
- DetachFromAvatar();
- }
-
- public void llTakeCamera(string avatar)
- {
- m_host.AddScriptLPS(1);
- Deprecated("llTakeCamera", "Use llSetCameraParams instead");
- }
-
- public void llReleaseCamera(string avatar)
- {
- m_host.AddScriptLPS(1);
- Deprecated("llReleaseCamera", "Use llClearCameraParams instead");
- }
-
- public LSL_String llGetOwner()
- {
- m_host.AddScriptLPS(1);
-
- return m_host.OwnerID.ToString();
- }
-
- public void llInstantMessage(string user, string message)
- {
- m_host.AddScriptLPS(1);
-
- // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
- // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
- // but I don't think we have a list of scenes available from here.
- // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
-
- // user is a UUID
-
- // TODO: figure out values for client, fromSession, and imSessionID
- // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
-
- GridInstantMessage msg = new GridInstantMessage();
+/*
+ * 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.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.Remoting.Lifetime;
+using System.Text;
+using System.Threading;
+using System.Text.RegularExpressions;
+using Nini.Config;
+using log4net;
+using OpenMetaverse;
+using OpenMetaverse.Assets;
+using OpenMetaverse.Packets;
+using OpenMetaverse.Rendering;
+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;
+using System.Linq;
+using PermissionMask = OpenSim.Framework.PermissionMask;
+
+namespace OpenSim.Region.ScriptEngine.Shared.Api
+{
+ // MUST be a ref type
+ public class UserInfoCacheEntry
+ {
+ public int time;
+ public UserAccount account;
+ public PresenceInfo pinfo;
+ }
+
+ ///
+ /// Contains all LSL ll-functions. This class will be in Default AppDomain.
+ ///
+ public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public int LlRequestAgentDataCacheTimeoutMs { get; set; }
+
+ protected IScriptEngine m_ScriptEngine;
+ protected SceneObjectPart m_host;
+
+ ///
+ /// Used for script sleeps when we are using co-operative script termination.
+ ///
+ /// null if co-operative script termination is not active
+ WaitHandle m_coopSleepHandle;
+
+ ///
+ /// The timer used by the ScriptInstance to measure how long the script has executed.
+ ///
+ private Stopwatch m_executionTimer;
+
+ ///
+ /// The item that hosts this script
+ ///
+ protected TaskInventoryItem m_item;
+
+ protected bool throwErrorOnNotImplemented = false;
+ 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 m_userInfoCache = new Dictionary();
+ protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp.
+ protected int m_sleepMsOnSetTexture = 200;
+ protected int m_sleepMsOnSetLinkTexture = 200;
+ protected int m_sleepMsOnScaleTexture = 200;
+ protected int m_sleepMsOnOffsetTexture = 200;
+ protected int m_sleepMsOnRotateTexture = 200;
+ protected int m_sleepMsOnSetPos = 200;
+ protected int m_sleepMsOnSetRot = 200;
+ protected int m_sleepMsOnSetLocalRot = 200;
+ protected int m_sleepMsOnPreloadSound = 1000;
+ protected int m_sleepMsOnMakeExplosion = 100;
+ protected int m_sleepMsOnMakeFountain = 100;
+ protected int m_sleepMsOnMakeSmoke = 100;
+ protected int m_sleepMsOnMakeFire = 100;
+ protected int m_sleepMsOnRezAtRoot = 100;
+ protected int m_sleepMsOnInstantMessage = 2000;
+ protected int m_sleepMsOnEmail = 20000;
+ protected int m_sleepMsOnCreateLink = 1000;
+ protected int m_sleepMsOnGiveInventory = 3000;
+ protected int m_sleepMsOnRequestAgentData = 100;
+ protected int m_sleepMsOnRequestInventoryData = 1000;
+ protected int m_sleepMsOnSetDamage = 5000;
+ protected int m_sleepMsOnTextBox = 1000;
+ protected int m_sleepMsOnAdjustSoundVolume = 100;
+ protected int m_sleepMsOnEjectFromLand = 5000;
+ protected int m_sleepMsOnAddToLandPassList = 100;
+ protected int m_sleepMsOnDialog = 1000;
+ protected int m_sleepMsOnRemoteLoadScript = 3000;
+ protected int m_sleepMsOnRemoteLoadScriptPin = 3000;
+ protected int m_sleepMsOnOpenRemoteDataChannel = 1000;
+ protected int m_sleepMsOnSendRemoteData = 3000;
+ protected int m_sleepMsOnRemoteDataReply = 3000;
+ protected int m_sleepMsOnCloseRemoteDataChannel = 1000;
+ protected int m_sleepMsOnSetPrimitiveParams = 200;
+ protected int m_sleepMsOnSetLinkPrimitiveParams = 200;
+ protected int m_sleepMsOnXorBase64Strings = 300;
+ protected int m_sleepMsOnSetParcelMusicURL = 2000;
+ protected int m_sleepMsOnGetPrimMediaParams = 1000;
+ protected int m_sleepMsOnGetLinkMedia = 1000;
+ protected int m_sleepMsOnSetPrimMediaParams = 1000;
+ protected int m_sleepMsOnSetLinkMedia = 1000;
+ protected int m_sleepMsOnClearPrimMedia = 1000;
+ protected int m_sleepMsOnClearLinkMedia = 1000;
+ protected int m_sleepMsOnRequestSimulatorData = 1000;
+ protected int m_sleepMsOnLoadURL = 10000;
+ protected int m_sleepMsOnParcelMediaCommandList = 2000;
+ protected int m_sleepMsOnParcelMediaQuery = 2000;
+ protected int m_sleepMsOnModPow = 1000;
+ protected int m_sleepMsOnSetPrimURL = 2000;
+ protected int m_sleepMsOnRefreshPrimURL = 20000;
+ protected int m_sleepMsOnMapDestination = 1000;
+ protected int m_sleepMsOnAddToLandBanList = 100;
+ protected int m_sleepMsOnRemoveFromLandPassList = 100;
+ protected int m_sleepMsOnRemoveFromLandBanList = 100;
+ protected int m_sleepMsOnResetLandBanList = 100;
+ protected int m_sleepMsOnResetLandPassList = 100;
+ protected int m_sleepMsOnGetParcelPrimOwners = 2000;
+ protected int m_sleepMsOnGetNumberOfNotecardLines = 100;
+ protected int m_sleepMsOnGetNotecardLine = 100;
+ protected string m_internalObjectHost = "lsl.opensim.local";
+ protected bool m_restrictEmail = false;
+ protected ISoundModule m_SoundModule = null;
+
+ protected float m_avatarHeightCorrection = 0.2f;
+ protected bool m_useSimpleBoxesInGetBoundingBox = false;
+ protected bool m_addStatsInGetBoundingBox = false;
+
+ //LSL Avatar Bounding Box (lABB), lower (1) and upper (2),
+ //standing (Std), Groundsitting (Grs), Sitting (Sit),
+ //along X, Y and Z axes, constants (0) and coefficients (1)
+ protected float m_lABB1StdX0 = -0.275f;
+ protected float m_lABB2StdX0 = 0.275f;
+ protected float m_lABB1StdY0 = -0.35f;
+ protected float m_lABB2StdY0 = 0.35f;
+ protected float m_lABB1StdZ0 = -0.1f;
+ protected float m_lABB1StdZ1 = -0.5f;
+ protected float m_lABB2StdZ0 = 0.1f;
+ protected float m_lABB2StdZ1 = 0.5f;
+ protected float m_lABB1GrsX0 = -0.3875f;
+ protected float m_lABB2GrsX0 = 0.3875f;
+ protected float m_lABB1GrsY0 = -0.5f;
+ protected float m_lABB2GrsY0 = 0.5f;
+ protected float m_lABB1GrsZ0 = -0.05f;
+ protected float m_lABB1GrsZ1 = -0.375f;
+ protected float m_lABB2GrsZ0 = 0.5f;
+ protected float m_lABB2GrsZ1 = 0.0f;
+ protected float m_lABB1SitX0 = -0.5875f;
+ protected float m_lABB2SitX0 = 0.1875f;
+ protected float m_lABB1SitY0 = -0.35f;
+ protected float m_lABB2SitY0 = 0.35f;
+ protected float m_lABB1SitZ0 = -0.35f;
+ protected float m_lABB1SitZ1 = -0.375f;
+ protected float m_lABB2SitZ0 = -0.25f;
+ protected float m_lABB2SitZ1 = 0.25f;
+
+ protected float m_primSafetyCoeffX = 2.414214f;
+ protected float m_primSafetyCoeffY = 2.414214f;
+ protected float m_primSafetyCoeffZ = 1.618034f;
+ protected bool m_useCastRayV3 = false;
+ protected float m_floatToleranceInCastRay = 0.00001f;
+ protected float m_floatTolerance2InCastRay = 0.001f;
+ protected DetailLevel m_primLodInCastRay = DetailLevel.Medium;
+ protected DetailLevel m_sculptLodInCastRay = DetailLevel.Medium;
+ protected DetailLevel m_meshLodInCastRay = DetailLevel.Highest;
+ protected DetailLevel m_avatarLodInCastRay = DetailLevel.Medium;
+ protected int m_maxHitsInCastRay = 16;
+ protected int m_maxHitsPerPrimInCastRay = 16;
+ protected int m_maxHitsPerObjectInCastRay = 16;
+ protected bool m_detectExitsInCastRay = false;
+ protected bool m_filterPartsInCastRay = false;
+ protected bool m_doAttachmentsInCastRay = false;
+ protected int m_msThrottleInCastRay = 200;
+ protected int m_msPerRegionInCastRay = 40;
+ protected int m_msPerAvatarInCastRay = 10;
+ protected int m_msMinInCastRay = 2;
+ protected int m_msMaxInCastRay = 40;
+ protected static List m_castRayCalls = new List();
+ protected bool m_useMeshCacheInCastRay = true;
+ protected static Dictionary m_cachedMeshes = new Dictionary();
+
+ //An array of HTTP/1.1 headers that are not allowed to be used
+ //as custom headers by llHTTPRequest.
+ private string[] HttpStandardHeaders =
+ {
+ "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language",
+ "Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control",
+ "Connection", "Content-Encoding", "Content-Language",
+ "Content-Length", "Content-Location", "Content-MD5",
+ "Content-Range", "Content-Type", "Date", "ETag", "Expect",
+ "Expires", "From", "Host", "If-Match", "If-Modified-Since",
+ "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified",
+ "Location", "Max-Forwards", "Pragma", "Proxy-Authenticate",
+ "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server",
+ "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent",
+ "Vary", "Via", "Warning", "WWW-Authenticate"
+ };
+
+ public void Initialize(
+ IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle,
+ Stopwatch executionTimer)
+ {
+ m_ScriptEngine = scriptEngine;
+ m_host = host;
+ m_item = item;
+ m_coopSleepHandle = coopSleepHandle;
+ m_executionTimer = executionTimer;
+
+ LoadConfig();
+
+ m_TransferModule =
+ m_ScriptEngine.World.RequestModuleInterface();
+ m_UrlModule = m_ScriptEngine.World.RequestModuleInterface();
+ m_SoundModule = m_ScriptEngine.World.RequestModuleInterface();
+
+ AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
+ }
+
+ ///
+ /// Load configuration items that affect script, object and run-time behavior. */
+ ///
+ private void LoadConfig()
+ {
+ LlRequestAgentDataCacheTimeoutMs = 20000;
+
+ IConfig seConfig = m_ScriptEngine.Config;
+
+ if (seConfig != null)
+ {
+ m_ScriptDelayFactor =
+ seConfig.GetFloat("ScriptDelayFactor", m_ScriptDelayFactor);
+ m_ScriptDistanceFactor =
+ seConfig.GetFloat("ScriptDistanceLimitFactor", m_ScriptDistanceFactor);
+ m_MinTimerInterval =
+ seConfig.GetFloat("MinTimerInterval", m_MinTimerInterval);
+ m_automaticLinkPermission =
+ seConfig.GetBoolean("AutomaticLinkPermission", m_automaticLinkPermission);
+ m_notecardLineReadCharsMax =
+ seConfig.GetInt("NotecardLineReadCharsMax", m_notecardLineReadCharsMax);
+
+ // 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);
+ }
+
+ if (m_notecardLineReadCharsMax > 65535)
+ m_notecardLineReadCharsMax = 65535;
+
+ // load limits for particular subsystems.
+ IConfigSource seConfigSource = m_ScriptEngine.ConfigSource;
+
+ if (seConfigSource != null)
+ {
+ IConfig lslConfig = seConfigSource.Configs["LL-Functions"];
+ if (lslConfig != null)
+ {
+ m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail);
+ m_avatarHeightCorrection = lslConfig.GetFloat("AvatarHeightCorrection", m_avatarHeightCorrection);
+ m_useSimpleBoxesInGetBoundingBox = lslConfig.GetBoolean("UseSimpleBoxesInGetBoundingBox", m_useSimpleBoxesInGetBoundingBox);
+ m_addStatsInGetBoundingBox = lslConfig.GetBoolean("AddStatsInGetBoundingBox", m_addStatsInGetBoundingBox);
+ m_lABB1StdX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingXconst", m_lABB1StdX0);
+ m_lABB2StdX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingXconst", m_lABB2StdX0);
+ m_lABB1StdY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingYconst", m_lABB1StdY0);
+ m_lABB2StdY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingYconst", m_lABB2StdY0);
+ m_lABB1StdZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZconst", m_lABB1StdZ0);
+ m_lABB1StdZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZcoeff", m_lABB1StdZ1);
+ m_lABB2StdZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZconst", m_lABB2StdZ0);
+ m_lABB2StdZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZcoeff", m_lABB2StdZ1);
+ m_lABB1GrsX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingXconst", m_lABB1GrsX0);
+ m_lABB2GrsX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingXconst", m_lABB2GrsX0);
+ m_lABB1GrsY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingYconst", m_lABB1GrsY0);
+ m_lABB2GrsY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingYconst", m_lABB2GrsY0);
+ m_lABB1GrsZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZconst", m_lABB1GrsZ0);
+ m_lABB1GrsZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZcoeff", m_lABB1GrsZ1);
+ m_lABB2GrsZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZconst", m_lABB2GrsZ0);
+ m_lABB2GrsZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZcoeff", m_lABB2GrsZ1);
+ m_lABB1SitX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingXconst", m_lABB1SitX0);
+ m_lABB2SitX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingXconst", m_lABB2SitX0);
+ m_lABB1SitY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingYconst", m_lABB1SitY0);
+ m_lABB2SitY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingYconst", m_lABB2SitY0);
+ m_lABB1SitZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZconst", m_lABB1SitZ0);
+ m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1);
+ m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0);
+ m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1);
+ m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX);
+ m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY);
+ m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ);
+ m_useCastRayV3 = lslConfig.GetBoolean("UseLlCastRayV3", m_useCastRayV3);
+ m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay);
+ m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay);
+ m_primLodInCastRay = (DetailLevel)lslConfig.GetInt("PrimDetailLevelInLlCastRay", (int)m_primLodInCastRay);
+ m_sculptLodInCastRay = (DetailLevel)lslConfig.GetInt("SculptDetailLevelInLlCastRay", (int)m_sculptLodInCastRay);
+ m_meshLodInCastRay = (DetailLevel)lslConfig.GetInt("MeshDetailLevelInLlCastRay", (int)m_meshLodInCastRay);
+ m_avatarLodInCastRay = (DetailLevel)lslConfig.GetInt("AvatarDetailLevelInLlCastRay", (int)m_avatarLodInCastRay);
+ m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay);
+ m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay);
+ m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay);
+ m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay);
+ m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay);
+ m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay);
+ m_msThrottleInCastRay = lslConfig.GetInt("ThrottleTimeInMsInLlCastRay", m_msThrottleInCastRay);
+ m_msPerRegionInCastRay = lslConfig.GetInt("AvailableTimeInMsPerRegionInLlCastRay", m_msPerRegionInCastRay);
+ m_msPerAvatarInCastRay = lslConfig.GetInt("AvailableTimeInMsPerAvatarInLlCastRay", m_msPerAvatarInCastRay);
+ m_msMinInCastRay = lslConfig.GetInt("RequiredAvailableTimeInMsInLlCastRay", m_msMinInCastRay);
+ m_msMaxInCastRay = lslConfig.GetInt("MaximumAvailableTimeInMsInLlCastRay", m_msMaxInCastRay);
+ m_useMeshCacheInCastRay = lslConfig.GetBoolean("UseMeshCacheInLlCastRay", m_useMeshCacheInCastRay);
+ }
+
+ IConfig smtpConfig = seConfigSource.Configs["SMTP"];
+ if (smtpConfig != null)
+ {
+ // there's an smtp config, so load in the snooze time.
+ EMAIL_PAUSE_TIME = smtpConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME);
+
+ m_internalObjectHost = smtpConfig.GetString("internal_object_host", m_internalObjectHost);
+ }
+ }
+ m_sleepMsOnEmail = EMAIL_PAUSE_TIME * 1000;
+ }
+
+ 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_executionTimer != null)
+ m_executionTimer.Stop(); // sleep time doesn't count as execution time, since it doesn't use the CPU
+
+ try
+ {
+ if (m_coopSleepHandle == null)
+ System.Threading.Thread.Sleep(delay);
+ else
+ CheckForCoopTermination(delay);
+ }
+ finally
+ {
+ if (m_executionTimer != null)
+ m_executionTimer.Start();
+ }
+ }
+
+ ///
+ /// Check for co-operative termination.
+ ///
+ /// If called with 0, then just the check is performed with no wait.
+ 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);
+ }
+
+ ///
+ /// Reset the named script. The script must be present
+ /// in the same prim.
+ ///
+ 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
+ Error("llResetOtherScript", "Can't find script '" + name + "'");
+ }
+
+ 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;
+ }
+
+ Error("llGetScriptState", "Can't find script '" + name + "'");
+
+ // 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
+ {
+ Error("llSetScriptState", "Can't find script '" + name + "'");
+ }
+ }
+
+ ///
+ /// Get a given link entity from a linkset (linked objects and any sitting avatars).
+ ///
+ ///
+ /// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then
+ /// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset.
+ /// The ScenePresences receive linknums in the order in which they sat.
+ ///
+ ///
+ /// The link entity. null if not found.
+ ///
+ ///
+ ///
+ /// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4).
+ /// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned.
+ /// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any
+ /// positive integer is given in this case then null is returned.
+ /// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number
+ /// of entities, then the entity which corresponds to that linknum is returned.
+ /// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then
+ /// null is returned.
+ ///
+ public ISceneEntity GetLinkEntity(SceneObjectPart part, int linknum)
+ {
+ if (linknum < 0)
+ {
+ if (linknum == ScriptBaseClass.LINK_THIS)
+ return part;
+ else
+ return null;
+ }
+
+ int actualPrimCount = part.ParentGroup.PrimCount;
+ List sittingAvatars = part.ParentGroup.GetSittingAvatars();
+ int adjustedPrimCount = actualPrimCount + sittingAvatars.Count;
+
+ // Special case for a single prim. In this case the linknum is zero. However, this will not match a single
+ // prim that has any avatars sat upon it (in which case the root prim is link 1).
+ if (linknum == 0)
+ {
+ if (actualPrimCount == 1 && sittingAvatars.Count == 0)
+ return part;
+
+ return null;
+ }
+ // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
+ // here we must match 1 (ScriptBaseClass.LINK_ROOT).
+ else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1)
+ {
+ if (sittingAvatars.Count > 0)
+ return part.ParentGroup.RootPart;
+ else
+ return null;
+ }
+ else if (linknum <= adjustedPrimCount)
+ {
+ if (linknum <= actualPrimCount)
+ {
+ return part.ParentGroup.GetLinkNumPart(linknum);
+ }
+ else
+ {
+ return sittingAvatars[linknum - actualPrimCount - 1];
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public List GetLinkParts(int linkType)
+ {
+ return GetLinkParts(m_host, linkType);
+ }
+
+ public static List GetLinkParts(SceneObjectPart part, int linkType)
+ {
+ List ret = new List();
+ ret.Add(part);
+
+ switch (linkType)
+ {
+ case ScriptBaseClass.LINK_SET:
+ return new List(part.ParentGroup.Parts);
+
+ case ScriptBaseClass.LINK_ROOT:
+ ret = new List();
+ ret.Add(part.ParentGroup.RootPart);
+ return ret;
+
+ case ScriptBaseClass.LINK_ALL_OTHERS:
+ ret = new List(part.ParentGroup.Parts);
+
+ if (ret.Contains(part))
+ ret.Remove(part);
+
+ return ret;
+
+ case ScriptBaseClass.LINK_ALL_CHILDREN:
+ ret = new List(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 target = part.ParentGroup.GetLinkNumPart(linkType);
+ if (target == null)
+ return new List();
+ ret = new List();
+ ret.Add(target);
+ return ret;
+ }
+ }
+
+ public List GetLinkEntities(int linkType)
+ {
+ return GetLinkEntities(m_host, linkType);
+ }
+
+ public List GetLinkEntities(SceneObjectPart part, int linkType)
+ {
+ List ret;
+
+ switch (linkType)
+ {
+ case ScriptBaseClass.LINK_SET:
+ return new List(part.ParentGroup.Parts);
+
+ case ScriptBaseClass.LINK_ROOT:
+ return new List() { part.ParentGroup.RootPart };
+
+ case ScriptBaseClass.LINK_ALL_OTHERS:
+ ret = new List(part.ParentGroup.Parts);
+
+ if (ret.Contains(part))
+ ret.Remove(part);
+
+ return ret;
+
+ case ScriptBaseClass.LINK_ALL_CHILDREN:
+ ret = new List(part.ParentGroup.Parts);
+
+ if (ret.Contains(part.ParentGroup.RootPart))
+ ret.Remove(part.ParentGroup.RootPart);
+
+ return ret;
+
+ case ScriptBaseClass.LINK_THIS:
+ return new List() { part };
+
+ default:
+ if (linkType < 0)
+ return new List();
+
+ ISceneEntity target = GetLinkEntity(part, linkType);
+ if (target == null)
+ return new List();
+
+ return new List() { target };
+ }
+ }
+
+ //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);
+
+ 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
+
+ ///
+ /// Convert an LSL rotation to a Euler vector.
+ ///
+ ///
+ /// 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
+ ///
+ ///
+ ///
+ 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()=<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();
+ 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();
+ 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();
+ 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)
+ {
+ Error("llRegionSay", "Cannot use on channel 0");
+ return;
+ }
+
+ if (text.Length > 1023)
+ text = text.Substring(0, 1023);
+
+ m_host.AddScriptLPS(1);
+
+ World.SimChat(Utils.StringToBytes(text),
+ ChatTypeEnum.Region, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
+
+ IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface();
+ 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);
+
+ World.SimChatToAgent(TargetID, Utils.StringToBytes(msg),
+ channel, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true);
+
+ IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface();
+ 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();
+ 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();
+ 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();
+ 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();
+ 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);
+ }
+
+ ///
+ /// See http://wiki.secondlife.com/wiki/LlDetectedTouchBinormal for details
+ ///
+ 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;
+ }
+
+ ///
+ /// See http://wiki.secondlife.com/wiki/LlDetectedTouchFace for details
+ ///
+ 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);
+ }
+
+ ///
+ /// See http://wiki.secondlife.com/wiki/LlDetectedTouchNormal for details
+ ///
+ 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;
+ }
+
+ ///
+ /// See http://wiki.secondlife.com/wiki/LlDetectedTouchPos for details
+ ///
+ 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;
+ }
+
+ ///
+ /// See http://wiki.secondlife.com/wiki/LlDetectedTouchST for details
+ ///
+ 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;
+ }
+
+ ///
+ /// See http://wiki.secondlife.com/wiki/LlDetectedTouchUV for details
+ ///
+ 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();
+ 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();
+ 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)
+ m_host.BlockGrab = value != 0;
+
+ if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT) == ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT)
+ m_host.ParentGroup.BlockGrabOverride = value != 0;
+
+ 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:
+ return m_host.BlockGrab ? 1 : 0;
+
+ case ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT:
+ return m_host.ParentGroup.BlockGrabOverride ? 1 : 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;
+
+ case ScriptBaseClass.STATUS_SANDBOX:
+ if (m_host.GetStatusSandbox())
+ return 1;
+ else
+ return 0;
+ }
+ return 0;
+ }
+
+ public void llSetScale(LSL_Vector scale)
+ {
+ m_host.AddScriptLPS(1);
+ SetScale(m_host, scale);
+ }
+
+ protected void SetScale(SceneObjectPart part, LSL_Vector scale)
+ {
+ // TODO: this needs to trigger a persistance save as well
+ if (part == null || part.ParentGroup.IsDeleted)
+ return;
+
+ // First we need to check whether or not we need to clamp the size of a physics-enabled prim
+ PhysicsActor pa = part.ParentGroup.RootPart.PhysActor;
+ if (pa != null && pa.IsPhysical)
+ {
+ scale.x = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.x));
+ scale.y = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.y));
+ scale.z = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.z));
+ }
+ else
+ {
+ // If not physical, then we clamp the scale to the non-physical min/max
+ scale.x = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.x));
+ scale.y = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.y));
+ scale.z = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.z));
+ }
+
+ Vector3 tmp = part.Scale;
+ tmp.X = (float)scale.x;
+ tmp.Y = (float)scale.y;
+ tmp.Z = (float)scale.z;
+ part.Scale = tmp;
+ part.SendFullUpdateToAllClients();
+ }
+
+ public LSL_Vector llGetScale()
+ {
+ m_host.AddScriptLPS(1);
+ return new LSL_Vector(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
+ }
+
+ public void llSetClickAction(int action)
+ {
+ m_host.AddScriptLPS(1);
+ m_host.ClickAction = (byte)action;
+ m_host.ParentGroup.HasGroupChanged = true;
+ m_host.ScheduleFullUpdate();
+ return;
+ }
+
+ public void llSetColor(LSL_Vector color, int face)
+ {
+ m_host.AddScriptLPS(1);
+
+ if (face == ScriptBaseClass.ALL_SIDES)
+ face = SceneObjectPart.ALL_SIDES;
+
+ m_host.SetFaceColorAlpha(face, color, null);
+ }
+
+ public void llSetContentType(LSL_Key id, LSL_Integer type)
+ {
+ m_host.AddScriptLPS(1);
+
+ if (m_UrlModule == null)
+ return;
+
+ // Make sure the content type is text/plain to start with
+ m_UrlModule.HttpContentType(new UUID(id), "text/plain");
+
+ // Is the object owner online and in the region
+ ScenePresence agent = World.GetScenePresence(m_host.ParentGroup.OwnerID);
+ if (agent == null || agent.IsChildAgent)
+ return; // Fail if the owner is not in the same region
+
+ // Is it the embeded browser?
+ string userAgent = m_UrlModule.GetHttpHeader(new UUID(id), "user-agent");
+ if (userAgent.IndexOf("SecondLife") < 0)
+ return; // Not the embedded browser. Is this check good enough?
+
+ // Use the IP address of the client and check against the request
+ // seperate logins from the same IP will allow all of them to get non-text/plain as long
+ // as the owner is in the region. Same as SL!
+ string logonFromIPAddress = agent.ControllingClient.RemoteEndPoint.Address.ToString();
+ string requestFromIPAddress = m_UrlModule.GetHttpHeader(new UUID(id), "remote_addr");
+ //m_log.Debug("IP from header='" + requestFromIPAddress + "' IP from endpoint='" + logonFromIPAddress + "'");
+ if (requestFromIPAddress == null || requestFromIPAddress.Trim() == "")
+ return;
+ if (logonFromIPAddress == null || logonFromIPAddress.Trim() == "")
+ return;
+
+ // If the request isnt from the same IP address then the request cannot be from the owner
+ if (!requestFromIPAddress.Trim().Equals(logonFromIPAddress.Trim()))
+ return;
+
+ switch (type)
+ {
+ case ScriptBaseClass.CONTENT_TYPE_HTML:
+ m_UrlModule.HttpContentType(new UUID(id), "text/html");
+ break;
+ case ScriptBaseClass.CONTENT_TYPE_XML:
+ m_UrlModule.HttpContentType(new UUID(id), "application/xml");
+ break;
+ case ScriptBaseClass.CONTENT_TYPE_XHTML:
+ m_UrlModule.HttpContentType(new UUID(id), "application/xhtml+xml");
+ break;
+ case ScriptBaseClass.CONTENT_TYPE_ATOM:
+ m_UrlModule.HttpContentType(new UUID(id), "application/atom+xml");
+ break;
+ case ScriptBaseClass.CONTENT_TYPE_JSON:
+ m_UrlModule.HttpContentType(new UUID(id), "application/json");
+ break;
+ case ScriptBaseClass.CONTENT_TYPE_LLSD:
+ m_UrlModule.HttpContentType(new UUID(id), "application/llsd+xml");
+ break;
+ case ScriptBaseClass.CONTENT_TYPE_FORM:
+ m_UrlModule.HttpContentType(new UUID(id), "application/x-www-form-urlencoded");
+ break;
+ case ScriptBaseClass.CONTENT_TYPE_RSS:
+ m_UrlModule.HttpContentType(new UUID(id), "application/rss+xml");
+ break;
+ default:
+ m_UrlModule.HttpContentType(new UUID(id), "text/plain");
+ break;
+ }
+ }
+
+ public void SetTexGen(SceneObjectPart part, int face,int style)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ MappingType textype;
+ textype = MappingType.Default;
+ if (style == (int)ScriptBaseClass.PRIM_TEXGEN_PLANAR)
+ textype = MappingType.Planar;
+
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ tex.CreateFace((uint) face);
+ tex.FaceTextures[face].TexMapType = textype;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ else if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (uint i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ tex.FaceTextures[i].TexMapType = textype;
+ }
+ tex.DefaultTexture.TexMapType = textype;
+ }
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ public void SetGlow(SceneObjectPart part, int face, float glow)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ tex.CreateFace((uint) face);
+ tex.FaceTextures[face].Glow = glow;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ else if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (uint i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ tex.FaceTextures[i].Glow = glow;
+ }
+ tex.DefaultTexture.Glow = glow;
+ }
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
+ {
+
+ Shininess sval = new Shininess();
+
+ switch (shiny)
+ {
+ case 0:
+ sval = Shininess.None;
+ break;
+ case 1:
+ sval = Shininess.Low;
+ break;
+ case 2:
+ sval = Shininess.Medium;
+ break;
+ case 3:
+ sval = Shininess.High;
+ break;
+ default:
+ sval = Shininess.None;
+ break;
+ }
+
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ tex.CreateFace((uint) face);
+ tex.FaceTextures[face].Shiny = sval;
+ tex.FaceTextures[face].Bump = bump;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ else if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (uint i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ tex.FaceTextures[i].Shiny = sval;
+ tex.FaceTextures[i].Bump = bump;
+ }
+ tex.DefaultTexture.Shiny = sval;
+ tex.DefaultTexture.Bump = bump;
+ }
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ public void SetFullBright(SceneObjectPart part, int face, bool bright)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ tex.CreateFace((uint) face);
+ tex.FaceTextures[face].Fullbright = bright;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ else if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (uint i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ tex.FaceTextures[i].Fullbright = bright;
+ }
+ }
+ tex.DefaultTexture.Fullbright = bright;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ public LSL_Float llGetAlpha(int face)
+ {
+ m_host.AddScriptLPS(1);
+
+ return GetAlpha(m_host, face);
+ }
+
+ protected LSL_Float GetAlpha(SceneObjectPart part, int face)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ int i;
+ double sum = 0.0;
+ for (i = 0 ; i < GetNumberOfSides(part); i++)
+ sum += (double)tex.GetFace((uint)i).RGBA.A;
+ return sum;
+ }
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ return (double)tex.GetFace((uint)face).RGBA.A;
+ }
+ return 0.0;
+ }
+
+ public void llSetAlpha(double alpha, int face)
+ {
+ m_host.AddScriptLPS(1);
+
+ SetAlpha(m_host, alpha, face);
+ }
+
+ public void llSetLinkAlpha(int linknumber, double alpha, int face)
+ {
+ m_host.AddScriptLPS(1);
+
+ List parts = GetLinkParts(linknumber);
+
+ foreach (SceneObjectPart part in parts)
+ SetAlpha(part, alpha, face);
+ }
+
+ protected void SetAlpha(SceneObjectPart part, double alpha, int face)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ Color4 texcolor;
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ texcolor = tex.CreateFace((uint)face).RGBA;
+ texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
+ tex.FaceTextures[face].RGBA = texcolor;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ else if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (int i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ texcolor = tex.FaceTextures[i].RGBA;
+ texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
+ tex.FaceTextures[i].RGBA = texcolor;
+ }
+ }
+
+ // In some cases, the default texture can be null, eg when every face
+ // has a unique texture
+ if (tex.DefaultTexture != null)
+ {
+ texcolor = tex.DefaultTexture.RGBA;
+ texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
+ tex.DefaultTexture.RGBA = texcolor;
+ }
+
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ ///
+ /// Set flexi parameters of a part.
+ ///
+ /// FIXME: Much of this code should probably be within the part itself.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
+ float wind, float tension, LSL_Vector Force)
+ {
+ if (part == null)
+ return;
+
+ if (flexi)
+ {
+ part.Shape.FlexiEntry = true; // this setting flexi true isn't working, but the below parameters do
+ // work once the prim is already flexi
+ part.Shape.FlexiSoftness = softness;
+ part.Shape.FlexiGravity = gravity;
+ part.Shape.FlexiDrag = friction;
+ part.Shape.FlexiWind = wind;
+ part.Shape.FlexiTension = tension;
+ part.Shape.FlexiForceX = (float)Force.x;
+ part.Shape.FlexiForceY = (float)Force.y;
+ part.Shape.FlexiForceZ = (float)Force.z;
+ part.Shape.PathCurve = (byte)Extrusion.Flexible;
+ }
+ else
+ {
+ // Other values not set, they do not seem to be sent to the viewer
+ // Setting PathCurve appears to be what actually toggles the check box and turns Flexi on and off
+ part.Shape.PathCurve = (byte)Extrusion.Straight;
+ part.Shape.FlexiEntry = false;
+ }
+ part.ParentGroup.HasGroupChanged = true;
+ part.ScheduleFullUpdate();
+ }
+
+ ///
+ /// Set a light point on a part
+ ///
+ /// FIXME: Much of this code should probably be in SceneObjectGroup
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
+ {
+ if (part == null)
+ return;
+
+ if (light)
+ {
+ part.Shape.LightEntry = true;
+ part.Shape.LightColorR = Util.Clip((float)color.x, 0.0f, 1.0f);
+ part.Shape.LightColorG = Util.Clip((float)color.y, 0.0f, 1.0f);
+ part.Shape.LightColorB = Util.Clip((float)color.z, 0.0f, 1.0f);
+ part.Shape.LightIntensity = Util.Clip((float)intensity, 0.0f, 1.0f);
+ part.Shape.LightRadius = Util.Clip((float)radius, 0.1f, 20.0f);
+ part.Shape.LightFalloff = Util.Clip((float)falloff, 0.01f, 2.0f);
+ }
+ else
+ {
+ part.Shape.LightEntry = false;
+ }
+
+ part.ParentGroup.HasGroupChanged = true;
+ part.ScheduleFullUpdate();
+ }
+
+ public LSL_Vector llGetColor(int face)
+ {
+ m_host.AddScriptLPS(1);
+ return GetColor(m_host, face);
+ }
+
+ protected LSL_Vector GetColor(SceneObjectPart part, int face)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ Color4 texcolor;
+ LSL_Vector rgb = new LSL_Vector();
+ if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ int i;
+
+ for (i = 0 ; i < GetNumberOfSides(part); i++)
+ {
+ texcolor = tex.GetFace((uint)i).RGBA;
+ rgb.x += texcolor.R;
+ rgb.y += texcolor.G;
+ rgb.z += texcolor.B;
+ }
+
+ rgb.x /= (float)GetNumberOfSides(part);
+ rgb.y /= (float)GetNumberOfSides(part);
+ rgb.z /= (float)GetNumberOfSides(part);
+
+ return rgb;
+ }
+
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ texcolor = tex.GetFace((uint)face).RGBA;
+ rgb.x = texcolor.R;
+ rgb.y = texcolor.G;
+ rgb.z = texcolor.B;
+
+ return rgb;
+ }
+ else
+ {
+ return new LSL_Vector();
+ }
+ }
+
+ public void llSetTexture(string texture, int face)
+ {
+ m_host.AddScriptLPS(1);
+ SetTexture(m_host, texture, face);
+ ScriptSleep(m_sleepMsOnSetTexture);
+ }
+
+ public void llSetLinkTexture(int linknumber, string texture, int face)
+ {
+ m_host.AddScriptLPS(1);
+
+ List parts = GetLinkParts(linknumber);
+
+ foreach (SceneObjectPart part in parts)
+ SetTexture(part, texture, face);
+
+ ScriptSleep(m_sleepMsOnSetLinkTexture);
+ }
+
+ protected void SetTexture(SceneObjectPart part, string texture, int face)
+ {
+ UUID textureID = new UUID();
+
+ textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture);
+ if (textureID == UUID.Zero)
+ {
+ if (!UUID.TryParse(texture, out textureID))
+ return;
+ }
+
+ Primitive.TextureEntry tex = part.Shape.Textures;
+
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
+ texface.TextureID = textureID;
+ tex.FaceTextures[face] = texface;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ else if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (uint i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ tex.FaceTextures[i].TextureID = textureID;
+ }
+ }
+ tex.DefaultTexture.TextureID = textureID;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ public void llScaleTexture(double u, double v, int face)
+ {
+ m_host.AddScriptLPS(1);
+
+ ScaleTexture(m_host, u, v, face);
+ ScriptSleep(m_sleepMsOnScaleTexture);
+ }
+
+ protected void ScaleTexture(SceneObjectPart part, double u, double v, int face)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
+ texface.RepeatU = (float)u;
+ texface.RepeatV = (float)v;
+ tex.FaceTextures[face] = texface;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (int i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ tex.FaceTextures[i].RepeatU = (float)u;
+ tex.FaceTextures[i].RepeatV = (float)v;
+ }
+ }
+ tex.DefaultTexture.RepeatU = (float)u;
+ tex.DefaultTexture.RepeatV = (float)v;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ public void llOffsetTexture(double u, double v, int face)
+ {
+ m_host.AddScriptLPS(1);
+ OffsetTexture(m_host, u, v, face);
+ ScriptSleep(m_sleepMsOnOffsetTexture);
+ }
+
+ protected void OffsetTexture(SceneObjectPart part, double u, double v, int face)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
+ texface.OffsetU = (float)u;
+ texface.OffsetV = (float)v;
+ tex.FaceTextures[face] = texface;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (int i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ tex.FaceTextures[i].OffsetU = (float)u;
+ tex.FaceTextures[i].OffsetV = (float)v;
+ }
+ }
+ tex.DefaultTexture.OffsetU = (float)u;
+ tex.DefaultTexture.OffsetV = (float)v;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ public void llRotateTexture(double rotation, int face)
+ {
+ m_host.AddScriptLPS(1);
+ RotateTexture(m_host, rotation, face);
+ ScriptSleep(m_sleepMsOnRotateTexture);
+ }
+
+ protected void RotateTexture(SceneObjectPart part, double rotation, int face)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
+ texface.Rotation = (float)rotation;
+ tex.FaceTextures[face] = texface;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ for (int i = 0; i < GetNumberOfSides(part); i++)
+ {
+ if (tex.FaceTextures[i] != null)
+ {
+ tex.FaceTextures[i].Rotation = (float)rotation;
+ }
+ }
+ tex.DefaultTexture.Rotation = (float)rotation;
+ part.UpdateTextureEntry(tex.GetBytes());
+ return;
+ }
+ }
+
+ public LSL_String llGetTexture(int face)
+ {
+ m_host.AddScriptLPS(1);
+ return GetTexture(m_host, face);
+ }
+
+ protected LSL_String GetTexture(SceneObjectPart part, int face)
+ {
+ Primitive.TextureEntry tex = part.Shape.Textures;
+ if (face == ScriptBaseClass.ALL_SIDES)
+ {
+ face = 0;
+ }
+
+ if (face >= 0 && face < GetNumberOfSides(part))
+ {
+ Primitive.TextureEntryFace texface;
+ texface = tex.GetFace((uint)face);
+ string texture = texface.TextureID.ToString();
+
+ lock (part.TaskInventory)
+ {
+ foreach (KeyValuePair inv in part.TaskInventory)
+ {
+ if (inv.Value.AssetID == texface.TextureID)
+ {
+ texture = inv.Value.Name.ToString();
+ break;
+ }
+ }
+ }
+
+ return texture;
+ }
+ else
+ {
+ return UUID.Zero.ToString();
+ }
+ }
+
+ public void llSetPos(LSL_Vector pos)
+ {
+ m_host.AddScriptLPS(1);
+
+ SetPos(m_host, pos, true);
+
+ ScriptSleep(m_sleepMsOnSetPos);
+ }
+
+ ///
+ /// Tries to move the entire object so that the root prim is within 0.1m of position. http://wiki.secondlife.com/wiki/LlSetRegionPos
+ /// 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.
+ /// 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.
+ ///
+ ///
+ /// 1 if successful, 0 otherwise.
+ public LSL_Integer llSetRegionPos(LSL_Vector pos)
+ {
+ m_host.AddScriptLPS(1);
+
+ // BEGIN WORKAROUND
+ // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND.
+ //
+ // This workaround is to prevent silent failure of this function.
+ // According to the specification on the SL Wiki, providing a position outside of the
+ if (pos.x < 0 || pos.x > World.RegionInfo.RegionSizeX || pos.y < 0 || pos.y > World.RegionInfo.RegionSizeY)
+ {
+ return 0;
+ }
+ // END WORK AROUND
+ else if ( // this is not part of the workaround if-block because it's not related to the workaround.
+ IsPhysical() ||
+ m_host.ParentGroup.IsAttachment || // return FALSE if attachment
+ (
+ pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region.
+ pos.x > (World.RegionInfo.RegionSizeX + 10) || // return FALSE if more than 10 meters into a east-adjacent region.
+ pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region.
+ pos.y > (World.RegionInfo.RegionSizeY + 10) || // return FALSE if more than 10 meters into a north-adjacent region.
+ pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m
+ )
+ )
+ {
+ return 0;
+ }
+
+ // if we reach this point, then the object is not physical, it's not an attachment, and the destination is within the valid range.
+ // 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.
+
+ Vector3 objectPos = m_host.ParentGroup.RootPart.AbsolutePosition;
+ LandData here = World.GetLandData(objectPos);
+ LandData there = World.GetLandData(pos);
+
+ // 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.
+
+ bool sameParcel = here.GlobalID == there.GlobalID;
+
+ if (!sameParcel && !World.Permissions.CanRezObject(
+ m_host.ParentGroup.PrimCount, m_host.ParentGroup.OwnerID, pos))
+ {
+ return 0;
+ }
+
+ SetPos(m_host.ParentGroup.RootPart, pos, false);
+
+ return VecDist(pos, llGetRootPosition()) <= 0.1 ? 1 : 0;
+ }
+
+ // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
+ // note linked setpos is capped "differently"
+ private LSL_Vector SetPosAdjust(LSL_Vector start, LSL_Vector end)
+ {
+ if (llVecDist(start, end) > 10.0f * m_ScriptDistanceFactor)
+ return start + m_ScriptDistanceFactor * 10.0f * llVecNorm(end - start);
+ else
+ return end;
+ }
+
+ protected LSL_Vector GetSetPosTarget(SceneObjectPart part, LSL_Vector targetPos, LSL_Vector fromPos)
+ {
+ if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
+ return fromPos;
+
+ // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
+
+
+ float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
+ bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
+
+ if (part.ParentGroup.RootPart == part)
+ {
+ if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
+ targetPos.z = ground;
+ }
+ LSL_Vector real_vec = SetPosAdjust(fromPos, targetPos);
+
+ return real_vec;
+ }
+
+ ///
+ /// set object position, optionally capping the distance.
+ ///
+ ///
+ ///
+ /// if TRUE, will cap the distance to 10m.
+ protected void SetPos(SceneObjectPart part, LSL_Vector targetPos, bool adjust)
+ {
+ // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
+ LSL_Vector currentPos = GetPartLocalPos(part);
+
+ float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
+ bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
+
+ if (part.ParentGroup.RootPart == part)
+ {
+ if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
+ targetPos.z = ground;
+ SceneObjectGroup parent = part.ParentGroup;
+ parent.UpdateGroupPosition(!adjust ? targetPos :
+ SetPosAdjust(currentPos, targetPos));
+ }
+ else
+ {
+ part.OffsetPosition = !adjust ? targetPos :
+ SetPosAdjust(currentPos, targetPos);
+ SceneObjectGroup parent = part.ParentGroup;
+ parent.HasGroupChanged = true;
+ parent.ScheduleGroupForTerseUpdate();
+ }
+ }
+
+ public LSL_Vector llGetPos()
+ {
+ m_host.AddScriptLPS(1);
+ return m_host.GetWorldPosition();
+ }
+
+ public LSL_Vector llGetLocalPos()
+ {
+ m_host.AddScriptLPS(1);
+ return GetPartLocalPos(m_host);
+ }
+
+ protected LSL_Vector GetPartLocalPos(SceneObjectPart part)
+ {
+ m_host.AddScriptLPS(1);
+
+ Vector3 pos;
+
+ if (!part.IsRoot)
+ {
+ pos = part.OffsetPosition;
+ }
+ else
+ {
+ if (part.ParentGroup.IsAttachment)
+ {
+ pos = part.AttachedPos;
+ }
+ else
+ {
+ pos = part.AbsolutePosition;
+ }
+ }
+
+// m_log.DebugFormat("[LSL API]: Returning {0} in GetPartLocalPos()", pos);
+
+ return new LSL_Vector(pos);
+ }
+
+ public void llSetRot(LSL_Rotation rot)
+ {
+ m_host.AddScriptLPS(1);
+
+ // try to let this work as in SL...
+ if (m_host.ParentID == 0)
+ {
+ // special case: If we are root, rotate complete SOG to new rotation
+ SetRot(m_host, rot);
+ }
+ else
+ {
+ // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
+ SceneObjectPart rootPart = m_host.ParentGroup.RootPart;
+ if (rootPart != null) // better safe than sorry
+ {
+ SetRot(m_host, rootPart.RotationOffset * (Quaternion)rot);
+ }
+ }
+
+ ScriptSleep(m_sleepMsOnSetRot);
+ }
+
+ public void llSetLocalRot(LSL_Rotation rot)
+ {
+ m_host.AddScriptLPS(1);
+ SetRot(m_host, rot);
+ ScriptSleep(m_sleepMsOnSetLocalRot);
+ }
+
+ protected void SetRot(SceneObjectPart part, Quaternion rot)
+ {
+ part.UpdateRotation(rot);
+ // Update rotation does not move the object in the physics scene if it's a linkset.
+
+//KF: Do NOT use this next line if using ODE physics engine. This need a switch based on .ini Phys Engine type
+// part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
+
+ // So, after thinking about this for a bit, the issue with the part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition line
+ // is it isn't compatible with vehicles because it causes the vehicle body to have to be broken down and rebuilt
+ // It's perfectly okay when the object is not an active physical body though.
+ // So, part.ParentGroup.ResetChildPrimPhysicsPositions(); does the thing that Kitto is warning against
+ // but only if the object is not physial and active. This is important for rotating doors.
+ // without the absoluteposition = absoluteposition happening, the doors do not move in the physics
+ // scene
+ PhysicsActor pa = part.PhysActor;
+
+ if (pa != null && !pa.IsPhysical)
+ {
+ part.ParentGroup.ResetChildPrimPhysicsPositions();
+ }
+ }
+
+ ///
+ /// See http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
+ ///
+ public LSL_Rotation llGetRot()
+ {
+ // unlinked or root prim then use llRootRotation
+ // see llRootRotaion for references.
+ if (m_host.LinkNum == 0 || m_host.LinkNum == 1)
+ {
+ return llGetRootRotation();
+ }
+
+ m_host.AddScriptLPS(1);
+ Quaternion q = m_host.GetWorldRotation();
+ return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
+ }
+
+ private LSL_Rotation GetPartRot(SceneObjectPart part)
+ {
+ Quaternion q;
+ if (part.LinkNum == 0 || part.LinkNum == 1) // unlinked or root prim
+ {
+ if (part.ParentGroup.AttachmentPoint != 0)
+ {
+ ScenePresence avatar = World.GetScenePresence(part.ParentGroup.AttachedAvatar);
+ if (avatar != null)
+ {
+ if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
+ q = avatar.CameraRotation; // Mouselook
+ else
+ q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
+ }
+ else
+ q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
+ }
+ else
+ q = part.ParentGroup.GroupRotation; // just the group rotation
+
+ return new LSL_Rotation(q);
+ }
+
+ return new LSL_Rotation(part.GetWorldRotation());
+ }
+
+ public LSL_Rotation llGetLocalRot()
+ {
+ m_host.AddScriptLPS(1);
+
+ return new LSL_Rotation(m_host.RotationOffset);
+ }
+
+ public void llSetForce(LSL_Vector force, int local)
+ {
+ m_host.AddScriptLPS(1);
+
+ if (!m_host.ParentGroup.IsDeleted)
+ {
+ if (local != 0)
+ force *= llGetRot();
+
+ m_host.ParentGroup.RootPart.SetForce(force);
+ }
+ }
+
+ public LSL_Vector llGetForce()
+ {
+ LSL_Vector force = new LSL_Vector(0.0, 0.0, 0.0);
+
+ m_host.AddScriptLPS(1);
+
+ if (!m_host.ParentGroup.IsDeleted)
+ {
+ force = m_host.ParentGroup.RootPart.GetForce();
+ }
+
+ return force;
+ }
+
+ public void llSetVelocity(LSL_Vector velocity, int local)
+ {
+ m_host.AddScriptLPS(1);
+
+ if (!m_host.ParentGroup.IsDeleted)
+ {
+ if (local != 0)
+ velocity *= llGetRot();
+
+ m_host.ParentGroup.RootPart.Velocity = velocity;
+ }
+ }
+
+ public void llSetAngularVelocity(LSL_Vector angularVelocity, int local)
+ {
+ m_host.AddScriptLPS(1);
+
+ if (!m_host.ParentGroup.IsDeleted)
+ {
+ if (local != 0)
+ angularVelocity *= llGetRot();
+
+ m_host.ParentGroup.RootPart.AngularVelocity = angularVelocity;
+ }
+ }
+
+ public LSL_Integer llTarget(LSL_Vector position, double range)
+ {
+ m_host.AddScriptLPS(1);
+ return m_host.ParentGroup.registerTargetWaypoint(position,
+ (float)range);
+ }
+
+ public void llTargetRemove(int number)
+ {
+ m_host.AddScriptLPS(1);
+ m_host.ParentGroup.unregisterTargetWaypoint(number);
+ }
+
+ public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
+ {
+ m_host.AddScriptLPS(1);
+ return m_host.ParentGroup.registerRotTargetWaypoint(rot, (float)error);
+ }
+
+ public void llRotTargetRemove(int number)
+ {
+ m_host.AddScriptLPS(1);
+ m_host.ParentGroup.unregisterRotTargetWaypoint(number);
+ }
+
+ public void llMoveToTarget(LSL_Vector target, double tau)
+ {
+ m_host.AddScriptLPS(1);
+ m_host.MoveToTarget(target, (float)tau);
+ }
+
+ public void llStopMoveToTarget()
+ {
+ m_host.AddScriptLPS(1);
+ m_host.StopMoveToTarget();
+ }
+
+ public void llApplyImpulse(LSL_Vector force, int local)
+ {
+ m_host.AddScriptLPS(1);
+ //No energy force yet
+ Vector3 v = force;
+ if (v.Length() > 20000.0f)
+ {
+ v.Normalize();
+ v = v * 20000.0f;
+ }
+ m_host.ApplyImpulse(v, local != 0);
+ }
+
+ public void llApplyRotationalImpulse(LSL_Vector force, int local)
+ {
+ m_host.AddScriptLPS(1);
+ m_host.ApplyAngularImpulse(force, local != 0);
+ }
+
+ public void llSetTorque(LSL_Vector torque, int local)
+ {
+ m_host.AddScriptLPS(1);
+ m_host.SetAngularImpulse(torque, local != 0);
+ }
+
+ public LSL_Vector llGetTorque()
+ {
+ m_host.AddScriptLPS(1);
+
+ return new LSL_Vector(m_host.ParentGroup.GetTorque());
+ }
+
+ public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
+ {
+ m_host.AddScriptLPS(1);
+ llSetForce(force, local);
+ llSetTorque(torque, local);
+ }
+
+ public LSL_Vector llGetVel()
+ {
+ m_host.AddScriptLPS(1);
+
+ Vector3 vel;
+
+ if (m_host.ParentGroup.IsAttachment)
+ {
+ ScenePresence avatar = m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
+ vel = avatar.GetWorldVelocity();
+ }
+ else
+ {
+ vel = m_host.Velocity;
+ }
+
+ return new LSL_Vector(vel);
+ }
+
+ public LSL_Vector llGetAccel()
+ {
+ m_host.AddScriptLPS(1);
+
+ return new LSL_Vector(m_host.Acceleration);
+ }
+
+ public LSL_Vector llGetOmega()
+ {
+ m_host.AddScriptLPS(1);
+
+ return new LSL_Vector(m_host.AngularVelocity);
+ }
+
+ public LSL_Float llGetTimeOfDay()
+ {
+ m_host.AddScriptLPS(1);
+ return (double)((DateTime.Now.TimeOfDay.TotalMilliseconds / 1000) % (3600 * 4));
+ }
+
+ public LSL_Float llGetWallclock()
+ {
+ m_host.AddScriptLPS(1);
+ return DateTime.Now.TimeOfDay.TotalSeconds;
+ }
+
+ public LSL_Float llGetTime()
+ {
+ m_host.AddScriptLPS(1);
+ TimeSpan ScriptTime = DateTime.Now - m_timer;
+ return (double)(ScriptTime.TotalMilliseconds / 1000);
+ }
+
+ public void llResetTime()
+ {
+ m_host.AddScriptLPS(1);
+ m_timer = DateTime.Now;
+ }
+
+ public LSL_Float llGetAndResetTime()
+ {
+ m_host.AddScriptLPS(1);
+ TimeSpan ScriptTime = DateTime.Now - m_timer;
+ m_timer = DateTime.Now;
+ return (double)(ScriptTime.TotalMilliseconds / 1000);
+ }
+
+ public void llSound(string sound, double volume, int queue, int loop)
+ {
+ m_host.AddScriptLPS(1);
+ Deprecated("llSound", "Use llPlaySound instead");
+ }
+
+ // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
+ // 20080530 Updated to remove code duplication
+ public void llPlaySound(string sound, double volume)
+ {
+ m_host.AddScriptLPS(1);
+
+ // send the sound, once, to all clients in range
+ if (m_SoundModule != null)
+ {
+ m_SoundModule.SendSound(
+ m_host.UUID,
+ ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound),
+ volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None,
+ 0, false, false);
+ }
+ }
+
+ public void llLoopSound(string sound, double volume)
+ {
+ m_host.AddScriptLPS(1);
+ if (m_SoundModule != null)
+ {
+ m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
+ volume, 20, false);
+ }
+ }
+
+ public void llLoopSoundMaster(string sound, double volume)
+ {
+ m_host.AddScriptLPS(1);
+ if (m_SoundModule != null)
+ {
+ m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
+ volume, 20, true);
+ }
+ }
+
+ public void llLoopSoundSlave(string sound, double volume)
+ {
+ m_host.AddScriptLPS(1);
+ lock (m_host.ParentGroup.LoopSoundSlavePrims)
+ {
+ m_host.ParentGroup.LoopSoundSlavePrims.Add(m_host);
+ }
+ }
+
+ public void llPlaySoundSlave(string sound, double volume)
+ {
+ m_host.AddScriptLPS(1);
+
+ // send the sound, once, to all clients in range
+ if (m_SoundModule != null)
+ {
+ m_SoundModule.SendSound(m_host.UUID,
+ ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0,
+ 0, true, false);
+ }
+ }
+
+ public void llTriggerSound(string sound, double volume)
+ {
+ m_host.AddScriptLPS(1);
+ // send the sound, once, to all clients in rangeTrigger or play an attached sound in this part's inventory.
+ if (m_SoundModule != null)
+ {
+ m_SoundModule.SendSound(m_host.UUID,
+ ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, true, 0, 0,
+ false, false);
+ }
+ }
+
+ public void llStopSound()
+ {
+ m_host.AddScriptLPS(1);
+
+ if (m_SoundModule != null)
+ m_SoundModule.StopSound(m_host.UUID);
+ }
+
+ public void llPreloadSound(string sound)
+ {
+ m_host.AddScriptLPS(1);
+ if (m_SoundModule != null)
+ m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0);
+ ScriptSleep(m_sleepMsOnPreloadSound);
+ }
+
+ ///
+ /// Return a portion of the designated string bounded by
+ /// inclusive indices (start and end). As usual, the negative
+ /// indices, and the tolerance for out-of-bound values, makes
+ /// this more complicated than it might otherwise seem.
+ ///
+ public LSL_String llGetSubString(string src, int start, int end)
+ {
+ m_host.AddScriptLPS(1);
+
+ // Normalize indices (if negative).
+ // After normlaization they may still be
+ // negative, but that is now relative to
+ // the start, rather than the end, of the
+ // sequence.
+
+ if (start < 0)
+ {
+ start = src.Length+start;
+ }
+ if (end < 0)
+ {
+ end = src.Length+end;
+ }
+
+ // Conventional substring
+ if (start <= end)
+ {
+ // Implies both bounds are out-of-range.
+ if (end < 0 || start >= src.Length)
+ {
+ return String.Empty;
+ }
+ // If end is positive, then it directly
+ // corresponds to the lengt of the substring
+ // needed (plus one of course). BUT, it
+ // must be within bounds.
+ if (end >= src.Length)
+ {
+ end = src.Length-1;
+ }
+
+ if (start < 0)
+ {
+ return src.Substring(0,end+1);
+ }
+ // Both indices are positive
+ return src.Substring(start, (end+1) - start);
+ }
+
+ // Inverted substring (end < start)
+ else
+ {
+ // Implies both indices are below the
+ // lower bound. In the inverted case, that
+ // means the entire string will be returned
+ // unchanged.
+ if (start < 0)
+ {
+ return src;
+ }
+ // If both indices are greater than the upper
+ // bound the result may seem initially counter
+ // intuitive.
+ if (end >= src.Length)
+ {
+ return src;
+ }
+
+ if (end < 0)
+ {
+ if (start < src.Length)
+ {
+ return src.Substring(start);
+ }
+ else
+ {
+ return String.Empty;
+ }
+ }
+ else
+ {
+ if (start < src.Length)
+ {
+ return src.Substring(0,end+1) + src.Substring(start);
+ }
+ else
+ {
+ return src.Substring(0,end+1);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Delete substring removes the specified substring bounded
+ /// by the inclusive indices start and end. Indices may be
+ /// negative (indicating end-relative) and may be inverted,
+ /// i.e. end < start.
+ ///
+ public LSL_String llDeleteSubString(string src, int start, int end)
+ {
+ m_host.AddScriptLPS(1);
+
+ // Normalize indices (if negative).
+ // After normlaization they may still be
+ // negative, but that is now relative to
+ // the start, rather than the end, of the
+ // sequence.
+ if (start < 0)
+ {
+ start = src.Length+start;
+ }
+ if (end < 0)
+ {
+ end = src.Length+end;
+ }
+ // Conventionally delimited substring
+ if (start <= end)
+ {
+ // If both bounds are outside of the existing
+ // string, then return unchanges.
+ if (end < 0 || start >= src.Length)
+ {
+ return src;
+ }
+ // At least one bound is in-range, so we
+ // need to clip the out-of-bound argument.
+ if (start < 0)
+ {
+ start = 0;
+ }
+
+ if (end >= src.Length)
+ {
+ end = src.Length-1;
+ }
+
+ return src.Remove(start,end-start+1);
+ }
+ // Inverted substring
+ else
+ {
+ // In this case, out of bounds means that
+ // the existing string is part of the cut.
+ if (start < 0 || end >= src.Length)
+ {
+ return String.Empty;
+ }
+
+ if (end > 0)
+ {
+ if (start < src.Length)
+ {
+ return src.Remove(start).Remove(0,end+1);
+ }
+ else
+ {
+ return src.Remove(0,end+1);
+ }
+ }
+ else
+ {
+ if (start < src.Length)
+ {
+ return src.Remove(start);
+ }
+ else
+ {
+ return src;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Insert string inserts the specified string identified by src
+ /// at the index indicated by index. Index may be negative, in
+ /// which case it is end-relative. The index may exceed either
+ /// string bound, with the result being a concatenation.
+ ///
+ public LSL_String llInsertString(string dest, int index, string src)
+ {
+ m_host.AddScriptLPS(1);
+
+ // Normalize indices (if negative).
+ // After normlaization they may still be
+ // negative, but that is now relative to
+ // the start, rather than the end, of the
+ // sequence.
+ if (index < 0)
+ {
+ index = dest.Length+index;
+
+ // Negative now means it is less than the lower
+ // bound of the string.
+
+ if (index < 0)
+ {
+ return src+dest;
+ }
+
+ }
+
+ if (index >= dest.Length)
+ {
+ return dest+src;
+ }
+
+ // The index is in bounds.
+ // In this case the index refers to the index that will
+ // be assigned to the first character of the inserted string.
+ // So unlike the other string operations, we do not add one
+ // to get the correct string length.
+ return dest.Substring(0,index)+src+dest.Substring(index);
+
+ }
+
+ public LSL_String llToUpper(string src)
+ {
+ m_host.AddScriptLPS(1);
+ return src.ToUpper();
+ }
+
+ public LSL_String llToLower(string src)
+ {
+ m_host.AddScriptLPS(1);
+ return src.ToLower();
+ }
+
+ public void llGiveMoney(string destination, int amount)
+ {
+ Util.FireAndForget(x =>
+ {
+ m_host.AddScriptLPS(1);
+
+ if (m_item.PermsGranter == UUID.Zero)
+ return;
+
+ if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
+ {
+ Error("llGiveMoney", "No permissions to give money");
+ return;
+ }
+
+ UUID toID = new UUID();
+
+ if (!UUID.TryParse(destination, out toID))
+ {
+ Error("llGiveMoney", "Bad key in llGiveMoney");
+ return;
+ }
+
+ IMoneyModule money = World.RequestModuleInterface();
+
+ if (money == null)
+ {
+ NotImplemented("llGiveMoney");
+ return;
+ }
+
+ money.ObjectGiveMoney(
+ m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
+ }, null, "LSL_Api.llGiveMoney");
+ }
+
+ public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
+ {
+ m_host.AddScriptLPS(1);
+ Deprecated("llMakeExplosion", "Use llParticleSystem instead");
+ ScriptSleep(m_sleepMsOnMakeExplosion);
+ }
+
+ public void llMakeFountain(int particles, double scale, double vel, double lifetime, double arc, int bounce, string texture, LSL_Vector offset, double bounce_offset)
+ {
+ m_host.AddScriptLPS(1);
+ Deprecated("llMakeFountain", "Use llParticleSystem instead");
+ ScriptSleep(m_sleepMsOnMakeFountain);
+ }
+
+ public void llMakeSmoke(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
+ {
+ m_host.AddScriptLPS(1);
+ Deprecated("llMakeSmoke", "Use llParticleSystem instead");
+ ScriptSleep(m_sleepMsOnMakeSmoke);
+ }
+
+ public void llMakeFire(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
+ {
+ m_host.AddScriptLPS(1);
+ Deprecated("llMakeFire", "Use llParticleSystem instead");
+ ScriptSleep(m_sleepMsOnMakeFire);
+ }
+
+ public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
+ {
+ m_host.AddScriptLPS(1);
+
+ Util.FireAndForget(x =>
+ {
+ if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
+ return;
+
+ float dist = (float)llVecDist(llGetPos(), pos);
+
+ if (dist > m_ScriptDistanceFactor * 10.0f)
+ return;
+
+ TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
+
+ if (item == null)
+ {
+ Error("llRezAtRoot", "Can't find object '" + inventory + "'");
+ return;
+ }
+
+ if (item.InvType != (int)InventoryType.Object)
+ {
+ Error("llRezAtRoot", "Can't create requested object; object is missing from database");
+ return;
+ }
+
+ // need the magnitude later
+ // float velmag = (float)Util.GetMagnitude(llvel);
+
+ List new_groups = World.RezObject(m_host, item, pos, rot, vel, param);
+
+ // If either of these are null, then there was an unknown error.
+ if (new_groups == null)
+ return;
+
+ foreach (SceneObjectGroup group in new_groups)
+ {
+ // objects rezzed with this method are die_at_edge by default.
+ group.RootPart.SetDieAtEdge(true);
+
+ group.ResumeScripts();
+
+ m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
+ "object_rez", new Object[] {
+ new LSL_String(
+ group.RootPart.UUID.ToString()) },
+ new DetectParams[0]));
+
+ float groupmass = group.GetMass();
+
+ PhysicsActor pa = group.RootPart.PhysActor;
+
+ //Recoil.
+ if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero)
+ {
+ Vector3 recoil = -vel * groupmass * m_recoilScaleFactor;
+ if (recoil != Vector3.Zero)
+ {
+ llApplyImpulse(recoil, 0);
+ }
+ }
+ // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
+ }
+ }, null, "LSL_Api.llRezAtRoot");
+
+ //ScriptSleep((int)((groupmass * velmag) / 10));
+ ScriptSleep(m_sleepMsOnRezAtRoot);
+ }
+
+ public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
+ {
+ llRezAtRoot(inventory, pos, vel, rot, param);
+ }
+
+ public void llLookAt(LSL_Vector target, double strength, double damping)
+ {
+ m_host.AddScriptLPS(1);
+ // Determine where we are looking from
+ LSL_Vector from = llGetPos();
+
+ // normalized direction to target
+ LSL_Vector dir = llVecNorm(target - from);
+ // use vertical to help compute left axis
+ LSL_Vector up = new LSL_Vector(0.0, 0.0, 1.0);
+ // find normalized left axis parallel to horizon
+ LSL_Vector left = llVecNorm(LSL_Vector.Cross(up, dir));
+ // make up orthogonal to left and dir
+ up = LSL_Vector.Cross(dir, left);
+
+ // compute rotation based on orthogonal axes
+ LSL_Rotation rot = new LSL_Rotation(0.0, 0.707107, 0.0, 0.707107) * llAxes2Rot(dir, left, up);
+
+ // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
+ // set the rotation of the object, copy that behavior
+ PhysicsActor pa = m_host.PhysActor;
+
+ if (m_host.ParentGroup.IsAttachment || strength == 0 || pa == null || !pa.IsPhysical)
+ {
+ llSetRot(rot);
+ }
+ else
+ {
+ m_host.StartLookAt(rot, (float)strength, (float)damping);
+ }
+ }
+
+ public void llStopLookAt()
+ {
+ m_host.AddScriptLPS(1);
+ m_host.StopLookAt();
+ }
+
+ public void llSetTimerEvent(double sec)
+ {
+ if (sec != 0.0 && sec < m_MinTimerInterval)
+ sec = m_MinTimerInterval;
+ m_host.AddScriptLPS(1);
+ // Setting timer repeat
+ AsyncCommands.TimerPlugin.SetTimerEvent(m_host.LocalId, m_item.ItemID, sec);
+ }
+
+ public virtual void llSleep(double sec)
+ {
+// m_log.Info("llSleep snoozing " + sec + "s.");
+ m_host.AddScriptLPS(1);
+
+ Sleep((int)(sec * 1000));
+ }
+
+ public LSL_Float llGetMass()
+ {
+ m_host.AddScriptLPS(1);
+
+ if (m_host.ParentGroup.IsAttachment)
+ {
+ ScenePresence attachedAvatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
+
+ if (attachedAvatar != null)
+ {
+ return attachedAvatar.GetMass();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ if (m_host.IsRoot)
+ {
+ return m_host.ParentGroup.GetMass();
+ }
+ else
+ {
+ return m_host.GetMass();
+ }
+ }
+ }
+
+ public LSL_Float llGetMassMKS()
+ {
+ // this is what the wiki says it does!
+ // http://wiki.secondlife.com/wiki/LlGetMassMKS
+ return llGetMass() * 100.0;
+ }
+
+ public void llCollisionFilter(string name, string id, int accept)
+ {
+ m_host.AddScriptLPS(1);
+ m_host.CollisionFilter.Clear();
+ UUID objectID;
+
+ if (!UUID.TryParse(id, out objectID))
+ objectID = UUID.Zero;
+
+ if (objectID == UUID.Zero && name == "")
+ return;
+
+ m_host.CollisionFilter.Add(accept,objectID.ToString() + name);
+ }
+
+ public void llTakeControls(int controls, int accept, int pass_on)
+ {
+ if (m_item.PermsGranter != UUID.Zero)
+ {
+ ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
+
+ if (presence != null)
+ {
+ if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
+ {
+ presence.RegisterControlEventsToScript(controls, accept, pass_on, m_host.LocalId, m_item.ItemID);
+ }
+ }
+ }
+
+ m_host.AddScriptLPS(1);
+ }
+
+ public void llReleaseControls()
+ {
+ m_host.AddScriptLPS(1);
+
+ if (m_item.PermsGranter != UUID.Zero)
+ {
+ ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
+
+ if (presence != null)
+ {
+ if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
+ {
+ // Unregister controls from Presence
+ presence.UnRegisterControlEventsToScript(m_host.LocalId, m_item.ItemID);
+ // Remove Take Control permission.
+ m_item.PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
+ }
+ }
+ }
+ }
+
+ public void llReleaseURL(string url)
+ {
+ m_host.AddScriptLPS(1);
+ if (m_UrlModule != null)
+ m_UrlModule.ReleaseURL(url);
+ }
+
+ ///
+ /// Attach the object containing this script to the avatar that owns it.
+ ///
+ ///
+ /// The attachment point (e.g. ATTACH_CHEST)
+ ///
+ /// true if the attach suceeded, false if it did not
+ public bool AttachToAvatar(int attachmentPoint)
+ {
+ SceneObjectGroup grp = m_host.ParentGroup;
+ ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
+
+ IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
+
+ if (attachmentsModule != null)
+ return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, true);
+ else
+ return false;
+ }
+
+ ///
+ /// Detach the object containing this script from the avatar it is attached to.
+ ///
+ ///
+ /// Nothing happens if the object is not attached.
+ ///
+ public void DetachFromAvatar()
+ {
+ Util.FireAndForget(DetachWrapper, m_host, "LSL_Api.DetachFromAvatar");
+ }
+
+ private void DetachWrapper(object o)
+ {
+ if (World.AttachmentsModule != null)
+ {
+ SceneObjectPart host = (SceneObjectPart)o;
+ ScenePresence presence = World.GetScenePresence(host.OwnerID);
+ World.AttachmentsModule.DetachSingleAttachmentToInv(presence, host.ParentGroup);
+ }
+ }
+
+ public void llAttachToAvatar(int attachmentPoint)
+ {
+ m_host.AddScriptLPS(1);
+
+// if (m_host.ParentGroup.RootPart.AttachmentPoint == 0)
+// return;
+
+ if (m_item.PermsGranter != m_host.OwnerID)
+ return;
+
+ if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
+ AttachToAvatar(attachmentPoint);
+ }
+
+ public void llDetachFromAvatar()
+ {
+ m_host.AddScriptLPS(1);
+
+ if (m_host.ParentGroup.AttachmentPoint == 0)
+ return;
+
+ if (m_item.PermsGranter != m_host.OwnerID)
+ return;
+
+ if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
+ DetachFromAvatar();
+ }
+
+ public void llTakeCamera(string avatar)
+ {
+ m_host.AddScriptLPS(1);
+ Deprecated("llTakeCamera", "Use llSetCameraParams instead");
+ }
+
+ public void llReleaseCamera(string avatar)
+ {
+ m_host.AddScriptLPS(1);
+ Deprecated("llReleaseCamera", "Use llClearCameraParams instead");
+ }
+
+ public LSL_String llGetOwner()
+ {
+ m_host.AddScriptLPS(1);
+
+ return m_host.OwnerID.ToString();
+ }
+
+ public void llInstantMessage(string user, string message)
+ {
+ m_host.AddScriptLPS(1);
+
+ // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
+ // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
+ // but I don't think we have a list of scenes available from here.
+ // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
+
+ // user is a UUID
+
+ // TODO: figure out values for client, fromSession, and imSessionID
+ // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
+
+ GridInstantMessage msg = new GridInstantMessage();
msg.fromAgentID = new Guid(m_host.OwnerID.ToString()); // fromAgentID.Guid;
- msg.toAgentID = new Guid(user); // toAgentID.Guid;
- msg.imSessionID = new Guid(m_host.UUID.ToString()); // This is the item we're mucking with here
-// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
-// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
- msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp;
- //if (client != null)
- //{
- msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
- //}
- //else
- //{
- // msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it
- //}
- // Cap the message length at 1024.
- if (message != null && message.Length > 1024)
- msg.message = message.Substring(0, 1024);
- else
- msg.message = message;
- msg.dialog = (byte)19; // messgage from script ??? // dialog;
- msg.fromGroup = false;// fromGroup;
- msg.offline = (byte)0; //offline;
- msg.ParentEstateID = 0; //ParentEstateID;
- msg.Position = new Vector3(m_host.AbsolutePosition);
- msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
-
- Vector3 pos = m_host.AbsolutePosition;
- msg.binaryBucket
- = Util.StringToBytes256(
- "{0}/{1}/{2}/{3}",
- World.RegionInfo.RegionName,
- (int)Math.Floor(pos.X),
- (int)Math.Floor(pos.Y),
- (int)Math.Floor(pos.Z));
-
- if (m_TransferModule != null)
- {
- m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
- }
-
- ScriptSleep(m_sleepMsOnInstantMessage);
- }
-
- public void llEmail(string address, string subject, string message)
- {
- m_host.AddScriptLPS(1);
- IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface();
- if (emailModule == null)
- {
- Error("llEmail", "Email module not configured");
- return;
- }
-
- //Restrict email destination to the avatars registered email address?
- //The restriction only applies if the destination address is not local.
- if (m_restrictEmail == true && address.Contains(m_internalObjectHost) == false)
- {
- UserAccount account =
- World.UserAccountService.GetUserAccount(
- World.RegionInfo.ScopeID,
- m_host.OwnerID);
-
- if (account == null)
- {
- Error("llEmail", "Can't find user account for '" + m_host.OwnerID.ToString() + "'");
- return;
- }
-
- if (String.IsNullOrEmpty(account.Email))
- {
- Error("llEmail", "User account has not registered an email address.");
- return;
- }
-
- address = account.Email;
- }
-
- emailModule.SendEmail(m_host.UUID, address, subject, message);
- ScriptSleep(m_sleepMsOnEmail);
- }
-
- public void llGetNextEmail(string address, string subject)
- {
- m_host.AddScriptLPS(1);
- IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface();
- if (emailModule == null)
- {
- Error("llGetNextEmail", "Email module not configured");
- return;
- }
- Email email;
-
- email = emailModule.GetNextEmail(m_host.UUID, address, subject);
-
- if (email == null)
- return;
-
- m_ScriptEngine.PostObjectEvent(m_host.LocalId,
- new EventParams("email",
- new Object[] {
- new LSL_String(email.time),
- new LSL_String(email.sender),
- new LSL_String(email.subject),
- new LSL_String(email.message),
- new LSL_Integer(email.numLeft)},
- new DetectParams[0]));
-
- }
-
- public LSL_String llGetKey()
- {
- m_host.AddScriptLPS(1);
- return m_host.UUID.ToString();
- }
-
- public LSL_Key llGenerateKey()
- {
- m_host.AddScriptLPS(1);
- return UUID.Random().ToString();
- }
-
- public void llSetBuoyancy(double buoyancy)
- {
- m_host.AddScriptLPS(1);
-
- if (!m_host.ParentGroup.IsDeleted)
- {
- m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
- }
- }
-
- ///
- /// Attempt to clamp the object on the Z axis at the given height over tau seconds.
- ///
- /// Height to hover. Height of zero disables hover.
- /// False if height is calculated just from ground, otherwise uses ground or water depending on whichever is higher
- /// Number of seconds over which to reach target
- public void llSetHoverHeight(double height, int water, double tau)
- {
- m_host.AddScriptLPS(1);
-
- if (m_host.PhysActor != null)
- {
- PIDHoverType hoverType = PIDHoverType.Ground;
- if (water != 0)
- {
- hoverType = PIDHoverType.GroundAndWater;
- }
-
- m_host.SetHoverHeight((float)height, hoverType, (float)tau);
- }
- }
-
- public void llStopHover()
- {
- m_host.AddScriptLPS(1);
- if (m_host.PhysActor != null)
- {
- m_host.SetHoverHeight(0f, PIDHoverType.Ground, 0f);
- }
- }
-
- public void llMinEventDelay(double delay)
- {
- m_host.AddScriptLPS(1);
- try
- {
- m_ScriptEngine.SetMinEventDelay(m_item.ItemID, delay);
- }
- catch (NotImplementedException)
- {
- // Currently not implemented in DotNetEngine only XEngine
- NotImplemented("llMinEventDelay", "In DotNetEngine");
- }
- }
-
- public void llSoundPreload(string sound)
- {
- m_host.AddScriptLPS(1);
- Deprecated("llSoundPreload", "Use llPreloadSound instead");
- }
-
- public void llRotLookAt(LSL_Rotation target, double strength, double damping)
- {
- m_host.AddScriptLPS(1);
-
- // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
- // set the rotation of the object, copy that behavior
- PhysicsActor pa = m_host.PhysActor;
-
- if (strength == 0 || pa == null || !pa.IsPhysical)
- {
- llSetLocalRot(target);
- }
- else
- {
- m_host.RotLookAt(target, (float)strength, (float)damping);
- }
- }
-
- public LSL_Integer llStringLength(string str)
- {
- m_host.AddScriptLPS(1);
- if (str.Length > 0)
- {
- return str.Length;
- }
- else
- {
- return 0;
- }
- }
-
- public void llStartAnimation(string anim)
- {
- m_host.AddScriptLPS(1);
-
- if (m_item.PermsGranter == UUID.Zero)
- return;
-
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
- {
- ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
-
- if (presence != null)
- {
- // Do NOT try to parse UUID, animations cannot be triggered by ID
- UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation);
- if (animID == UUID.Zero)
- presence.Animator.AddAnimation(anim, m_host.UUID);
- else
- presence.Animator.AddAnimation(animID, m_host.UUID);
- }
- }
- }
-
- public void llStopAnimation(string anim)
- {
- m_host.AddScriptLPS(1);
-
- if (m_item.PermsGranter == UUID.Zero)
- return;
-
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
- {
- ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
-
- if (presence != null)
- {
- UUID animID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, anim);
-
- if (animID == UUID.Zero)
- presence.Animator.RemoveAnimation(anim);
- else
- presence.Animator.RemoveAnimation(animID, true);
- }
- }
- }
-
- public void llPointAt(LSL_Vector pos)
- {
- m_host.AddScriptLPS(1);
- }
-
- public void llStopPointAt()
- {
- m_host.AddScriptLPS(1);
- }
-
- public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
- {
- m_host.AddScriptLPS(1);
- TargetOmega(m_host, axis, spinrate, gain);
- }
-
- protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain)
- {
- PhysicsActor pa = part.PhysActor;
- if ( ( pa == null || !pa.IsPhysical ) && gain == 0.0d )
- spinrate = 0.0d;
- part.UpdateAngularVelocity(axis * spinrate);
- }
-
- public LSL_Integer llGetStartParameter()
- {
- m_host.AddScriptLPS(1);
- return m_ScriptEngine.GetStartParameter(m_item.ItemID);
- }
-
- public void llRequestPermissions(string agent, int perm)
- {
- UUID agentID;
-
- if (!UUID.TryParse(agent, out agentID))
- return;
-
- if (agentID == UUID.Zero || perm == 0) // Releasing permissions
- {
- llReleaseControls();
-
- m_item.PermsGranter = UUID.Zero;
- m_item.PermsMask = 0;
-
- m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
- "run_time_permissions", new Object[] {
- new LSL_Integer(0) },
- new DetectParams[0]));
-
- return;
- }
-
- if (m_item.PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
- llReleaseControls();
-
- m_host.AddScriptLPS(1);
-
- int implicitPerms = 0;
-
- if (m_host.ParentGroup.IsAttachment && (UUID)agent == m_host.ParentGroup.AttachedAvatar)
- {
- // When attached, certain permissions are implicit if requested from owner
- implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
- ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
- ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
- ScriptBaseClass.PERMISSION_TRACK_CAMERA |
- ScriptBaseClass.PERMISSION_ATTACH;
- }
- else
- {
- if (m_host.ParentGroup.GetSittingAvatars().SingleOrDefault(sp => sp.UUID == agentID) != null)
- {
- // When agent is sitting, certain permissions are implicit if requested from sitting agent
- implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
- ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
- ScriptBaseClass.PERMISSION_TRACK_CAMERA |
- ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
- }
- else
- {
- if (World.GetExtraSetting("auto_grant_attach_perms") == "true")
- implicitPerms = ScriptBaseClass.PERMISSION_ATTACH;
- }
- }
-
- if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
- {
- lock (m_host.TaskInventory)
- {
- m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
- m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
- }
-
- m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
- "run_time_permissions", new Object[] {
- new LSL_Integer(perm) },
- new DetectParams[0]));
-
- return;
- }
-
- ScenePresence presence = World.GetScenePresence(agentID);
-
- if (presence != null)
- {
- // If permissions are being requested from an NPC and were not implicitly granted above then
- // auto grant all requested permissions if the script is owned by the NPC or the NPCs owner
- INPCModule npcModule = World.RequestModuleInterface();
- if (npcModule != null && npcModule.IsNPC(agentID, World))
- {
- if (npcModule.CheckPermissions(agentID, m_host.OwnerID))
- {
- lock (m_host.TaskInventory)
- {
- m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
- m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
- }
-
- m_ScriptEngine.PostScriptEvent(
- m_item.ItemID,
- new EventParams(
- "run_time_permissions", new Object[] { new LSL_Integer(perm) }, new DetectParams[0]));
- }
-
- // it is an NPC, exit even if the permissions werent granted above, they are not going to answer
- // the question!
- return;
- }
-
- string ownerName = resolveName(m_host.ParentGroup.RootPart.OwnerID);
- if (ownerName == String.Empty)
- ownerName = "(hippos)";
-
- if (!m_waitingForScriptAnswer)
- {
- lock (m_host.TaskInventory)
- {
- m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
- m_host.TaskInventory[m_item.ItemID].PermsMask = 0;
- }
-
- presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
- m_waitingForScriptAnswer=true;
- }
-
- presence.ControllingClient.SendScriptQuestion(
- m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, m_item.ItemID, perm);
-
- return;
- }
-
- // Requested agent is not in range, refuse perms
- m_ScriptEngine.PostScriptEvent(
- m_item.ItemID,
- new EventParams("run_time_permissions", new Object[] { new LSL_Integer(0) }, new DetectParams[0]));
- }
-
- void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer)
- {
- if (taskID != m_host.UUID)
- return;
-
- client.OnScriptAnswer -= handleScriptAnswer;
- m_waitingForScriptAnswer = false;
-
- if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
- llReleaseControls();
-
- lock (m_host.TaskInventory)
- {
- m_host.TaskInventory[m_item.ItemID].PermsMask = answer;
- }
-
- m_ScriptEngine.PostScriptEvent(
- m_item.ItemID,
- new EventParams("run_time_permissions", new Object[] { new LSL_Integer(answer) }, new DetectParams[0]));
- }
-
- public LSL_String llGetPermissionsKey()
- {
- m_host.AddScriptLPS(1);
-
- return m_item.PermsGranter.ToString();
- }
-
- public LSL_Integer llGetPermissions()
- {
- m_host.AddScriptLPS(1);
-
- int perms = m_item.PermsMask;
-
- if (m_automaticLinkPermission)
- perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
-
- return perms;
- }
-
- public LSL_Integer llGetLinkNumber()
- {
- m_host.AddScriptLPS(1);
-
- if (m_host.ParentGroup.PrimCount > 1)
- {
- return m_host.LinkNum;
- }
- else
- {
- return 0;
- }
- }
-
- public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
- {
- List parts = GetLinkParts(linknumber);
-
- foreach (SceneObjectPart part in parts)
- part.SetFaceColorAlpha(face, color, null);
- }
-
- public void llCreateLink(string target, int parent)
- {
- m_host.AddScriptLPS(1);
-
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
- && !m_automaticLinkPermission)
- {
- Error("llCreateLink", "PERMISSION_CHANGE_LINKS permission not set");
- return;
- }
-
- CreateLink(target, parent);
- }
-
- public void CreateLink(string target, int parent)
- {
- UUID targetID;
-
- if (!UUID.TryParse(target, out targetID))
- return;
-
- SceneObjectPart targetPart = World.GetSceneObjectPart((UUID)targetID);
-
- if (targetPart.ParentGroup.AttachmentPoint != 0)
- return; // Fail silently if attached
-
- if (targetPart.ParentGroup.RootPart.OwnerID != m_host.ParentGroup.RootPart.OwnerID)
- return;
-
- SceneObjectGroup parentPrim = null, childPrim = null;
-
- if (targetPart != null)
- {
- if (parent != 0)
- {
- parentPrim = m_host.ParentGroup;
- childPrim = targetPart.ParentGroup;
- }
- else
- {
- parentPrim = targetPart.ParentGroup;
- childPrim = m_host.ParentGroup;
- }
-
- // Required for linking
- childPrim.RootPart.ClearUpdateSchedule();
- parentPrim.LinkToGroup(childPrim, true);
- }
-
- parentPrim.TriggerScriptChangedEvent(Changed.LINK);
- parentPrim.RootPart.CreateSelected = true;
- parentPrim.HasGroupChanged = true;
- parentPrim.ScheduleGroupForFullUpdate();
-
- IClientAPI client = null;
- ScenePresence sp = World.GetScenePresence(m_host.OwnerID);
- if (sp != null)
- client = sp.ControllingClient;
-
- if (client != null)
- parentPrim.SendPropertiesToClient(client);
-
- ScriptSleep(m_sleepMsOnCreateLink);
- }
-
- public void llBreakLink(int linknum)
- {
- m_host.AddScriptLPS(1);
-
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
- && !m_automaticLinkPermission)
- {
- Error("llBreakLink", "PERMISSION_CHANGE_LINKS permission not set");
- return;
- }
-
- BreakLink(linknum);
- }
-
- public void BreakLink(int linknum)
- {
- if (linknum < ScriptBaseClass.LINK_THIS)
- return;
-
- SceneObjectGroup parentPrim = m_host.ParentGroup;
-
- if (parentPrim.AttachmentPoint != 0)
- return; // Fail silently if attached
- SceneObjectPart childPrim = null;
-
- switch (linknum)
- {
- case ScriptBaseClass.LINK_ROOT:
- break;
- case ScriptBaseClass.LINK_SET:
- case ScriptBaseClass.LINK_ALL_OTHERS:
- case ScriptBaseClass.LINK_ALL_CHILDREN:
- case ScriptBaseClass.LINK_THIS:
- foreach (SceneObjectPart part in parentPrim.Parts)
- {
- if (part.UUID != m_host.UUID)
- {
- childPrim = part;
- break;
- }
- }
- break;
- default:
- childPrim = parentPrim.GetLinkNumPart(linknum);
- if (childPrim.UUID == m_host.UUID)
- childPrim = null;
- break;
- }
-
- if (linknum == ScriptBaseClass.LINK_ROOT)
- {
- // Restructuring Multiple Prims.
- List parts = new List(parentPrim.Parts);
- parts.Remove(parentPrim.RootPart);
- foreach (SceneObjectPart part in parts)
- {
- parentPrim.DelinkFromGroup(part.LocalId, true);
- }
- parentPrim.HasGroupChanged = true;
- parentPrim.ScheduleGroupForFullUpdate();
- parentPrim.TriggerScriptChangedEvent(Changed.LINK);
-
- if (parts.Count > 0)
- {
- SceneObjectPart newRoot = parts[0];
- parts.Remove(newRoot);
- foreach (SceneObjectPart part in parts)
- {
- // Required for linking
- part.ClearUpdateSchedule();
- newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
- }
- newRoot.ParentGroup.HasGroupChanged = true;
- newRoot.ParentGroup.ScheduleGroupForFullUpdate();
- }
- }
- else
- {
- if (childPrim == null)
- return;
-
- parentPrim.DelinkFromGroup(childPrim.LocalId, true);
- parentPrim.HasGroupChanged = true;
- parentPrim.ScheduleGroupForFullUpdate();
- parentPrim.TriggerScriptChangedEvent(Changed.LINK);
- }
- }
-
- public void llBreakAllLinks()
- {
- m_host.AddScriptLPS(1);
-
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
- && !m_automaticLinkPermission)
- {
- Error("llBreakAllLinks", "PERMISSION_CHANGE_LINKS permission not set");
- return;
- }
-
- BreakAllLinks();
- }
-
- public void BreakAllLinks()
- {
- SceneObjectGroup parentPrim = m_host.ParentGroup;
- if (parentPrim.AttachmentPoint != 0)
- return; // Fail silently if attached
-
- List parts = new List(parentPrim.Parts);
- parts.Remove(parentPrim.RootPart);
-
- foreach (SceneObjectPart part in parts)
- {
- parentPrim.DelinkFromGroup(part.LocalId, true);
- parentPrim.TriggerScriptChangedEvent(Changed.LINK);
- }
- parentPrim.HasGroupChanged = true;
- parentPrim.ScheduleGroupForFullUpdate();
- }
-
- public LSL_String llGetLinkKey(int linknum)
- {
- m_host.AddScriptLPS(1);
-
- ISceneEntity entity = GetLinkEntity(m_host, linknum);
-
- if (entity != null)
- return entity.UUID.ToString();
- else
- return ScriptBaseClass.NULL_KEY;
- }
-
- ///
- /// Returns the name of the child prim or seated avatar matching the
- /// specified link number.
- ///
- ///
- /// The number of a link in the linkset or a link-related constant.
- ///
- ///
- /// The name determined to match the specified link number.
- ///
- ///
- /// The rules governing the returned name are not simple. The only
- /// time a blank name is returned is if the target prim has a blank
- /// name. If no prim with the given link number can be found then
- /// usually NULL_KEY is returned but there are exceptions.
- ///
- /// In a single unlinked prim, A call with 0 returns the name, all
- /// other values for link number return NULL_KEY
- ///
- /// In link sets it is more complicated.
- ///
- /// If the script is in the root prim:-
- /// A zero link number returns NULL_KEY.
- /// Positive link numbers return the name of the prim, or NULL_KEY
- /// if a prim does not exist at that position.
- /// Negative link numbers return the name of the first child prim.
- ///
- /// If the script is in a child prim:-
- /// Link numbers 0 or 1 return the name of the root prim.
- /// Positive link numbers return the name of the prim or NULL_KEY
- /// if a prim does not exist at that position.
- /// Negative numbers return the name of the root prim.
- ///
- /// References
- /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetLinkName
- /// Mentions NULL_KEY being returned
- /// http://wiki.secondlife.com/wiki/LlGetLinkName
- /// Mentions using the LINK_* constants, some of which are negative
- ///
- public LSL_String llGetLinkName(int linknum)
- {
- m_host.AddScriptLPS(1);
-
- ISceneEntity entity = GetLinkEntity(m_host, linknum);
-
- if (entity != null)
- return entity.Name;
- else
- return ScriptBaseClass.NULL_KEY;
- }
-
- public LSL_Integer llGetInventoryNumber(int type)
- {
- m_host.AddScriptLPS(1);
- int count = 0;
-
- lock (m_host.TaskInventory)
- {
- foreach (KeyValuePair inv in m_host.TaskInventory)
- {
- if (inv.Value.Type == type || type == -1)
- {
- count = count + 1;
- }
- }
- }
-
- return count;
- }
-
- public LSL_String llGetInventoryName(int type, int number)
- {
- m_host.AddScriptLPS(1);
- ArrayList keys = new ArrayList();
-
- lock (m_host.TaskInventory)
- {
- foreach (KeyValuePair inv in m_host.TaskInventory)
- {
- if (inv.Value.Type == type || type == -1)
- {
- keys.Add(inv.Value.Name);
- }
- }
- }
-
- if (keys.Count == 0)
- {
- return String.Empty;
- }
- keys.Sort();
- if (keys.Count > number)
- {
- return (string)keys[number];
- }
- return String.Empty;
- }
-
- public LSL_Float llGetEnergy()
- {
- m_host.AddScriptLPS(1);
- // TODO: figure out real energy value
- return 1.0f;
- }
-
- public void llGiveInventory(string destination, string inventory)
- {
- m_host.AddScriptLPS(1);
-
- UUID destId = UUID.Zero;
-
- if (!UUID.TryParse(destination, out destId))
- {
- Error("llGiveInventory", "Can't parse destination key '" + destination + "'");
- return;
- }
-
- TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
-
- if (item == null)
- {
- Error("llGiveInventory", "Can't find inventory object '" + inventory + "'");
- return;
- }
-
- UUID objId = item.ItemID;
-
- // check if destination is an object
- if (World.GetSceneObjectPart(destId) != null)
- {
- // destination is an object
- World.MoveTaskInventoryItem(destId, m_host, objId);
- }
- else
- {
- ScenePresence presence = World.GetScenePresence(destId);
-
- if (presence == null)
- {
- UserAccount account =
- World.UserAccountService.GetUserAccount(
- World.RegionInfo.ScopeID,
- destId);
-
- if (account == null)
- {
- GridUserInfo info = World.GridUserService.GetGridUserInfo(destId.ToString());
- if(info == null || info.Online == false)
- {
- Error("llGiveInventory", "Can't find destination '" + destId.ToString() + "'");
- return;
- }
- }
- }
- // destination is an avatar
- string message;
- InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId, out message);
-
- if (agentItem == null)
- {
- llSay(0, message);
- return;
- }
-
- if (m_TransferModule != null)
- {
- byte[] bucket = new byte[1];
- bucket[0] = (byte)item.Type;
-
- GridInstantMessage msg = new GridInstantMessage(World,
- m_host.OwnerID, m_host.Name, destId,
- (byte)InstantMessageDialog.TaskInventoryOffered,
- false, item.Name+". "+m_host.Name+" is located at "+
- World.RegionInfo.RegionName+" "+
- m_host.AbsolutePosition.ToString(),
- agentItem.ID, true, m_host.AbsolutePosition,
- bucket, true);
-
- m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
- }
-
- ScriptSleep(m_sleepMsOnGiveInventory);
- }
- }
-
- public void llRemoveInventory(string name)
- {
- m_host.AddScriptLPS(1);
-
- TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
-
- if (item == null)
- return;
-
- if (item.ItemID == m_item.ItemID)
- throw new ScriptDeleteException();
- else
- m_host.Inventory.RemoveInventoryItem(item.ItemID);
- }
-
- public void llSetText(string text, LSL_Vector color, double alpha)
- {
- m_host.AddScriptLPS(1);
- Vector3 av3 = Util.Clip(color, 0.0f, 1.0f);
- if (text.Length > 254)
- text = text.Remove(254);
-
- byte[] data;
- do
- {
- data = Util.UTF8.GetBytes(text);
- if (data.Length > 254)
- text = text.Substring(0, text.Length - 1);
- } while (data.Length > 254);
-
- m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f));
- //m_host.ParentGroup.HasGroupChanged = true;
- //m_host.ParentGroup.ScheduleGroupForFullUpdate();
- }
-
- public LSL_Float llWater(LSL_Vector offset)
- {
- m_host.AddScriptLPS(1);
- return World.RegionInfo.RegionSettings.WaterHeight;
- }
-
- public void llPassTouches(int pass)
- {
- m_host.AddScriptLPS(1);
- if (pass != 0)
- m_host.PassTouches = true;
- else
- m_host.PassTouches = false;
- }
-
- public LSL_String llRequestAgentData(string id, int data)
- {
- m_host.AddScriptLPS(1);
-
- UUID uuid = (UUID)id;
- PresenceInfo pinfo = null;
- UserAccount account;
-
- UserInfoCacheEntry ce;
-
- lock (m_userInfoCache)
- {
- if (!m_userInfoCache.TryGetValue(uuid, out ce))
- {
- account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid);
- if (account == null)
- {
- m_userInfoCache[uuid] = null; // Cache negative
- return UUID.Zero.ToString();
- }
-
- PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
- if (pinfos != null && pinfos.Length > 0)
- {
- foreach (PresenceInfo p in pinfos)
- {
- if (p.RegionID != UUID.Zero)
- {
- pinfo = p;
- }
- }
- }
-
- ce = new UserInfoCacheEntry();
- ce.time = Util.EnvironmentTickCount();
- ce.account = account;
- ce.pinfo = pinfo;
-
- m_userInfoCache[uuid] = ce;
- }
- else
- {
- if (ce == null)
- return UUID.Zero.ToString();
-
- account = ce.account;
-
- if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time)
- >= LlRequestAgentDataCacheTimeoutMs)
- {
- PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
- if (pinfos != null && pinfos.Length > 0)
- {
- foreach (PresenceInfo p in pinfos)
- {
- if (p.RegionID != UUID.Zero)
- {
- pinfo = p;
- }
- }
- }
- else
- {
- pinfo = null;
- }
-
- ce.time = Util.EnvironmentTickCount();
- ce.pinfo = pinfo;
- }
- else
- {
- pinfo = ce.pinfo;
- }
- }
- }
-
- string reply = String.Empty;
-
- switch (data)
- {
- case ScriptBaseClass.DATA_ONLINE:
- if (pinfo != null && pinfo.RegionID != UUID.Zero)
- reply = "1";
- else
- reply = "0";
- break;
- case ScriptBaseClass.DATA_NAME: // (First Last)
- reply = account.FirstName + " " + account.LastName;
- break;
- case ScriptBaseClass.DATA_BORN: // (YYYY-MM-DD)
- DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
- born = born.AddSeconds(account.Created);
- reply = born.ToString("yyyy-MM-dd");
- break;
- case ScriptBaseClass.DATA_RATING: // (0,0,0,0,0,0)
- reply = "0,0,0,0,0,0";
- break;
- case 7: // DATA_USERLEVEL (integer). This is not available in LL and so has no constant.
- reply = account.UserLevel.ToString();
- break;
- case ScriptBaseClass.DATA_PAYINFO: // (0|1|2|3)
- reply = "0";
- break;
- default:
- return UUID.Zero.ToString(); // Raise no event
- }
-
- UUID rq = UUID.Random();
-
- UUID tid = AsyncCommands.
- DataserverPlugin.RegisterRequest(m_host.LocalId,
- m_item.ItemID, rq.ToString());
-
- AsyncCommands.
- DataserverPlugin.DataserverReply(rq.ToString(), reply);
-
- ScriptSleep(m_sleepMsOnRequestAgentData);
- return tid.ToString();
- }
-
- public LSL_String llRequestInventoryData(string name)
- {
- m_host.AddScriptLPS(1);
-
- foreach (TaskInventoryItem item in m_host.Inventory.GetInventoryItems())
- {
- if (item.Type == 3 && item.Name == name)
- {
- UUID tid = AsyncCommands.
- DataserverPlugin.RegisterRequest(m_host.LocalId,
- m_item.ItemID, item.AssetID.ToString());
-
- Vector3 region = new Vector3(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
-
- World.AssetService.Get(item.AssetID.ToString(), this,
- delegate(string i, object sender, AssetBase a)
- {
- AssetLandmark lm = new AssetLandmark(a);
-
- float rx = (uint)(lm.RegionHandle >> 32);
- float ry = (uint)lm.RegionHandle;
- region = lm.Position + new Vector3(rx, ry, 0) - region;
-
- string reply = region.ToString();
- AsyncCommands.
- DataserverPlugin.DataserverReply(i.ToString(),
- reply);
- });
-
- ScriptSleep(m_sleepMsOnRequestInventoryData);
- return tid.ToString();
- }
- }
-
- ScriptSleep(m_sleepMsOnRequestInventoryData);
- return String.Empty;
- }
-
- public void llSetDamage(double damage)
- {
- m_host.AddScriptLPS(1);
- m_host.ParentGroup.Damage = (float)damage;
- }
-
- public void llTeleportAgentHome(string agent)
- {
- m_host.AddScriptLPS(1);
- UUID agentId = new UUID();
- if (UUID.TryParse(agent, out agentId))
- {
- ScenePresence presence = World.GetScenePresence(agentId);
- if (presence != null)
- {
- // agent must be over the owners land
- if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
- {
- World.TeleportClientHome(agentId, presence.ControllingClient);
- }
- }
- }
-
- ScriptSleep(m_sleepMsOnSetDamage);
- }
-
- public void llTeleportAgent(string agent, string destination, LSL_Vector targetPos, LSL_Vector targetLookAt)
- {
- m_host.AddScriptLPS(1);
- UUID agentId = new UUID();
-
- if (UUID.TryParse(agent, out agentId))
- {
- ScenePresence presence = World.GetScenePresence(agentId);
- if (presence != null && presence.PresenceType != PresenceType.Npc)
- {
- // agent must not be a god
- if (presence.GodLevel >= 200) return;
-
- if (destination == String.Empty)
- destination = World.RegionInfo.RegionName;
-
- // agent must be over the owners land
- if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
- {
- DoLLTeleport(presence, destination, targetPos, targetLookAt);
- }
- else // or must be wearing the prim
- {
- if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
- {
- DoLLTeleport(presence, destination, targetPos, targetLookAt);
- }
- }
- }
- }
- }
-
- public void llTeleportAgentGlobalCoords(string agent, LSL_Vector global_coords, LSL_Vector targetPos, LSL_Vector targetLookAt)
- {
- m_host.AddScriptLPS(1);
- UUID agentId = new UUID();
-
- ulong regionHandle = Util.RegionWorldLocToHandle((uint)global_coords.x, (uint)global_coords.y);
-
- if (UUID.TryParse(agent, out agentId))
- {
- ScenePresence presence = World.GetScenePresence(agentId);
- if (presence != null && presence.PresenceType != PresenceType.Npc)
- {
- // agent must not be a god
- if (presence.GodLevel >= 200) return;
-
- // agent must be over the owners land
- if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
- {
- World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
- }
- else // or must be wearing the prim
- {
- if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
- {
- World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
- }
- }
- }
- }
- }
-
- private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt)
- {
- UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, destination);
-
- // The destinaion is not an asset ID and also doesn't name a landmark.
- // Use it as a sim name
- if (assetID == UUID.Zero)
- {
- World.RequestTeleportLocation(sp.ControllingClient, destination, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
- return;
- }
-
- AssetBase lma = World.AssetService.Get(assetID.ToString());
- if (lma == null)
- return;
-
- if (lma.Type != (sbyte)AssetType.Landmark)
- return;
-
- AssetLandmark lm = new AssetLandmark(lma);
-
- World.RequestTeleportLocation(sp.ControllingClient, lm.RegionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
- }
-
- public void llTextBox(string agent, string message, int chatChannel)
- {
- IDialogModule dm = World.RequestModuleInterface();
-
- if (dm == null)
- return;
-
- m_host.AddScriptLPS(1);
- UUID av = new UUID();
- if (!UUID.TryParse(agent,out av))
- {
- Error("llTextBox", "First parameter must be a key");
- return;
- }
-
- if (message == string.Empty)
- {
- Error("llTextBox", "Empty message");
- }
- else if (message.Length > 512)
- {
- Error("llTextBox", "Message more than 512 characters");
- }
- else
- {
- dm.SendTextBoxToUser(av, message, chatChannel, m_host.Name, m_host.UUID, m_host.OwnerID);
- ScriptSleep(m_sleepMsOnTextBox);
- }
- }
-
- public void llModifyLand(int action, int brush)
- {
- m_host.AddScriptLPS(1);
- ITerrainModule tm = m_ScriptEngine.World.RequestModuleInterface();
- if (tm != null)
- {
- tm.ModifyTerrain(m_host.OwnerID, m_host.AbsolutePosition, (byte) brush, (byte) action, m_host.OwnerID);
- }
- }
-
- public void llCollisionSound(string impact_sound, double impact_volume)
- {
- m_host.AddScriptLPS(1);
-
- // TODO: Parameter check logic required.
- m_host.CollisionSound = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound);
- m_host.CollisionSoundVolume = (float)impact_volume;
- }
-
- public LSL_String llGetAnimation(string id)
- {
- // This should only return a value if the avatar is in the same region
- m_host.AddScriptLPS(1);
- UUID avatar = (UUID)id;
- ScenePresence presence = World.GetScenePresence(avatar);
- if (presence == null)
- return "";
-
- if (m_host.RegionHandle == presence.RegionHandle)
- {
- Dictionary animationstateNames = DefaultAvatarAnimations.AnimStateNames;
-
- if (presence != null)
- {
- AnimationSet currentAnims = presence.Animator.Animations;
- string currentAnimationState = String.Empty;
- if (animationstateNames.TryGetValue(currentAnims.ImplicitDefaultAnimation.AnimID, out currentAnimationState))
- return currentAnimationState;
- }
- }
-
- return String.Empty;
- }
-
- public void llMessageLinked(int linknumber, int num, string msg, string id)
- {
- m_host.AddScriptLPS(1);
-
- List parts = GetLinkParts(linknumber);
-
- UUID partItemID;
- foreach (SceneObjectPart part in parts)
- {
- foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems())
- {
- if (item.Type == ScriptBaseClass.INVENTORY_SCRIPT)
- {
- partItemID = item.ItemID;
- int linkNumber = m_host.LinkNum;
- if (m_host.ParentGroup.PrimCount == 1)
- linkNumber = 0;
-
- object[] resobj = new object[]
- {
- new LSL_Integer(linkNumber), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
- };
-
- m_ScriptEngine.PostScriptEvent(partItemID,
- new EventParams("link_message",
- resobj, new DetectParams[0]));
- }
- }
- }
- }
-
- public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
- {
- m_host.AddScriptLPS(1);
- bool pushrestricted = World.RegionInfo.RegionSettings.RestrictPushing;
- bool pushAllowed = false;
-
- bool pusheeIsAvatar = false;
- UUID targetID = UUID.Zero;
-
- if (!UUID.TryParse(target,out targetID))
- return;
-
- ScenePresence pusheeav = null;
- Vector3 PusheePos = Vector3.Zero;
- SceneObjectPart pusheeob = null;
-
- ScenePresence avatar = World.GetScenePresence(targetID);
- if (avatar != null)
- {
- pusheeIsAvatar = true;
-
- // Pushee doesn't have a physics actor
- if (avatar.PhysicsActor == null)
- return;
-
- // Pushee is in GodMode this pushing object isn't owned by them
- if (avatar.GodLevel > 0 && m_host.OwnerID != targetID)
- return;
-
- pusheeav = avatar;
-
- // Find pushee position
- // Pushee Linked?
- SceneObjectPart sitPart = pusheeav.ParentPart;
- if (sitPart != null)
- PusheePos = sitPart.AbsolutePosition;
- else
- PusheePos = pusheeav.AbsolutePosition;
- }
-
- if (!pusheeIsAvatar)
- {
- // not an avatar so push is not affected by parcel flags
- pusheeob = World.GetSceneObjectPart((UUID)target);
-
- // We can't find object
- if (pusheeob == null)
- return;
-
- // Object not pushable. Not an attachment and has no physics component
- if (!pusheeob.ParentGroup.IsAttachment && pusheeob.PhysActor == null)
- return;
-
- PusheePos = pusheeob.AbsolutePosition;
- pushAllowed = true;
- }
- else
- {
- if (pushrestricted)
- {
- ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
-
- // We didn't find the parcel but region is push restricted so assume it is NOT ok
- if (targetlandObj == null)
- return;
-
- // Need provisions for Group Owned here
- if (m_host.OwnerID == targetlandObj.LandData.OwnerID ||
- targetlandObj.LandData.IsGroupOwned || m_host.OwnerID == targetID)
- {
- pushAllowed = true;
- }
- }
- else
- {
- ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
- if (targetlandObj == null)
- {
- // We didn't find the parcel but region isn't push restricted so assume it's ok
- pushAllowed = true;
- }
- else
- {
- // Parcel push restriction
- if ((targetlandObj.LandData.Flags & (uint)ParcelFlags.RestrictPushObject) == (uint)ParcelFlags.RestrictPushObject)
- {
- // Need provisions for Group Owned here
- if (m_host.OwnerID == targetlandObj.LandData.OwnerID ||
- targetlandObj.LandData.IsGroupOwned ||
- m_host.OwnerID == targetID)
- {
- pushAllowed = true;
- }
-
- //ParcelFlags.RestrictPushObject
- //pushAllowed = true;
- }
- else
- {
- // Parcel isn't push restricted
- pushAllowed = true;
- }
- }
- }
- }
-
- if (pushAllowed)
- {
- float distance = (PusheePos - m_host.AbsolutePosition).Length();
- float distance_term = distance * distance * distance; // Script Energy
- float pusher_mass = m_host.GetMass();
-
- float PUSH_ATTENUATION_DISTANCE = 17f;
- float PUSH_ATTENUATION_SCALE = 5f;
- float distance_attenuation = 1f;
- if (distance > PUSH_ATTENUATION_DISTANCE)
- {
- float normalized_units = 1f + (distance - PUSH_ATTENUATION_DISTANCE) / PUSH_ATTENUATION_SCALE;
- distance_attenuation = 1f / normalized_units;
- }
-
- Vector3 applied_linear_impulse = impulse;
- {
- float impulse_length = applied_linear_impulse.Length();
-
- float desired_energy = impulse_length * pusher_mass;
- if (desired_energy > 0f)
- desired_energy += distance_term;
-
- float scaling_factor = 1f;
- scaling_factor *= distance_attenuation;
- applied_linear_impulse *= scaling_factor;
-
- }
-
- if (pusheeIsAvatar)
- {
- if (pusheeav != null)
- {
- PhysicsActor pa = pusheeav.PhysicsActor;
-
- if (pa != null)
- {
- if (local != 0)
- {
- applied_linear_impulse *= m_host.GetWorldRotation();
- }
-
- pa.AddForce(applied_linear_impulse, true);
- }
- }
- }
- else
- {
- if (pusheeob != null)
- {
- if (pusheeob.PhysActor != null)
- {
- pusheeob.ApplyImpulse(applied_linear_impulse, local != 0);
- }
- }
- }
- }
- }
-
- public void llPassCollisions(int pass)
- {
- m_host.AddScriptLPS(1);
- if (pass == 0)
- {
- m_host.PassCollisions = false;
- }
- else
- {
- m_host.PassCollisions = true;
- }
- }
-
- public LSL_String llGetScriptName()
- {
- m_host.AddScriptLPS(1);
-
- return m_item.Name != null ? m_item.Name : String.Empty;
- }
-
- public LSL_Integer llGetLinkNumberOfSides(int link)
- {
- m_host.AddScriptLPS(1);
-
- SceneObjectPart linkedPart;
-
- if (link == ScriptBaseClass.LINK_ROOT)
- linkedPart = m_host.ParentGroup.RootPart;
- else if (link == ScriptBaseClass.LINK_THIS)
- linkedPart = m_host;
- else
- linkedPart = m_host.ParentGroup.GetLinkNumPart(link);
-
- return GetNumberOfSides(linkedPart);
- }
-
- public LSL_Integer llGetNumberOfSides()
- {
- m_host.AddScriptLPS(1);
-
- return GetNumberOfSides(m_host);
- }
-
- protected int GetNumberOfSides(SceneObjectPart part)
- {
- int sides = part.GetNumberOfSides();
-
- if (part.GetPrimType() == PrimType.SPHERE && part.Shape.ProfileHollow > 0)
- {
- // Make up for a bug where LSL shows 4 sides rather than 2
- sides += 2;
- }
-
- return sides;
- }
-
-
- /* The new / changed functions were tested with the following LSL script:
-
- default
- {
- state_entry()
- {
- rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
-
- llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
- llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
-
- // convert back and forth between quaternion <-> vector and angle
-
- rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
-
- llOwnerSay("Old rotation was: "+(string) rot);
- llOwnerSay("re-converted rotation is: "+(string) newrot);
-
- llSetRot(rot); // to check the parameters in the prim
- }
- }
- */
-
- // Xantor 29/apr/2008
- // Returns rotation described by rotating angle radians about axis.
- // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
- public LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle)
- {
- m_host.AddScriptLPS(1);
-
- double x, y, z, s, t;
-
- s = Math.Cos(angle * 0.5);
- t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs
- axis = LSL_Vector.Norm(axis);
- x = axis.x * t;
- y = axis.y * t;
- z = axis.z * t;
-
- return new LSL_Rotation(x,y,z,s);
- }
-
- ///
- /// Returns the axis of rotation for a quaternion
- ///
- ///
- ///
- public LSL_Vector llRot2Axis(LSL_Rotation rot)
- {
- m_host.AddScriptLPS(1);
-
- if (Math.Abs(rot.s) > 1) // normalization needed
- rot.Normalize();
-
- double s = Math.Sqrt(1 - rot.s * rot.s);
- if (s < 0.001)
- {
- return new LSL_Vector(1, 0, 0);
- }
- else
- {
- double invS = 1.0 / s;
- if (rot.s < 0) invS = -invS;
- return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS);
- }
- }
-
-
- // Returns the angle of a quaternion (see llRot2Axis for the axis)
- public LSL_Float llRot2Angle(LSL_Rotation rot)
- {
- m_host.AddScriptLPS(1);
-
- if (Math.Abs(rot.s) > 1) // normalization needed
- rot.Normalize();
-
- double angle = 2 * Math.Acos(rot.s);
- if (angle > Math.PI)
- angle = 2 * Math.PI - angle;
-
- return angle;
- }
-
- public LSL_Float llAcos(double val)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Acos(val);
- }
-
- public LSL_Float llAsin(double val)
- {
- m_host.AddScriptLPS(1);
- return (double)Math.Asin(val);
- }
-
- // jcochran 5/jan/2012
- public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b)
- {
- m_host.AddScriptLPS(1);
-
- double aa = (a.x * a.x + a.y * a.y + a.z * a.z + a.s * a.s);
- double bb = (b.x * b.x + b.y * b.y + b.z * b.z + b.s * b.s);
- double aa_bb = aa * bb;
- if (aa_bb == 0) return 0.0;
- double ab = (a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s);
- double quotient = (ab * ab) / aa_bb;
- if (quotient >= 1.0) return 0.0;
- return Math.Acos(2 * quotient - 1);
- }
-
- public LSL_String llGetInventoryKey(string name)
- {
- m_host.AddScriptLPS(1);
-
- TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
-
- if (item == null)
- return UUID.Zero.ToString();
-
- if ((item.CurrentPermissions
- & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
- == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
- {
- return item.AssetID.ToString();
- }
-
- return UUID.Zero.ToString();
- }
-
- public void llAllowInventoryDrop(int add)
- {
- m_host.AddScriptLPS(1);
-
- if (add != 0)
- m_host.ParentGroup.RootPart.AllowedDrop = true;
- else
- m_host.ParentGroup.RootPart.AllowedDrop = false;
-
- // Update the object flags
- m_host.ParentGroup.RootPart.aggregateScriptEvents();
- }
-
- public LSL_Vector llGetSunDirection()
- {
- m_host.AddScriptLPS(1);
-
- LSL_Vector SunDoubleVector3;
- Vector3 SunFloatVector3;
-
- // sunPosition estate setting is set in OpenSim.Region.CoreModules.SunModule
- // have to convert from Vector3 (float) to LSL_Vector (double)
- SunFloatVector3 = World.RegionInfo.RegionSettings.SunVector;
- SunDoubleVector3.x = (double)SunFloatVector3.X;
- SunDoubleVector3.y = (double)SunFloatVector3.Y;
- SunDoubleVector3.z = (double)SunFloatVector3.Z;
-
- return SunDoubleVector3;
- }
-
- public LSL_Vector llGetTextureOffset(int face)
- {
- m_host.AddScriptLPS(1);
- return GetTextureOffset(m_host, face);
- }
-
- protected LSL_Vector GetTextureOffset(SceneObjectPart part, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- LSL_Vector offset = new LSL_Vector();
- if (face == ScriptBaseClass.ALL_SIDES)
- {
- face = 0;
- }
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- offset.x = tex.GetFace((uint)face).OffsetU;
- offset.y = tex.GetFace((uint)face).OffsetV;
- offset.z = 0.0;
- return offset;
- }
- else
- {
- return offset;
- }
- }
-
- public LSL_Vector llGetTextureScale(int side)
- {
- m_host.AddScriptLPS(1);
- Primitive.TextureEntry tex = m_host.Shape.Textures;
- LSL_Vector scale;
- if (side == -1)
- {
- side = 0;
- }
- scale.x = tex.GetFace((uint)side).RepeatU;
- scale.y = tex.GetFace((uint)side).RepeatV;
- scale.z = 0.0;
- return scale;
- }
-
- public LSL_Float llGetTextureRot(int face)
- {
- m_host.AddScriptLPS(1);
- return GetTextureRot(m_host, face);
- }
-
- protected LSL_Float GetTextureRot(SceneObjectPart part, int face)
- {
- Primitive.TextureEntry tex = part.Shape.Textures;
- if (face == -1)
- {
- face = 0;
- }
- if (face >= 0 && face < GetNumberOfSides(part))
- {
- return tex.GetFace((uint)face).Rotation;
- }
- else
- {
- return 0.0;
- }
- }
-
- public LSL_Integer llSubStringIndex(string source, string pattern)
- {
- m_host.AddScriptLPS(1);
- return source.IndexOf(pattern);
- }
-
- public LSL_String llGetOwnerKey(string id)
- {
- m_host.AddScriptLPS(1);
- UUID key = new UUID();
- if (UUID.TryParse(id, out key))
- {
- try
- {
- SceneObjectPart obj = World.GetSceneObjectPart(key);
- if (obj == null)
- return id; // the key is for an agent so just return the key
- else
- return obj.OwnerID.ToString();
- }
- catch (KeyNotFoundException)
- {
- return id; // The Object/Agent not in the region so just return the key
- }
- }
- else
- {
- return UUID.Zero.ToString();
- }
- }
-
- public LSL_Vector llGetCenterOfMass()
- {
- m_host.AddScriptLPS(1);
-
- return new LSL_Vector(m_host.GetCenterOfMass());
- }
-
- public LSL_List llListSort(LSL_List src, int stride, int ascending)
- {
- m_host.AddScriptLPS(1);
-
- if (stride <= 0)
- {
- stride = 1;
- }
- return src.Sort(stride, ascending);
- }
-
- public LSL_Integer llGetListLength(LSL_List src)
- {
- m_host.AddScriptLPS(1);
-
- if (src == null)
- {
- return 0;
- }
- else
- {
- return src.Length;
- }
- }
-
- public LSL_Integer llList2Integer(LSL_List src, int index)
- {
- m_host.AddScriptLPS(1);
- if (index < 0)
- {
- index = src.Length + index;
- }
- if (index >= src.Length || index < 0)
- {
- return 0;
- }
-
- // Vectors & Rotations always return zero in SL, but
- // keys don't always return zero, it seems to be a bit complex.
- else if (src.Data[index] is LSL_Vector ||
- src.Data[index] is LSL_Rotation)
- {
- return 0;
- }
- try
- {
-
- if (src.Data[index] is LSL_Integer)
- return (LSL_Integer)src.Data[index];
- else if (src.Data[index] is LSL_Float)
- return Convert.ToInt32(((LSL_Float)src.Data[index]).value);
- return new LSL_Integer(src.Data[index].ToString());
- }
- catch (FormatException)
- {
- return 0;
- }
- }
-
- public LSL_Float llList2Float(LSL_List src, int index)
- {
- m_host.AddScriptLPS(1);
- if (index < 0)
- {
- index = src.Length + index;
- }
- if (index >= src.Length || index < 0)
- {
- return 0.0;
- }
-
- // Vectors & Rotations always return zero in SL
- else if (src.Data[index] is LSL_Vector ||
- src.Data[index] is LSL_Rotation)
- {
- return 0;
- }
- // valid keys seem to get parsed as integers then converted to floats
- else
- {
- UUID uuidt;
- if (src.Data[index] is LSL_Key && UUID.TryParse(src.Data[index].ToString(), out uuidt))
- {
- return Convert.ToDouble(new LSL_Integer(src.Data[index].ToString()).value);
- }
- }
- try
- {
- if (src.Data[index] is LSL_Integer)
- return Convert.ToDouble(((LSL_Integer)src.Data[index]).value);
- else if (src.Data[index] is LSL_Float)
- return Convert.ToDouble(((LSL_Float)src.Data[index]).value);
- else if (src.Data[index] is LSL_String)
- return Convert.ToDouble(((LSL_String)src.Data[index]).m_string);
- return Convert.ToDouble(src.Data[index]);
- }
- catch (FormatException)
- {
- return 0.0;
- }
- }
-
- public LSL_String llList2String(LSL_List src, int index)
- {
- m_host.AddScriptLPS(1);
- if (index < 0)
- {
- index = src.Length + index;
- }
- if (index >= src.Length || index < 0)
- {
- return String.Empty;
- }
- return src.Data[index].ToString();
- }
-
- public LSL_Key llList2Key(LSL_List src, int index)
- {
- m_host.AddScriptLPS(1);
- if (index < 0)
- {
- index = src.Length + index;
- }
-
- if (index >= src.Length || index < 0)
- {
- return "";
- }
-
- // SL spits out an empty string for types other than key & string
- // At the time of patching, LSL_Key is currently LSL_String,
- // so the OR check may be a little redundant, but it's being done
- // for completion and should LSL_Key ever be implemented
- // as it's own struct
- // NOTE: 3rd case is needed because a NULL_KEY comes through as
- // type 'obj' and wrongly returns ""
- else if (!(src.Data[index] is LSL_String ||
- src.Data[index] is LSL_Key ||
- src.Data[index].ToString() == "00000000-0000-0000-0000-000000000000"))
- {
- return "";
- }
-
- return src.Data[index].ToString();
- }
-
- public LSL_Vector llList2Vector(LSL_List src, int index)
- {
- m_host.AddScriptLPS(1);
- if (index < 0)
- {
- index = src.Length + index;
- }
- if (index >= src.Length || index < 0)
- {
- return new LSL_Vector(0, 0, 0);
- }
- if (src.Data[index].GetType() == typeof(LSL_Vector))
- {
- return (LSL_Vector)src.Data[index];
- }
-
- // SL spits always out ZERO_VECTOR for anything other than
- // strings or vectors. Although keys always return ZERO_VECTOR,
- // it is currently difficult to make the distinction between
- // a string, a key as string and a string that by coincidence
- // is a string, so we're going to leave that up to the
- // LSL_Vector constructor.
- else if (!(src.Data[index] is LSL_String ||
- src.Data[index] is LSL_Vector))
- {
- return new LSL_Vector(0, 0, 0);
- }
- else
- {
- return new LSL_Vector(src.Data[index].ToString());
- }
- }
-
- public LSL_Rotation llList2Rot(LSL_List src, int index)
- {
- m_host.AddScriptLPS(1);
- if (index < 0)
- {
- index = src.Length + index;
- }
- if (index >= src.Length || index < 0)
- {
- return new LSL_Rotation(0, 0, 0, 1);
- }
-
- // SL spits always out ZERO_ROTATION for anything other than
- // strings or vectors. Although keys always return ZERO_ROTATION,
- // it is currently difficult to make the distinction between
- // a string, a key as string and a string that by coincidence
- // is a string, so we're going to leave that up to the
- // LSL_Rotation constructor.
- else if (!(src.Data[index] is LSL_String ||
- src.Data[index] is LSL_Rotation))
- {
- return new LSL_Rotation(0, 0, 0, 1);
- }
- else if (src.Data[index].GetType() == typeof(LSL_Rotation))
- {
- return (LSL_Rotation)src.Data[index];
- }
- else
- {
- return new LSL_Rotation(src.Data[index].ToString());
- }
- }
-
- public LSL_List llList2List(LSL_List src, int start, int end)
- {
- m_host.AddScriptLPS(1);
- return src.GetSublist(start, end);
- }
-
- public LSL_List llDeleteSubList(LSL_List src, int start, int end)
- {
- return src.DeleteSublist(start, end);
- }
-
- public LSL_Integer llGetListEntryType(LSL_List src, int index)
- {
- m_host.AddScriptLPS(1);
- if (index < 0)
- {
- index = src.Length + index;
- }
- if (index >= src.Length)
- {
- return 0;
- }
-
- if (src.Data[index] is LSL_Integer || src.Data[index] is Int32)
- return 1;
- if (src.Data[index] is LSL_Float || src.Data[index] is Single || src.Data[index] is Double)
- return 2;
- if (src.Data[index] is LSL_String || src.Data[index] is String)
- {
- UUID tuuid;
- if (UUID.TryParse(src.Data[index].ToString(), out tuuid))
- {
- return 4;
- }
- else
- {
- return 3;
- }
- }
- if (src.Data[index] is LSL_Vector)
- return 5;
- if (src.Data[index] is LSL_Rotation)
- return 6;
- if (src.Data[index] is LSL_List)
- return 7;
- return 0;
-
- }
-
- ///
- /// Process the supplied list and return the
- /// content of the list formatted as a comma
- /// separated list. There is a space after
- /// each comma.
- ///
- public LSL_String llList2CSV(LSL_List src)
- {
- m_host.AddScriptLPS(1);
-
- return string.Join(", ",
- (new List