From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../Api/Implementation/AsyncCommandManager.cs | 123 +- .../Shared/Api/Implementation/CM_Api.cs | 129 + .../Shared/Api/Implementation/LSL_Api.cs | 5966 ++++++++++++++------ .../Shared/Api/Implementation/LS_Api.cs | 18 +- .../Shared/Api/Implementation/MOD_Api.cs | 84 +- .../Shared/Api/Implementation/OSSL_Api.cs | 2065 +++++-- .../Api/Implementation/Plugins/SensorRepeat.cs | 62 +- .../Shared/Api/Implementation/Plugins/Timer.cs | 34 +- .../Api/Implementation/Properties/AssemblyInfo.cs | 10 +- .../ScriptEngine/Shared/Api/Interface/ICM_Api.cs | 46 + .../ScriptEngine/Shared/Api/Interface/ILSL_Api.cs | 24 +- .../ScriptEngine/Shared/Api/Interface/IMOD_Api.cs | 2 +- .../ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs | 50 +- .../ScriptEngine/Shared/Api/Runtime/CM_Stub.cs | 71 + .../ScriptEngine/Shared/Api/Runtime/Executor.cs | 2 + .../Shared/Api/Runtime/LSL_Constants.cs | 79 +- .../ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs | 113 +- .../ScriptEngine/Shared/Api/Runtime/LS_Stub.cs | 21 + .../ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs | 173 +- ...nSim.Region.ScriptEngine.Shared.Api.Runtime.mdp | 48 - .../Shared/Api/Runtime/Properties/AssemblyInfo.cs | 8 +- .../ScriptEngine/Shared/Api/Runtime/ScriptBase.cs | 2 + 22 files changed, 6572 insertions(+), 2558 deletions(-) create mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs delete mode 100644 OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OpenSim.Region.ScriptEngine.Shared.Api.Runtime.mdp (limited to 'OpenSim/Region/ScriptEngine/Shared/Api') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 036cb5d..e01d2e4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -28,9 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Reflection; using System.Threading; -using log4net; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Monitoring; @@ -39,6 +37,8 @@ using OpenSim.Region.ScriptEngine.Interfaces; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; +using System.Reflection; +using log4net; namespace OpenSim.Region.ScriptEngine.Shared.Api { @@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private static Thread cmdHandlerThread; private static int cmdHandlerThreadCycleSleepms; - + private static int numInstances; /// /// Lock for reading/writing static components of AsyncCommandManager. /// @@ -81,64 +81,64 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public Dataserver DataserverPlugin { - get - { + get + { lock (staticLock) - return m_Dataserver[m_ScriptEngine]; + return m_Dataserver[m_ScriptEngine]; } } public Timer TimerPlugin { - get - { + get + { lock (staticLock) - return m_Timer[m_ScriptEngine]; + return m_Timer[m_ScriptEngine]; } } public HttpRequest HttpRequestPlugin { - get - { + get + { lock (staticLock) - return m_HttpRequest[m_ScriptEngine]; + return m_HttpRequest[m_ScriptEngine]; } } public Listener ListenerPlugin { - get - { + get + { lock (staticLock) - return m_Listener[m_ScriptEngine]; + return m_Listener[m_ScriptEngine]; } } public SensorRepeat SensorRepeatPlugin { - get - { + get + { lock (staticLock) - return m_SensorRepeat[m_ScriptEngine]; + return m_SensorRepeat[m_ScriptEngine]; } } public XmlRequest XmlRequestPlugin { - get - { + get + { lock (staticLock) - return m_XmlRequest[m_ScriptEngine]; + return m_XmlRequest[m_ScriptEngine]; } } public IScriptEngine[] ScriptEngines { - get - { + get + { lock (staticLock) - return m_ScriptEngines.ToArray(); + return m_ScriptEngines.ToArray(); } } @@ -172,18 +172,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); - StartThread(); - } - } - - private static void StartThread() - { - if (cmdHandlerThread == null) - { - // Start the thread that will be doing the work - cmdHandlerThread - = WorkManager.StartThread( + numInstances++; + if (cmdHandlerThread == null) + { + cmdHandlerThread = WorkManager.StartThread( CmdHandlerThreadLoop, "AsyncLSLCmdHandlerThread", ThreadPriority.Normal, true, true); + } } } @@ -194,25 +188,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api cmdHandlerThreadCycleSleepms = 100; } +/* ~AsyncCommandManager() { // Shut down thread -// try -// { -// if (cmdHandlerThread != null) -// { -// if (cmdHandlerThread.IsAlive == true) -// { -// cmdHandlerThread.Abort(); -// //cmdHandlerThread.Join(); -// } -// } -// } -// catch -// { -// } - } + try + { + lock (staticLock) + { + numInstances--; + if(numInstances > 0) + return; + if (cmdHandlerThread != null) + { + if (cmdHandlerThread.IsAlive == true) + { + cmdHandlerThread.Abort(); + //cmdHandlerThread.Join(); + cmdHandlerThread = null; + } + } + } + } + catch + { + } + } +*/ /// /// Main loop for the manager thread /// @@ -223,11 +226,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api try { Thread.Sleep(cmdHandlerThreadCycleSleepms); - + Watchdog.UpdateThread(); DoOneCmdHandlerPass(); - Watchdog.UpdateThread(); } + catch ( System.Threading.ThreadAbortException) { } catch (Exception e) { m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e); @@ -240,24 +243,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api lock (staticLock) { // Check HttpRequests - m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); + try { m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); } catch {} // Check XMLRPCRequests - m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); + try { m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); } catch {} foreach (IScriptEngine s in m_ScriptEngines) { // Check Listeners - m_Listener[s].CheckListeners(); + try { m_Listener[s].CheckListeners(); } catch {} + // Check timers - m_Timer[s].CheckTimerEvents(); + try { m_Timer[s].CheckTimerEvents(); } catch {} // Check Sensors - m_SensorRepeat[s].CheckSenseRepeaterEvents(); + try { m_SensorRepeat[s].CheckSenseRepeaterEvents(); } catch {} // Check dataserver - m_Dataserver[s].ExpireRequests(); + try { m_Dataserver[s].ExpireRequests(); } catch {} } } } @@ -269,6 +273,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) { + // Remove a specific script // m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID); lock (staticLock) @@ -282,7 +287,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Remove from: HttpRequest IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface(); if (iHttpReq != null) - iHttpReq.StopHttpRequestsForScript(itemID); + iHttpReq.StopHttpRequest(localID, itemID); IWorldComm comms = engine.World.RequestModuleInterface(); if (comms != null) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs new file mode 100644 index 0000000..3509968 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs @@ -0,0 +1,129 @@ +/* + * 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.Threading; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Remoting.Lifetime; +using OpenMetaverse; +using Nini.Config; +using OpenSim; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.World.LightShare; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +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 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; + +namespace OpenSim.Region.ScriptEngine.Shared.Api +{ + [Serializable] + public class CM_Api : MarshalByRefObject, ICM_Api, IScriptApi + { + internal IScriptEngine m_ScriptEngine; + internal SceneObjectPart m_host; + internal TaskInventoryItem m_item; + internal bool m_CMFunctionsEnabled = false; + + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) + { + m_ScriptEngine = ScriptEngine; + m_host = host; + m_item = item; + + if (m_ScriptEngine.Config.GetBoolean("AllowCareminsterFunctions", false)) + m_CMFunctionsEnabled = true; + } + + 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; + } + + public Scene World + { + get { return m_ScriptEngine.World; } + } + + public string cmDetectedCountry(int number) + { + m_host.AddScriptLPS(1); + if(!m_CMFunctionsEnabled) + return String.Empty; + if(World.UserAccountService == null) + return String.Empty; + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); + if (detectedParams == null) + return String.Empty; + UUID key = detectedParams.Key; + if(key == UUID.Zero) + return String.Empty; + UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, key); + return account.UserCountry; + } + + public string cmGetAgentCountry(LSL_Key key) + { + if(! m_CMFunctionsEnabled) + return ""; + if(World.UserAccountService == null) + return String.Empty; + if (!World.Permissions.IsGod(m_host.OwnerID)) + return String.Empty; + + UUID uuid; + + if (!UUID.TryParse(key, out uuid)) + return String.Empty; + + UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid); + return account.UserCountry; + } + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 1399880..bac1468 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.Specialized; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; @@ -35,10 +36,12 @@ using System.Runtime.Remoting.Lifetime; using System.Text; using System.Threading; using System.Text.RegularExpressions; +using System.Timers; using Nini.Config; using log4net; using OpenMetaverse; using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; // LitJson is hidden on this using OpenMetaverse.Packets; using OpenMetaverse.Rendering; using OpenSim; @@ -49,6 +52,7 @@ 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.Serialization; using OpenSim.Region.Framework.Scenes.Animation; using OpenSim.Region.Framework.Scenes.Scripting; using OpenSim.Region.PhysicsModules.SharedBase; @@ -72,6 +76,7 @@ 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 Timer = System.Timers.Timer; using System.Linq; using PermissionMask = OpenSim.Framework.PermissionMask; @@ -98,30 +103,87 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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 - /// /// 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 double m_timer = Util.GetTimeStampMS(); 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 bool m_debuggerSafe = 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; @@ -172,7 +234,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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; @@ -183,6 +244,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected bool m_useMeshCacheInCastRay = true; protected static Dictionary m_cachedMeshes = new Dictionary(); +// protected Timer m_ShoutSayTimer; + protected int m_SayShoutCount = 0; + DateTime m_lastSayShoutCheck; + + private Dictionary MovementAnimationsForLSL = + new Dictionary { + {"CROUCH", "Crouching"}, + {"CROUCHWALK", "CrouchWalking"}, + {"FALLDOWN", "Falling Down"}, + {"FLY", "Flying"}, + {"FLYSLOW", "FlyingSlow"}, + {"HOVER", "Hovering"}, + {"HOVER_UP", "Hovering Up"}, + {"HOVER_DOWN", "Hovering Down"}, + {"JUMP", "Jumping"}, + {"LAND", "Landing"}, + {"PREJUMP", "PreJumping"}, + {"RUN", "Running"}, + {"SIT","Sitting"}, + {"SITGROUND","Sitting on Ground"}, + {"STAND", "Standing"}, + {"STANDUP", "Standing Up"}, + {"STRIDE","Striding"}, + {"SOFT_LAND", "Soft Landing"}, + {"TURNLEFT", "Turning Left"}, + {"TURNRIGHT", "Turning Right"}, + {"WALK", "Walking"} + }; + //An array of HTTP/1.1 headers that are not allowed to be used //as custom headers by llHTTPRequest. private string[] HttpStandardHeaders = @@ -203,9 +293,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void Initialize( IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item) { + m_lastSayShoutCheck = DateTime.UtcNow; + m_ScriptEngine = scriptEngine; m_host = host; m_item = item; + m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); LoadConfig(); @@ -228,6 +321,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (seConfig != null) { + m_ScriptDelayFactor = + seConfig.GetFloat("ScriptDelayFactor", m_ScriptDelayFactor); m_ScriptDistanceFactor = seConfig.GetFloat("ScriptDistanceLimitFactor", m_ScriptDistanceFactor); m_MinTimerInterval = @@ -296,7 +391,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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); @@ -307,7 +401,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } IConfig smtpConfig = seConfigSource.Configs["SMTP"]; - if (smtpConfig != null) + 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); @@ -315,6 +409,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_internalObjectHost = smtpConfig.GetString("internal_object_host", m_internalObjectHost); } } + m_sleepMsOnEmail = EMAIL_PAUSE_TIME * 1000; } public override Object InitializeLifetimeService() @@ -330,6 +425,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return lease; } + protected SceneObjectPart MonitoringObject() + { + UUID m = m_host.ParentGroup.MonitoringObject; + if (m == UUID.Zero) + return null; + + SceneObjectPart p = m_ScriptEngine.World.GetSceneObjectPart(m); + if (p == null) + m_host.ParentGroup.MonitoringObject = UUID.Zero; + + return p; + } + + 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_item == null) // Some unit tests don't set this @@ -351,6 +468,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api get { return m_ScriptEngine.World; } } + [DebuggerNonUserCode] public void state(string newState) { m_ScriptEngine.SetState(m_item.ItemID, newState); @@ -360,6 +478,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Reset the named script. The script must be present /// in the same prim. /// + [DebuggerNonUserCode] public void llResetScript() { m_host.AddScriptLPS(1); @@ -376,12 +495,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID item; - m_host.AddScriptLPS(1); - - if ((item = GetScriptByName(name)) != UUID.Zero) - m_ScriptEngine.ResetScript(item); - else + if ((item = GetScriptByName(name)) == UUID.Zero) + { + m_host.AddScriptLPS(1); Error("llResetOtherScript", "Can't find script '" + name + "'"); + return; + } + if(item == m_item.ItemID) + llResetScript(); + else + { + m_host.AddScriptLPS(1); + m_ScriptEngine.ResetScript(item); + } } public LSL_Integer llGetScriptState(string name) @@ -414,7 +540,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((item = GetScriptByName(name)) != UUID.Zero) { - m_ScriptEngine.SetScriptState(item, run == 0 ? false : true); + m_ScriptEngine.SetScriptState(item, run == 0 ? false : true, item == m_item.ItemID); } else { @@ -422,6 +548,58 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public List GetLinkAvatars(int linkType) + { + List ret = new List(); + if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted) + return ret; + + // List avs = m_host.ParentGroup.GetLinkedAvatars(); + // this needs check + List avs = m_host.ParentGroup.GetSittingAvatars(); + switch (linkType) + { + case ScriptBaseClass.LINK_SET: + return avs; + + case ScriptBaseClass.LINK_ROOT: + return ret; + + case ScriptBaseClass.LINK_ALL_OTHERS: + return avs; + + case ScriptBaseClass.LINK_ALL_CHILDREN: + return avs; + + case ScriptBaseClass.LINK_THIS: + return ret; + + default: + if (linkType < 0) + return ret; + + int partCount = m_host.ParentGroup.GetPartCount(); + + if (linkType <= partCount) + { + return ret; + } + else + { + linkType = linkType - partCount; + if (linkType > avs.Count) + { + return ret; + } + else + { + ret.Add(avs[linkType-1]); + return ret; + } + } + } + } + /// /// Get a given link entity from a linkset (linked objects and any sitting avatars). /// @@ -501,7 +679,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public static List GetLinkParts(SceneObjectPart part, int linkType) { List ret = new List(); - ret.Add(part); + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return ret; switch (linkType) { @@ -509,7 +688,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new List(part.ParentGroup.Parts); case ScriptBaseClass.LINK_ROOT: - ret = new List(); ret.Add(part.ParentGroup.RootPart); return ret; @@ -529,16 +707,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ret; case ScriptBaseClass.LINK_THIS: + ret.Add(part); return ret; default: if (linkType < 0) - return new List(); + return ret; SceneObjectPart target = part.ParentGroup.GetLinkNumPart(linkType); if (target == null) - return new List(); - ret = new List(); + return ret; ret.Add(target); return ret; } @@ -648,8 +826,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float llFrand(double mag) { m_host.AddScriptLPS(1); - - return Util.RandomClass.NextDouble() * mag; + lock (Util.RandomClass) + { + return Util.RandomClass.NextDouble() * mag; + } } public LSL_Integer llFloor(double f) @@ -700,31 +880,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //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) + // Utility function for llRot2Euler + + public LSL_Vector llRot2Euler(LSL_Rotation q1) { m_host.AddScriptLPS(1); + LSL_Vector eul = new LSL_Vector(); - 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); + double sqw = q1.s*q1.s; + double sqx = q1.x*q1.x; + double sqy = q1.z*q1.z; + double sqz = q1.y*q1.y; + double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor + double test = q1.x*q1.z + q1.y*q1.s; + if (test > 0.4999*unit) { // singularity at north pole + eul.z = 2 * Math.Atan2(q1.x,q1.s); + eul.y = Math.PI/2; + eul.x = 0; + return eul; + } + if (test < -0.4999*unit) { // singularity at south pole + eul.z = -2 * Math.Atan2(q1.x,q1.s); + eul.y = -Math.PI/2; + eul.x = 0; + return eul; + } + eul.z = Math.Atan2(2*q1.z*q1.s-2*q1.x*q1.y , sqx - sqy - sqz + sqw); + eul.y = Math.Asin(2*test/unit); + eul.x = Math.Atan2(2*q1.x*q1.s-2*q1.z*q1.y , -sqx + sqy - sqz + sqw); + return eul; } /* From wiki: @@ -777,18 +961,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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; + v.x *= 0.5; + v.y *= 0.5; + v.z *= 0.5; + double c1 = Math.Cos(v.x); + double c2 = Math.Cos(v.y); + double c1c2 = c1 * c2; + double s1 = Math.Sin(v.x); + double s2 = Math.Sin(v.y); + double s1s2 = s1 * s2; + double c1s2 = c1 * s2; + double s1c2 = s1 * c2; + double c3 = Math.Cos(v.z); + double s3 = Math.Sin(v.z); + + x = s1c2 * c3 + c1s2 * s3; + y = c1s2 * c3 - s1c2 * s3; + z = s1s2 * c3 + c1c2 * s3; + s = c1c2 * c3 - s1s2 * s3; return new LSL_Rotation(x, y, z, s); } @@ -926,75 +1116,74 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { //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)) + /* This method is more accurate than the SL one, and thus causes problems + for scripts that deal with the SL inaccuracy around 180-degrees -.- .._. + + double dotProduct = LSL_Vector.Dot(a, b); + LSL_Vector crossProduct = LSL_Vector.Cross(a, b); + double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b); + double angle = Math.Acos(dotProduct / magProduct); + LSL_Vector axis = LSL_Vector.Norm(crossProduct); + double s = Math.Sin(angle / 2); + + double x = axis.x * s; + double y = axis.y * s; + double z = axis.z * s; + double w = Math.Cos(angle / 2); + + if (Double.IsNaN(x) || Double.IsNaN(y) || Double.IsNaN(z) || Double.IsNaN(w)) + return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); + + return new LSL_Rotation((float)x, (float)y, (float)z, (float)w); + */ + + // This method mimics the 180 errors found in SL + // See www.euclideanspace.com... angleBetween + LSL_Vector vec_a = a; + LSL_Vector vec_b = b; + + // Eliminate zero length + LSL_Float vec_a_mag = LSL_Vector.Mag(vec_a); + LSL_Float vec_b_mag = LSL_Vector.Mag(vec_b); + if (vec_a_mag < 0.00001 || + vec_b_mag < 0.00001) { - rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); + return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); } - else + + // Normalize + vec_a = llVecNorm(vec_a); + vec_b = llVecNorm(vec_b); + + // Calculate axis and rotation angle + LSL_Vector axis = vec_a % vec_b; + LSL_Float cos_theta = vec_a * vec_b; + + // Check if parallel + if (cos_theta > 0.99999) { - 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 new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); + } + + // Check if anti-parallel + else if (cos_theta < -0.99999) + { + LSL_Vector orthog_axis = new LSL_Vector(1.0, 0.0, 0.0) - (vec_a.x / (vec_a * vec_a) * vec_a); + if (LSL_Vector.Mag(orthog_axis) < 0.000001) orthog_axis = new LSL_Vector(0.0, 0.0, 1.0); + return new LSL_Rotation((float)orthog_axis.x, (float)orthog_axis.y, (float)orthog_axis.z, 0.0); + } + else // other rotation + { + LSL_Float theta = (LSL_Float)Math.Acos(cos_theta) * 0.5f; + axis = llVecNorm(axis); + double x, y, z, s, t; + s = Math.Cos(theta); + t = Math.Sin(theta); + x = axis.x * t; + y = axis.y * t; + z = axis.z * t; + return new LSL_Rotation(x,y,z,s); } - return rotBetween; } public void llWhisper(int channelID, string text) @@ -1012,10 +1201,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text); } + private void CheckSayShoutTime() + { + DateTime now = DateTime.UtcNow; + if ((now - m_lastSayShoutCheck).Ticks > 10000000) // 1sec + { + m_lastSayShoutCheck = now; + m_SayShoutCount = 0; + } + else + m_SayShoutCount++; + } + public void llSay(int channelID, string text) { m_host.AddScriptLPS(1); + if (channelID == 0) +// m_SayShoutCount++; + CheckSayShoutTime(); + + if (m_SayShoutCount >= 11) + ScriptSleep(2000); + if (m_scriptConsoleChannelEnabled && (channelID == m_scriptConsoleChannel)) { Console.WriteLine(text); @@ -1038,6 +1246,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); + if (channelID == 0) +// m_SayShoutCount++; + CheckSayShoutTime(); + + if (m_SayShoutCount >= 11) + ScriptSleep(2000); + if (text.Length > 1023) text = text.Substring(0, 1023); @@ -1062,8 +1277,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); - World.SimChat(Utils.StringToBytes(text), - ChatTypeEnum.Region, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false); + // debug channel is also sent to avatars + if (channelID == ScriptBaseClass.DEBUG_CHANNEL) + { + 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) @@ -1078,16 +1298,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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); @@ -1346,10 +1561,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return detectedParams.TouchUV; } + [DebuggerNonUserCode] public virtual void llDie() { m_host.AddScriptLPS(1); - throw new SelfDeleteException(); + if (!m_host.ParentGroup.IsAttachment) throw new SelfDeleteException(); } public LSL_Float llGround(LSL_Vector offset) @@ -1420,6 +1636,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llSetStatus(int status, int value) { + if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted) + return; m_host.AddScriptLPS(1); int statusrotationaxis = 0; @@ -1431,18 +1649,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SceneObjectGroup group = m_host.ParentGroup; bool allow = true; + int maxprims = World.m_linksetPhysCapacity; + bool checkShape = (maxprims > 0 && group.PrimCount > maxprims); + foreach (SceneObjectPart part in group.Parts) { + if (part.PhysicsShapeType == (byte)PhysicsShapeType.None) + continue; + if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys) { allow = false; break; } + if (checkShape) + { + if (--maxprims < 0) + { + allow = false; + break; + } + } } if (!allow) return; + if (m_host.ParentGroup.RootPart.PhysActor != null && + m_host.ParentGroup.RootPart.PhysActor.IsPhysical) + return; + m_host.ScriptSetPhysicsStatus(true); } else @@ -1586,6 +1822,53 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 0; } + public LSL_Integer llScaleByFactor(double scaling_factor) + { + m_host.AddScriptLPS(1); + SceneObjectGroup group = m_host.ParentGroup; + + if(scaling_factor < 1e-6) + return ScriptBaseClass.FALSE; + if(scaling_factor > 1e6) + return ScriptBaseClass.FALSE; + + if (group == null || group.IsDeleted || group.inTransit) + return ScriptBaseClass.FALSE; + + if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical) + return ScriptBaseClass.FALSE; + + if (group.RootPart.KeyframeMotion != null) + return ScriptBaseClass.FALSE; + + if(group.GroupResize(scaling_factor)) + return ScriptBaseClass.TRUE; + else + return ScriptBaseClass.FALSE; + } + + public LSL_Float llGetMaxScaleFactor() + { + m_host.AddScriptLPS(1); + SceneObjectGroup group = m_host.ParentGroup; + + if (group == null || group.IsDeleted || group.inTransit) + return 1.0f; + + return (LSL_Float)group.GetMaxGroupResizeScale(); + } + + public LSL_Float llGetMinScaleFactor() + { + m_host.AddScriptLPS(1); + SceneObjectGroup group = m_host.ParentGroup; + + if (group == null || group.IsDeleted || group.inTransit) + return 1.0f; + + return (LSL_Float)group.GetMinGroupResizeScale(); + } + public void llSetScale(LSL_Vector scale) { m_host.AddScriptLPS(1); @@ -1641,6 +1924,50 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); + SetColor(m_host, color, face); + } + + protected void SetColor(SceneObjectPart part, LSL_Vector color, int face) + { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + + Primitive.TextureEntry tex = part.Shape.Textures; + int nsides = GetNumberOfSides(part); + Color4 texcolor; + + if (face >= 0 && face < nsides) + { + texcolor = tex.CreateFace((uint)face).RGBA; + texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f); + texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f); + texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f); + tex.FaceTextures[face].RGBA = texcolor; + part.UpdateTextureEntry(tex.GetBytes()); + return; + } + else if (face == ScriptBaseClass.ALL_SIDES) + { + for (uint i = 0; i < nsides; i++) + { + if (tex.FaceTextures[i] != null) + { + texcolor = tex.FaceTextures[i].RGBA; + texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f); + texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f); + texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f); + tex.FaceTextures[i].RGBA = texcolor; + } + texcolor = tex.DefaultTexture.RGBA; + texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f); + texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f); + texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f); + tex.DefaultTexture.RGBA = texcolor; + } + part.UpdateTextureEntry(tex.GetBytes()); + return; + } + if (face == ScriptBaseClass.ALL_SIDES) face = SceneObjectPart.ALL_SIDES; @@ -1714,15 +2041,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } +/* + public void llSetContentType(LSL_Key id, LSL_Integer content_type) + { + if (m_UrlModule != null) + { + string type = "text.plain"; + if (content_type == (int)ScriptBaseClass.CONTENT_TYPE_HTML) + type = "text/html"; + + m_UrlModule.HttpContentType(new UUID(id),type); + } + } +*/ public void SetTexGen(SceneObjectPart part, int face,int style) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + 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)) + int nsides = GetNumberOfSides(part); + + if (face >= 0 && face < nsides) { tex.CreateFace((uint) face); tex.FaceTextures[face].TexMapType = textype; @@ -1731,7 +2076,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else if (face == ScriptBaseClass.ALL_SIDES) { - for (uint i = 0; i < GetNumberOfSides(part); i++) + for (uint i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -1746,8 +2091,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void SetGlow(SceneObjectPart part, int face, float glow) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + Primitive.TextureEntry tex = part.Shape.Textures; - if (face >= 0 && face < GetNumberOfSides(part)) + int nsides = GetNumberOfSides(part); + + if (face >= 0 && face < nsides) { tex.CreateFace((uint) face); tex.FaceTextures[face].Glow = glow; @@ -1756,7 +2106,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else if (face == ScriptBaseClass.ALL_SIDES) { - for (uint i = 0; i < GetNumberOfSides(part); i++) + for (uint i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -1771,6 +2121,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; Shininess sval = new Shininess(); @@ -1793,8 +2145,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; } + int nsides = GetNumberOfSides(part); + Primitive.TextureEntry tex = part.Shape.Textures; - if (face >= 0 && face < GetNumberOfSides(part)) + if (face >= 0 && face < nsides) { tex.CreateFace((uint) face); tex.FaceTextures[face].Shiny = sval; @@ -1804,7 +2158,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else if (face == ScriptBaseClass.ALL_SIDES) { - for (uint i = 0; i < GetNumberOfSides(part); i++) + for (uint i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -1821,8 +2175,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void SetFullBright(SceneObjectPart part, int face, bool bright) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + + int nsides = GetNumberOfSides(part); Primitive.TextureEntry tex = part.Shape.Textures; - if (face >= 0 && face < GetNumberOfSides(part)) + if (face >= 0 && face < nsides) { tex.CreateFace((uint) face); tex.FaceTextures[face].Fullbright = bright; @@ -1831,7 +2189,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else if (face == ScriptBaseClass.ALL_SIDES) { - for (uint i = 0; i < GetNumberOfSides(part); i++) + for (uint i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -1854,15 +2212,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected LSL_Float GetAlpha(SceneObjectPart part, int face) { Primitive.TextureEntry tex = part.Shape.Textures; + int nsides = GetNumberOfSides(part); if (face == ScriptBaseClass.ALL_SIDES) { int i; double sum = 0.0; - for (i = 0 ; i < GetNumberOfSides(part); i++) + for (i = 0 ; i < nsides; i++) sum += (double)tex.GetFace((uint)i).RGBA.A; return sum; } - if (face >= 0 && face < GetNumberOfSides(part)) + if (face >= 0 && face < nsides) { return (double)tex.GetFace((uint)face).RGBA.A; } @@ -1881,16 +2240,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); List parts = GetLinkParts(linknumber); - - foreach (SceneObjectPart part in parts) - SetAlpha(part, alpha, face); + if (parts.Count > 0) + { + try + { + foreach (SceneObjectPart part in parts) + SetAlpha(part, alpha, face); + } + finally { } + } } protected void SetAlpha(SceneObjectPart part, double alpha, int face) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + Primitive.TextureEntry tex = part.Shape.Textures; + int nsides = GetNumberOfSides(part); Color4 texcolor; - if (face >= 0 && face < GetNumberOfSides(part)) + + if (face >= 0 && face < nsides) { texcolor = tex.CreateFace((uint)face).RGBA; texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f); @@ -1900,7 +2270,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else if (face == ScriptBaseClass.ALL_SIDES) { - for (int i = 0; i < GetNumberOfSides(part); i++) + for (int i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -1940,7 +2310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction, float wind, float tension, LSL_Vector Force) { - if (part == null) + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return; if (flexi) @@ -1981,7 +2351,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff) { - if (part == null) + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return; if (light) @@ -2014,11 +2384,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Primitive.TextureEntry tex = part.Shape.Textures; Color4 texcolor; LSL_Vector rgb = new LSL_Vector(); + int nsides = GetNumberOfSides(part); + if (face == ScriptBaseClass.ALL_SIDES) { int i; - - for (i = 0 ; i < GetNumberOfSides(part); i++) + for (i = 0; i < nsides; i++) { texcolor = tex.GetFace((uint)i).RGBA; rgb.x += texcolor.R; @@ -2026,14 +2397,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api rgb.z += texcolor.B; } - rgb.x /= (float)GetNumberOfSides(part); - rgb.y /= (float)GetNumberOfSides(part); - rgb.z /= (float)GetNumberOfSides(part); + float invnsides = 1.0f / (float)nsides; + + rgb.x *= invnsides; + rgb.y *= invnsides; + rgb.z *= invnsides; return rgb; } - - if (face >= 0 && face < GetNumberOfSides(part)) + if (face >= 0 && face < nsides) { texcolor = tex.GetFace((uint)face).RGBA; rgb.x = texcolor.R; @@ -2052,6 +2424,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); SetTexture(m_host, texture, face); + ScriptSleep(m_sleepMsOnSetTexture); } public void llSetLinkTexture(int linknumber, string texture, int face) @@ -2059,13 +2432,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); List parts = GetLinkParts(linknumber); - - foreach (SceneObjectPart part in parts) - SetTexture(part, texture, face); + if (parts.Count > 0) + { + try + { + foreach (SceneObjectPart part in parts) + SetTexture(part, texture, face); + } + finally { } + } + ScriptSleep(m_sleepMsOnSetLinkTexture); } protected void SetTexture(SceneObjectPart part, string texture, int face) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + UUID textureID = new UUID(); textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture); @@ -2075,9 +2458,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } + Primitive.TextureEntry tex = part.Shape.Textures; + int nsides = GetNumberOfSides(part); - if (face >= 0 && face < GetNumberOfSides(part)) + if (face >= 0 && face < nsides) { Primitive.TextureEntryFace texface = tex.CreateFace((uint)face); texface.TextureID = textureID; @@ -2087,7 +2472,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else if (face == ScriptBaseClass.ALL_SIDES) { - for (uint i = 0; i < GetNumberOfSides(part); i++) + for (uint i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -2105,12 +2490,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); ScaleTexture(m_host, u, v, face); + ScriptSleep(m_sleepMsOnScaleTexture); } protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + Primitive.TextureEntry tex = part.Shape.Textures; - if (face >= 0 && face < GetNumberOfSides(part)) + int nsides = GetNumberOfSides(part); + + if (face >= 0 && face < nsides) { Primitive.TextureEntryFace texface = tex.CreateFace((uint)face); texface.RepeatU = (float)u; @@ -2121,7 +2512,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } if (face == ScriptBaseClass.ALL_SIDES) { - for (int i = 0; i < GetNumberOfSides(part); i++) + for (int i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -2140,12 +2531,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); OffsetTexture(m_host, u, v, face); + ScriptSleep(m_sleepMsOnOffsetTexture); } protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + Primitive.TextureEntry tex = part.Shape.Textures; - if (face >= 0 && face < GetNumberOfSides(part)) + int nsides = GetNumberOfSides(part); + + if (face >= 0 && face < nsides) { Primitive.TextureEntryFace texface = tex.CreateFace((uint)face); texface.OffsetU = (float)u; @@ -2156,7 +2553,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } if (face == ScriptBaseClass.ALL_SIDES) { - for (int i = 0; i < GetNumberOfSides(part); i++) + for (int i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -2175,12 +2572,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); RotateTexture(m_host, rotation, face); + ScriptSleep(m_sleepMsOnRotateTexture); } protected void RotateTexture(SceneObjectPart part, double rotation, int face) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + Primitive.TextureEntry tex = part.Shape.Textures; - if (face >= 0 && face < GetNumberOfSides(part)) + int nsides = GetNumberOfSides(part); + + if (face >= 0 && face < nsides) { Primitive.TextureEntryFace texface = tex.CreateFace((uint)face); texface.Rotation = (float)rotation; @@ -2190,7 +2593,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } if (face == ScriptBaseClass.ALL_SIDES) { - for (int i = 0; i < GetNumberOfSides(part); i++) + for (int i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -2212,12 +2615,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected LSL_String GetTexture(SceneObjectPart part, int face) { Primitive.TextureEntry tex = part.Shape.Textures; + int nsides = GetNumberOfSides(part); + if (face == ScriptBaseClass.ALL_SIDES) { face = 0; } - if (face >= 0 && face < GetNumberOfSides(part)) + if (face >= 0 && face < nsides) { Primitive.TextureEntryFace texface; texface = tex.GetFace((uint)face); @@ -2248,6 +2653,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); SetPos(m_host, pos, true); + + ScriptSleep(m_sleepMsOnSetPos); } /// @@ -2278,7 +2685,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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.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 ) ) { @@ -2317,7 +2725,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return end; } - protected LSL_Vector GetSetPosTarget(SceneObjectPart part, LSL_Vector targetPos, LSL_Vector fromPos) + protected LSL_Vector GetSetPosTarget(SceneObjectPart part, LSL_Vector targetPos, LSL_Vector fromPos, bool adjust) { if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return fromPos; @@ -2333,9 +2741,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0) targetPos.z = ground; } - LSL_Vector real_vec = SetPosAdjust(fromPos, targetPos); + if (adjust) + return SetPosAdjust(fromPos, targetPos); - return real_vec; + return targetPos; } /// @@ -2346,27 +2755,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// 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) + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted || part.ParentGroup.inTransit) + return; + + LSL_Vector currentPos = GetPartLocalPos(part); + LSL_Vector toPos = GetSetPosTarget(part, targetPos, currentPos, adjust); - 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)); + if (!parent.IsAttachment && !World.Permissions.CanObjectEntry(parent, false, (Vector3)toPos)) + return; + parent.UpdateGroupPosition((Vector3)toPos); } else { - part.OffsetPosition = !adjust ? targetPos : - SetPosAdjust(currentPos, targetPos); - SceneObjectGroup parent = part.ParentGroup; - parent.HasGroupChanged = true; - parent.ScheduleGroupForTerseUpdate(); + part.OffsetPosition = (Vector3)toPos; +// SceneObjectGroup parent = part.ParentGroup; +// parent.HasGroupChanged = true; +// parent.ScheduleGroupForTerseUpdate(); + part.ScheduleTerseUpdate(); } } @@ -2395,13 +2805,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else { if (part.ParentGroup.IsAttachment) - { pos = part.AttachedPos; - } else - { pos = part.AbsolutePosition; - } } // m_log.DebugFormat("[LSL API]: Returning {0} in GetPartLocalPos()", pos); @@ -2414,7 +2820,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); // try to let this work as in SL... - if (m_host.ParentID == 0) + if (m_host.ParentID == 0 || (m_host.ParentGroup != null && m_host == m_host.ParentGroup.RootPart)) { // special case: If we are root, rotate complete SOG to new rotation SetRot(m_host, rot); @@ -2428,35 +2834,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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 + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + + bool isroot = (part == part.ParentGroup.RootPart); + bool isphys; + PhysicsActor pa = part.PhysActor; - if (pa != null && !pa.IsPhysical) + // keep using physactor ideia of isphysical + // it should be SOP ideia of that + // not much of a issue with ubOde + if (pa != null && pa.IsPhysical) + isphys = true; + else + isphys = false; + + // SL doesn't let scripts rotate root of physical linksets + if (isroot && isphys) + return; + + part.UpdateRotation(rot); + + // Update rotation does not move the object in the physics engine if it's a non physical linkset + // so do a nasty update of parts positions if is a root part rotation + if (isroot && pa != null) // with if above implies non physical root part { part.ParentGroup.ResetChildPrimPhysicsPositions(); } + else // fix sitting avatars. This is only needed bc of how we link avas to child parts, not root part + { + // List sittingavas = part.ParentGroup.GetLinkedAvatars(); + List sittingavas = part.ParentGroup.GetSittingAvatars(); + if (sittingavas.Count > 0) + { + foreach (ScenePresence av in sittingavas) + { + if (isroot || part.LocalId == av.ParentID) + av.SendTerseUpdateToAllClients(); + } + } + } } /// @@ -2473,6 +2904,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); Quaternion q = m_host.GetWorldRotation(); + + if (m_host.ParentGroup != null && m_host.ParentGroup.AttachmentPoint != 0) + { + ScenePresence avatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar); + if (avatar != null) + { + if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) + q = avatar.CameraRotation * q; // Mouselook + else + q = avatar.Rotation * q; // Currently infrequently updated so may be inaccurate + } + } + return new LSL_Rotation(q.X, q.Y, q.Z, q.W); } @@ -2500,14 +2944,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_Rotation(q); } - return new LSL_Rotation(part.GetWorldRotation()); + q = part.GetWorldRotation(); + 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 * q; // Mouselook + else + q = avatar.Rotation * q; // Currently infrequently updated so may be inaccurate + } + } + + return new LSL_Rotation(q.X, q.Y, q.Z, q.W); } public LSL_Rotation llGetLocalRot() { - m_host.AddScriptLPS(1); + return GetPartLocalRot(m_host); + } - return new LSL_Rotation(m_host.RotationOffset); + private LSL_Rotation GetPartLocalRot(SceneObjectPart part) + { + m_host.AddScriptLPS(1); + Quaternion rot = part.RotationOffset; + return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W); } public void llSetForce(LSL_Vector force, int local) @@ -2537,32 +2999,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return force; } - public void llSetVelocity(LSL_Vector velocity, int local) + public void llSetVelocity(LSL_Vector vel, int local) { m_host.AddScriptLPS(1); - - if (!m_host.ParentGroup.IsDeleted) - { - if (local != 0) - velocity *= llGetRot(); - - m_host.ParentGroup.RootPart.Velocity = velocity; - } + m_host.SetVelocity(new Vector3((float)vel.x, (float)vel.y, (float)vel.z), local != 0); } - public void llSetAngularVelocity(LSL_Vector angularVelocity, int local) + public void llSetAngularVelocity(LSL_Vector avel, int local) { m_host.AddScriptLPS(1); - - if (!m_host.ParentGroup.IsDeleted) - { - if (local != 0) - angularVelocity *= llGetRot(); - - m_host.ParentGroup.RootPart.AngularVelocity = angularVelocity; - } + m_host.SetAngularVelocity(new Vector3((float)avel.x, (float)avel.y, (float)avel.z), local != 0); } - public LSL_Integer llTarget(LSL_Vector position, double range) { m_host.AddScriptLPS(1); @@ -2613,16 +3060,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.ApplyImpulse(v, local != 0); } + public void llApplyRotationalImpulse(LSL_Vector force, int local) { m_host.AddScriptLPS(1); - m_host.ApplyAngularImpulse(force, local != 0); + m_host.ParentGroup.RootPart.ApplyAngularImpulse(force, local != 0); } public void llSetTorque(LSL_Vector torque, int local) { m_host.AddScriptLPS(1); - m_host.SetAngularImpulse(torque, local != 0); + m_host.ParentGroup.RootPart.SetAngularImpulse(torque, local != 0); } public LSL_Vector llGetTorque() @@ -2639,20 +3087,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api llSetTorque(torque, local); } + public LSL_Vector llGetVel() { m_host.AddScriptLPS(1); - Vector3 vel; + Vector3 vel = Vector3.Zero; if (m_host.ParentGroup.IsAttachment) { ScenePresence avatar = m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.AttachedAvatar); - vel = avatar.GetWorldVelocity(); + if (avatar != null) + vel = avatar.GetWorldVelocity(); } else { - vel = m_host.Velocity; + vel = m_host.ParentGroup.RootPart.Velocity; } return new LSL_Vector(vel); @@ -2668,8 +3118,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetOmega() { m_host.AddScriptLPS(1); - - return new LSL_Vector(m_host.AngularVelocity); + Vector3 avel = m_host.AngularVelocity; + return new LSL_Vector(avel.X, avel.Y, avel.Z); } public LSL_Float llGetTimeOfDay() @@ -2687,22 +3137,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float llGetTime() { m_host.AddScriptLPS(1); - TimeSpan ScriptTime = DateTime.Now - m_timer; - return (double)(ScriptTime.TotalMilliseconds / 1000); + double ScriptTime = Util.GetTimeStampMS() - m_timer; + return (float)Math.Round((ScriptTime / 1000.0), 3); } public void llResetTime() { m_host.AddScriptLPS(1); - m_timer = DateTime.Now; + m_timer = Util.GetTimeStampMS(); } public LSL_Float llGetAndResetTime() { m_host.AddScriptLPS(1); - TimeSpan ScriptTime = DateTime.Now - m_timer; - m_timer = DateTime.Now; - return (double)(ScriptTime.TotalMilliseconds / 1000); + double now = Util.GetTimeStampMS(); + double ScriptTime = now - m_timer; + m_timer = now; + return (float)Math.Round((ScriptTime / 1000.0), 3); } public void llSound(string sound, double volume, int queue, int loop) @@ -2722,8 +3173,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_SoundModule.SendSound( m_host.UUID, - ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), - volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None, + ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), + volume, false, 0, 0, false, false); } } @@ -2734,7 +3185,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_SoundModule != null) { m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), - volume, 20, false); + volume, 20, false,false); } } @@ -2744,16 +3195,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_SoundModule != null) { m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), - volume, 20, true); + volume, 20, true, false); } } public void llLoopSoundSlave(string sound, double volume) { m_host.AddScriptLPS(1); - lock (m_host.ParentGroup.LoopSoundSlavePrims) + if (m_SoundModule != null) { - m_host.ParentGroup.LoopSoundSlavePrims.Add(m_host); + m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), + volume, 20, false, true); } } @@ -2795,6 +3247,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_SoundModule != null) m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0); + ScriptSleep(m_sleepMsOnPreloadSound); } /// @@ -3027,7 +3480,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return src.ToLower(); } - public void llGiveMoney(string destination, int amount) + public LSL_Integer llGiveMoney(string destination, int amount) { Util.FireAndForget(x => { @@ -3058,69 +3511,86 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } + string reason; money.ObjectGiveMoney( - m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount); + + m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount,UUID.Zero, out reason); }, null, "LSL_Api.llGiveMoney"); + + return 0; } 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) { + doObjectRez(inventory, pos, vel, rot, param, true); + } + + public void doObjectRez(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param, bool atRoot) + { m_host.AddScriptLPS(1); + if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s)) + return; - 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); - float dist = (float)llVecDist(llGetPos(), pos); + if (dist > m_ScriptDistanceFactor * 10.0f) + return; - TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory); + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory); - if (item == null) - { - Error("llRezAtRoot", "Can't find object '" + inventory + "'"); - return; - } + if (item == null) + { + Error("llRez(AtRoot/Object)", "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; - } + if (item.InvType != (int)InventoryType.Object) + { + Error("llRez(AtRoot/Object)", "Can't create requested object; object is missing from database"); + return; + } - // need the magnitude later - // float velmag = (float)Util.GetMagnitude(llvel); + Util.FireAndForget(x => + { - List new_groups = World.RezObject(m_host, item, pos, rot, vel, param); + Quaternion wrot = rot; + wrot.Normalize(); + List new_groups = World.RezObject(m_host, item, pos, wrot, vel, param, atRoot); // If either of these are null, then there was an unknown error. if (new_groups == null) return; + bool notAttachment = !m_host.ParentGroup.IsAttachment; + foreach (SceneObjectGroup group in new_groups) { // objects rezzed with this method are die_at_edge by default. @@ -3134,58 +3604,79 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api group.RootPart.UUID.ToString()) }, new DetectParams[0])); - float groupmass = group.GetMass(); + if (notAttachment) + { + float groupmass = group.GetMass(); - PhysicsActor pa = group.RootPart.PhysActor; + 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) + //Recoil. + if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) { - llApplyImpulse(recoil, 0); + 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"); + } + }, null, "LSL_Api.doObjectRez"); + + //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); + doObjectRez(inventory, pos, vel, rot, param, false); } public void llLookAt(LSL_Vector target, double strength, double damping) { m_host.AddScriptLPS(1); - // Determine where we are looking from + + // Get the normalized vector to the target LSL_Vector from = llGetPos(); - // normalized direction to target + // 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); +// 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)); +// LSL_Vector left = llVecNorm(LSL_Vector.Cross(up, dir)); + + LSL_Vector left = new LSL_Vector(-dir.y, dir.x, 0.0f); + left = llVecNorm(left); // make up orthogonal to left and dir - up = LSL_Vector.Cross(dir, left); + LSL_Vector up = LSL_Vector.Cross(dir, left); // compute rotation based on orthogonal axes + // and rotate so Z points to target with X below horizont 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; + SceneObjectGroup sog = m_host.ParentGroup; + if(sog == null || sog.IsDeleted) + return; - if (m_host.ParentGroup.IsAttachment || strength == 0 || pa == null || !pa.IsPhysical) + if (!sog.UsesPhysics || sog.IsAttachment) { - llSetRot(rot); + // Do nothing if either value is 0 (this has been checked in SL) + if (strength <= 0.0 || damping <= 0.0) + return; + + llSetLocalRot(rot); } else { - m_host.StartLookAt(rot, (float)strength, (float)damping); + if (strength == 0) + { + llSetLocalRot(rot); + return; + } + + sog.StartLookAt(rot, (float)strength, (float)damping); } } @@ -3231,22 +3722,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - if (m_host.IsRoot) - { + // new SL always returns object mass +// if (m_host.IsRoot) +// { return m_host.ParentGroup.GetMass(); - } - else - { - return m_host.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; + return 100f * llGetMass(); } public void llCollisionFilter(string name, string id, int accept) @@ -3296,7 +3786,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // Unregister controls from Presence presence.UnRegisterControlEventsToScript(m_host.LocalId, m_item.ItemID); - // Remove Take Control permission. + // Remove Take Control permission. m_item.PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS; } } @@ -3355,9 +3845,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); -// if (m_host.ParentGroup.RootPart.AttachmentPoint == 0) -// return; - if (m_item.PermsGranter != m_host.OwnerID) return; @@ -3401,6 +3888,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llInstantMessage(string user, string message) { m_host.AddScriptLPS(1); + UUID result; + if (!UUID.TryParse(user, out result) || result == UUID.Zero) + { + Error("llInstantMessage","An invalid key was passed to llInstantMessage"); + ScriptSleep(2000); + return; + } // 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, @@ -3411,31 +3905,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // 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()); + UUID friendTransactionID = UUID.Random(); + + //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); 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. + msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); + msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName; + 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.dialog = (byte)19; // MessageFromObject msg.fromGroup = false;// fromGroup; msg.offline = (byte)0; //offline; - msg.ParentEstateID = 0; //ParentEstateID; + msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID; msg.Position = new Vector3(m_host.AbsolutePosition); msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; @@ -3452,6 +3940,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); } + + ScriptSleep(m_sleepMsOnInstantMessage); } public void llEmail(string address, string subject, string message) @@ -3489,6 +3979,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } emailModule.SendEmail(m_host.UUID, address, subject, message); + ScriptSleep(m_sleepMsOnEmail); } public void llGetNextEmail(string address, string subject) @@ -3551,25 +4042,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (m_host.PhysActor != null) + PIDHoverType hoverType = PIDHoverType.Ground; + if (water != 0) { - PIDHoverType hoverType = PIDHoverType.Ground; - if (water != 0) - { - hoverType = PIDHoverType.GroundAndWater; - } - - m_host.SetHoverHeight((float)height, hoverType, (float)tau); + 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); - } + m_host.SetHoverHeight(0f, PIDHoverType.Ground, 0f); } public void llMinEventDelay(double delay) @@ -3598,15 +4082,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // 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; + SceneObjectGroup sog = m_host.ParentGroup; + if(sog == null || sog.IsDeleted) + return; - if (strength == 0 || pa == null || !pa.IsPhysical) + if (strength == 0 || !sog.UsesPhysics || sog.IsAttachment) { llSetLocalRot(target); } else { - m_host.RotLookAt(target, (float)strength, (float)damping); + sog.RotLookAt(target, (float)strength, (float)damping); } } @@ -3735,7 +4221,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | ScriptBaseClass.PERMISSION_CONTROL_CAMERA | ScriptBaseClass.PERMISSION_TRACK_CAMERA | - ScriptBaseClass.PERMISSION_ATTACH; + ScriptBaseClass.PERMISSION_ATTACH | + ScriptBaseClass.PERMISSION_OVERRIDE_ANIMATIONS; } else { @@ -3752,15 +4239,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (World.GetExtraSetting("auto_grant_attach_perms") == "true") implicitPerms = ScriptBaseClass.PERMISSION_ATTACH; } + if (World.GetExtraSetting("auto_grant_all_perms") == "true") + { + implicitPerms = perm; + } } 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_host.TaskInventory.LockItemsForWrite(true); + m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID; + m_host.TaskInventory[m_item.ItemID].PermsMask = perm; + m_host.TaskInventory.LockItemsForWrite(false); m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams( "run_time_permissions", new Object[] { @@ -3771,7 +4261,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } ScenePresence presence = World.GetScenePresence(agentID); - + if (presence != null) { // If permissions are being requested from an NPC and were not implicitly granted above then @@ -3804,11 +4294,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!m_waitingForScriptAnswer) { - lock (m_host.TaskInventory) - { - m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID; - m_host.TaskInventory[m_item.ItemID].PermsMask = 0; - } + m_host.TaskInventory.LockItemsForWrite(true); + m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID; + m_host.TaskInventory[m_item.ItemID].PermsMask = 0; + m_host.TaskInventory.LockItemsForWrite(false); presence.ControllingClient.OnScriptAnswer += handleScriptAnswer; m_waitingForScriptAnswer=true; @@ -3837,14 +4326,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) llReleaseControls(); - lock (m_host.TaskInventory) - { - m_host.TaskInventory[m_item.ItemID].PermsMask = answer; - } + m_host.TaskInventory.LockItemsForWrite(true); + m_host.TaskInventory[m_item.ItemID].PermsMask = answer; + m_host.TaskInventory.LockItemsForWrite(false); - m_ScriptEngine.PostScriptEvent( - m_item.ItemID, - new EventParams("run_time_permissions", new Object[] { new LSL_Integer(answer) }, new DetectParams[0])); + m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams( + "run_time_permissions", new Object[] { + new LSL_Integer(answer) }, + new DetectParams[0])); } public LSL_String llGetPermissionsKey() @@ -3883,15 +4372,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llSetLinkColor(int linknumber, LSL_Vector color, int face) { List parts = GetLinkParts(linknumber); - - foreach (SceneObjectPart part in parts) - part.SetFaceColorAlpha(face, color, null); + if (parts.Count > 0) + { + try + { + foreach (SceneObjectPart part in parts) + part.SetFaceColorAlpha(face, color, null); + } + finally { } + } } public void llCreateLink(string target, int parent) { m_host.AddScriptLPS(1); + UUID targetID; + + if (!UUID.TryParse(target, out targetID)) + return; + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 && !m_automaticLinkPermission) { @@ -3907,9 +4407,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID targetID; if (!UUID.TryParse(target, out targetID)) - return; + return; SceneObjectPart targetPart = World.GetSceneObjectPart((UUID)targetID); + if (targetPart == null) + return; if (targetPart.ParentGroup.AttachmentPoint != 0) return; // Fail silently if attached @@ -3919,24 +4421,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SceneObjectGroup parentPrim = null, childPrim = null; - if (targetPart != null) + if (parent != 0) { - 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 = 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; @@ -3949,6 +4449,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (client != null) parentPrim.SendPropertiesToClient(client); + + ScriptSleep(m_sleepMsOnCreateLink); } public void llBreakLink(int linknum) @@ -4005,10 +4507,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Restructuring Multiple Prims. List parts = new List(parentPrim.Parts); parts.Remove(parentPrim.RootPart); - foreach (SceneObjectPart part in parts) + if (parts.Count > 0) { - parentPrim.DelinkFromGroup(part.LocalId, true); - } + try + { + foreach (SceneObjectPart part in parts) + { + parentPrim.DelinkFromGroup(part.LocalId, true); + } + } + finally { } + } + parentPrim.HasGroupChanged = true; parentPrim.ScheduleGroupForFullUpdate(); parentPrim.TriggerScriptChangedEvent(Changed.LINK); @@ -4017,12 +4527,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { SceneObjectPart newRoot = parts[0]; parts.Remove(newRoot); - foreach (SceneObjectPart part in parts) + + try { - // Required for linking - part.ClearUpdateSchedule(); - newRoot.ParentGroup.LinkToGroup(part.ParentGroup); + foreach (SceneObjectPart part in parts) + { + part.ClearUpdateSchedule(); + newRoot.ParentGroup.LinkToGroup(part.ParentGroup); + } } + finally { } + newRoot.ParentGroup.HasGroupChanged = true; newRoot.ParentGroup.ScheduleGroupForFullUpdate(); } @@ -4043,13 +4558,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 + TaskInventoryItem item = m_item; + + if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 && !m_automaticLinkPermission) { - Error("llBreakAllLinks", "PERMISSION_CHANGE_LINKS permission not set"); + Error("llBreakAllLinks","Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); return; } - BreakAllLinks(); } @@ -4074,13 +4590,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llGetLinkKey(int linknum) { m_host.AddScriptLPS(1); + SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum); + if (part != null) + { + return part.UUID.ToString(); + } + else + { + if (linknum > m_host.ParentGroup.PrimCount || (linknum == 1 && m_host.ParentGroup.PrimCount == 1)) + { + linknum -= (m_host.ParentGroup.PrimCount) + 1; - ISceneEntity entity = GetLinkEntity(m_host, linknum); + if (linknum < 0) + return UUID.Zero.ToString(); - if (entity != null) - return entity.UUID.ToString(); - else - return ScriptBaseClass.NULL_KEY; + List avatars = GetLinkAvatars(ScriptBaseClass.LINK_SET); + if (avatars.Count > linknum) + { + return avatars[linknum].UUID.ToString(); + } + } + return UUID.Zero.ToString(); + } } /// @@ -4139,17 +4670,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); int count = 0; - lock (m_host.TaskInventory) + m_host.TaskInventory.LockItemsForRead(true); + foreach (KeyValuePair inv in m_host.TaskInventory) { - foreach (KeyValuePair inv in m_host.TaskInventory) + if (inv.Value.Type == type || type == -1) { - if (inv.Value.Type == type || type == -1) - { - count = count + 1; - } + count = count + 1; } } + m_host.TaskInventory.LockItemsForRead(false); return count; } @@ -4158,16 +4688,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); ArrayList keys = new ArrayList(); - lock (m_host.TaskInventory) + m_host.TaskInventory.LockItemsForRead(true); + foreach (KeyValuePair inv in m_host.TaskInventory) { - foreach (KeyValuePair inv in m_host.TaskInventory) + if (inv.Value.Type == type || type == -1) { - if (inv.Value.Type == type || type == -1) - { - keys.Add(inv.Value.Name); - } + keys.Add(inv.Value.Name); } } + m_host.TaskInventory.LockItemsForRead(false); if (keys.Count == 0) { @@ -4237,35 +4766,49 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } + // destination is an avatar string message; InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId, out message); if (agentItem == null) { - llSay(0, message); + llSay(0, message); return; } - if (m_TransferModule != null) - { - byte[] bucket = new byte[1]; - bucket[0] = (byte)item.Type; + byte[] bucket = new byte[1]; + bucket[0] = (byte)item.Type; + //byte[] objBytes = agentItem.ID.GetBytes(); + //Array.Copy(objBytes, 0, bucket, 1, 16); + + 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); - 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); + ScenePresence sp; - m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); + if (World.TryGetScenePresence(destId, out sp)) + { + sp.ControllingClient.SendInstantMessage(msg); + } + else + { + if (m_TransferModule != null) + m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); } + + //This delay should only occur when giving inventory to avatars. + ScriptSleep(m_sleepMsOnGiveInventory); } } + [DebuggerNonUserCode] public void llRemoveInventory(string name) { m_host.AddScriptLPS(1); @@ -4285,20 +4828,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { 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); - + data = Util.StringToBytes256(text); + text = Util.UTF8.GetString(data); 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) @@ -4320,14 +4853,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - UUID uuid = (UUID)id; - PresenceInfo pinfo = null; - UserAccount account; - - UserInfoCacheEntry ce; - - lock (m_userInfoCache) + UUID uuid; + if (UUID.TryParse(id, out uuid)) { + PresenceInfo pinfo = null; + UserAccount account; + + UserInfoCacheEntry ce; if (!m_userInfoCache.TryGetValue(uuid, out ce)) { account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid); @@ -4353,7 +4885,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ce.time = Util.EnvironmentTickCount(); ce.account = account; ce.pinfo = pinfo; - m_userInfoCache[uuid] = ce; } else @@ -4362,77 +4893,78 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return UUID.Zero.ToString(); account = ce.account; + pinfo = ce.pinfo; + } - if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) - >= LlRequestAgentDataCacheTimeoutMs) + 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) { - PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() }); - if (pinfos != null && pinfos.Length > 0) + foreach (PresenceInfo p in pinfos) { - foreach (PresenceInfo p in pinfos) + if (p.RegionID != UUID.Zero) { - if (p.RegionID != UUID.Zero) - { - pinfo = p; - } + pinfo = p; } } - else - { - pinfo = null; - } - - ce.time = Util.EnvironmentTickCount(); - ce.pinfo = pinfo; } else - { - pinfo = ce.pinfo; - } + pinfo = null; + + ce.time = Util.EnvironmentTickCount(); + ce.pinfo = pinfo; } - } - string reply = String.Empty; + 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 - } + switch (data) + { + case ScriptBaseClass.DATA_ONLINE: // DATA_ONLINE (0|1) + if (pinfo != null && pinfo.RegionID != UUID.Zero) + reply = "1"; + else + reply = "0"; + break; + case ScriptBaseClass.DATA_NAME: // DATA_NAME (First Last) + reply = account.FirstName + " " + account.LastName; + break; + case ScriptBaseClass.DATA_BORN: // 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: // 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: // DATA_PAYINFO (0|1|2|3) + reply = "0"; + break; + default: + return UUID.Zero.ToString(); // Raise no event + } - UUID rq = UUID.Random(); + UUID rq = UUID.Random(); - UUID tid = AsyncCommands. - DataserverPlugin.RegisterRequest(m_host.LocalId, - m_item.ItemID, rq.ToString()); + UUID tid = AsyncCommands. + DataserverPlugin.RegisterRequest(m_host.LocalId, + m_item.ItemID, rq.ToString()); - AsyncCommands. - DataserverPlugin.DataserverReply(rq.ToString(), reply); + AsyncCommands. + DataserverPlugin.DataserverReply(rq.ToString(), reply); - return tid.ToString(); + ScriptSleep(m_sleepMsOnRequestAgentData); + return tid.ToString(); + } + else + { + Error("llRequestAgentData","Invalid UUID passed to llRequestAgentData."); + } + return ""; } public LSL_String llRequestInventoryData(string name) @@ -4464,10 +4996,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api reply); }); + ScriptSleep(m_sleepMsOnRequestInventoryData); return tid.ToString(); } } + ScriptSleep(m_sleepMsOnRequestInventoryData); return String.Empty; } @@ -4484,15 +5018,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (UUID.TryParse(agent, out agentId)) { ScenePresence presence = World.GetScenePresence(agentId); - if (presence != null) + if (presence != null && presence.PresenceType != PresenceType.Npc) { + // agent must not be a god + if (presence.GodController.UserLevel >= 200) return; + // agent must be over the owners land if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) { - World.TeleportClientHome(agentId, presence.ControllingClient); + if (!World.TeleportClientHome(agentId, presence.ControllingClient)) + { + // They can't be teleported home for some reason + GridRegion regionInfo = World.GridService.GetRegionByUUID(UUID.Zero, new UUID("2b02daac-e298-42fa-9a75-f488d37896e6")); + if (regionInfo != null) + { + World.RequestTeleportLocation( + presence.ControllingClient, regionInfo.RegionHandle, new Vector3(128, 128, 23), Vector3.Zero, + (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); + } + } } } } + + ScriptSleep(m_sleepMsOnSetDamage); } public void llTeleportAgent(string agent, string destination, LSL_Vector targetPos, LSL_Vector targetLookAt) @@ -4505,20 +5054,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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) + if (m_item.PermsGranter == agentId) + { + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TELEPORT) != 0) + { + DoLLTeleport(presence, destination, targetPos, targetLookAt); + } + } + + // agent must be wearing the object + if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID) { DoLLTeleport(presence, destination, targetPos, targetLookAt); } - else // or must be wearing the prim + else { - if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID) + // agent must not be a god + if (presence.IsViewerUIGod) return; + + // agent must be over the owners land + ILandObject agentLand = World.LandChannel.GetLandObject(presence.AbsolutePosition); + ILandObject objectLand = World.LandChannel.GetLandObject(m_host.AbsolutePosition); + if (m_host.OwnerID == objectLand.LandData.OwnerID && m_host.OwnerID == agentLand.LandData.OwnerID) { DoLLTeleport(presence, destination, targetPos, targetLookAt); } @@ -4536,23 +5096,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (UUID.TryParse(agent, out agentId)) { + // This function is owner only! + if (m_host.OwnerID != agentId) + return; + ScenePresence presence = World.GetScenePresence(agentId); - if (presence != null && presence.PresenceType != PresenceType.Npc) + + if (presence == null || presence.PresenceType == PresenceType.Npc) + return; + + // Can't TP sitting avatars + if (presence.ParentID != 0) // Sitting + return; + + if (m_item.PermsGranter == agentId) { - // agent must not be a god - if (presence.GodLevel >= 200) return; + // If attached using llAttachToAvatarTemp, cowardly refuse + if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.ParentGroup.FromItemID == UUID.Zero) + 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_item.PermsMask & ScriptBaseClass.PERMISSION_TELEPORT) != 0) { - if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID) - { - World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation); - } + World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation); } } } @@ -4601,13 +5166,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { Error("llTextBox", "Empty message"); } - else if (message.Length > 512) + else if (Encoding.UTF8.GetByteCount(message) > 512) { - Error("llTextBox", "Message more than 512 characters"); + Error("llTextBox", "Message longer than 512 bytes"); } else { dm.SendTextBoxToUser(av, message, chatChannel, m_host.Name, m_host.UUID, m_host.OwnerID); + ScriptSleep(m_sleepMsOnTextBox); } } @@ -4625,9 +5191,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); + if(impact_sound == "") + { + m_host.CollisionSoundVolume = (float)impact_volume; + m_host.CollisionSound = m_host.invalidCollisionSoundUUID; + m_host.CollisionSoundType = -1; // disable all sounds + m_host.aggregateScriptEvents(); + return; + } + // TODO: Parameter check logic required. - m_host.CollisionSound = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound); - m_host.CollisionSoundVolume = (float)impact_volume; + UUID soundId = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound); + if(soundId != UUID.Zero) + { + m_host.CollisionSound = soundId; + m_host.CollisionSoundVolume = (float)impact_volume; + m_host.CollisionSoundType = 1; + } + else + m_host.CollisionSoundType = -1; + + m_host.aggregateScriptEvents(); } public LSL_String llGetAnimation(string id) @@ -4641,14 +5225,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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; +// if (presence.SitGround) +// return "Sitting on Ground"; +// if (presence.ParentID != 0 || presence.ParentUUID != UUID.Zero) +// return "Sitting"; + + string movementAnimation = presence.Animator.CurrentMovementAnimation; + string lslMovementAnimation; + + if (MovementAnimationsForLSL.TryGetValue(movementAnimation, out lslMovementAnimation)) + return lslMovementAnimation; } } @@ -4712,7 +5300,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; // Pushee is in GodMode this pushing object isn't owned by them - if (avatar.GodLevel > 0 && m_host.OwnerID != targetID) + if (avatar.IsViewerUIGod && m_host.OwnerID != targetID) return; pusheeav = avatar; @@ -4796,7 +5384,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { float distance = (PusheePos - m_host.AbsolutePosition).Length(); float distance_term = distance * distance * distance; // Script Energy - float pusher_mass = m_host.GetMass(); + // use total object mass and not part + float pusher_mass = m_host.ParentGroup.GetMass(); float PUSH_ATTENUATION_DISTANCE = 17f; float PUSH_ATTENUATION_SCALE = 5f; @@ -4831,7 +5420,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (local != 0) { - applied_linear_impulse *= m_host.GetWorldRotation(); +// applied_linear_impulse *= m_host.GetWorldRotation(); + applied_linear_impulse *= pusheeav.GetWorldRotation(); } pa.AddForce(applied_linear_impulse, true); @@ -4891,20 +5481,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - return GetNumberOfSides(m_host); + return m_host.GetNumberOfSides(); } 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; + return part.GetNumberOfSides(); } @@ -4959,20 +5541,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (Math.Abs(rot.s) > 1) // normalization needed - rot.Normalize(); + 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); - } + if (s < 1e-8) + return new LSL_Vector(0, 0, 0); + + double invS = 1.0 / s; + if (rot.s < 0) + invS = -invS; + return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS); } @@ -4981,11 +5559,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (Math.Abs(rot.s) > 1) // normalization needed - rot.Normalize(); + rot.Normalize(); double angle = 2 * Math.Acos(rot.s); - if (angle > Math.PI) + if (angle > Math.PI) angle = 2 * Math.PI - angle; return angle; @@ -5185,43 +5762,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (src == null) - { - return 0; - } - else - { - return src.Length; - } + 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; - } + + object item = src.Data[index]; // 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) - { + if (item is LSL_Vector || item 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()); + if (item is LSL_Integer) + return (LSL_Integer)item; + else if (item is LSL_Float) + return Convert.ToInt32(((LSL_Float)item).value);; + return new LSL_Integer(item.ToString()); } catch (FormatException) { @@ -5233,38 +5799,50 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); if (index < 0) - { index = src.Length + index; - } + if (index >= src.Length || index < 0) - { - return 0.0; - } + return 0; + + object item = src.Data[index]; // Vectors & Rotations always return zero in SL - else if (src.Data[index] is LSL_Vector || - src.Data[index] is LSL_Rotation) - { + if(item is LSL_Vector || item is LSL_Rotation) return 0; - } + // valid keys seem to get parsed as integers then converted to floats - else + if (item is LSL_Key) { 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); - } + string s = item.ToString(); + if(UUID.TryParse(s, out uuidt)) + return Convert.ToDouble(new LSL_Integer(s).value); +// we can't do this because a string is also a LSL_Key for now :( +// else +// return 0; } + 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]); + if (item is LSL_Integer) + return Convert.ToDouble(((LSL_Integer)item).value); + else if (item is LSL_Float) + return Convert.ToDouble(((LSL_Float)item).value); + else if (item is LSL_String) + { + string str = ((LSL_String)item).m_string; + Match m = Regex.Match(str, "^\\s*(-?\\+?[,0-9]+\\.?[0-9]*)"); + if (m != Match.Empty) + { + str = m.Value; + double d = 0.0; + if (!Double.TryParse(str, out d)) + return 0.0; + return d; + } + return 0.0; + } + return Convert.ToDouble(item); } catch (FormatException) { @@ -5276,13 +5854,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { 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(); } @@ -5290,14 +5866,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); if (index < 0) - { index = src.Length + index; - } if (index >= src.Length || index < 0) - { - return ""; - } + return String.Empty; + + object item = src.Data[index]; // SL spits out an empty string for types other than key & string // At the time of patching, LSL_Key is currently LSL_String, @@ -5306,31 +5880,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // 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")) + if (!(item is LSL_String || + item is LSL_Key || + item.ToString() == "00000000-0000-0000-0000-000000000000")) { - return ""; + return String.Empty; } - return src.Data[index].ToString(); + return item.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]; - } + + object item = src.Data[index]; + + if (item.GetType() == typeof(LSL_Vector)) + return (LSL_Vector)item; // SL spits always out ZERO_VECTOR for anything other than // strings or vectors. Although keys always return ZERO_VECTOR, @@ -5338,28 +5910,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // 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()); - } + if(item is LSL_Vector) + return (LSL_Vector) item; + + if (item is LSL_String) + return new LSL_Vector(item.ToString()); + + return new LSL_Vector(0, 0, 0); } 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); - } + + object item = src.Data[index]; // SL spits always out ZERO_ROTATION for anything other than // strings or vectors. Although keys always return ZERO_ROTATION, @@ -5367,19 +5936,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // 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 - { + + if (item.GetType() == typeof(LSL_Rotation)) + return (LSL_Rotation)item; + + if (item is LSL_String) return new LSL_Rotation(src.Data[index].ToString()); - } + + return new LSL_Rotation(0, 0, 0, 1); } public LSL_List llList2List(LSL_List src, int start, int end) @@ -5567,7 +6131,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - else { + else + { object[] array = new object[src.Length]; Array.Copy(src.Data, 0, array, 0, src.Length); result = new LSL_List(array); @@ -5674,7 +6239,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llGetRegionAgentCount() { m_host.AddScriptLPS(1); - return new LSL_Integer(World.GetRootAgentCount()); + + int count = 0; + World.ForEachRootScenePresence(delegate(ScenePresence sp) { + count++; + }); + + return new LSL_Integer(count); } public LSL_Vector llGetRegionCorner() @@ -5742,10 +6313,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IUrlModule UrlModule = World.RequestModuleInterface(); return UrlModule.ExternalHostNameForLSL; } + else if (name == "region_max_prims") + { + return World.RegionInfo.ObjectCapacity.ToString(); + } + else if (name == "region_object_bonus") + { + return World.RegionInfo.RegionSettings.ObjectBonus.ToString(); + } else { return ""; } + } /// @@ -5821,17 +6401,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { for (int i = 0; i < length; i++) { + int needle = llGetListEntryType(test, 0).value; + int haystack = llGetListEntryType(src, i).value; + // Why this piece of insanity? This is because most script constants are C# value types (e.g. int) // rather than wrapped LSL types. Such a script constant does not have int.Equal(LSL_Integer) code // and so the comparison fails even if the LSL_Integer conceptually has the same value. // Therefore, here we test Equals on both the source and destination objects. // However, a future better approach may be use LSL struct script constants (e.g. LSL_Integer(1)). - if (src.Data[i].Equals(test.Data[0]) || test.Data[0].Equals(src.Data[i])) + if ((needle == haystack) && (src.Data[i].Equals(test.Data[0]) || test.Data[0].Equals(src.Data[i]))) { int j; for (j = 1; j < test.Length; j++) - if (!(src.Data[i+j].Equals(test.Data[j]) || test.Data[j].Equals(src.Data[i+j]))) + { + needle = llGetListEntryType(test, j).value; + haystack = llGetListEntryType(src, i+j).value; + + if ((needle != haystack) || (!(src.Data[i+j].Equals(test.Data[j]) || test.Data[j].Equals(src.Data[i+j])))) break; + } if (j == test.Length) { @@ -5869,64 +6457,61 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - // edge will be used to pass the Region Coordinates offset - // we want to check for a neighboring sim - LSL_Vector edge = new LSL_Vector(0, 0, 0); + if(dir.x == 0 && dir.y == 0) + return 1; // SL wiki + + float rsx = World.RegionInfo.RegionSizeX; + float rsy = World.RegionInfo.RegionSizeY; + + // can understand what sl does if position is not in region, so do something :) + float px = (float)Util.Clamp(pos.x, 0.5, rsx - 0.5); + float py = (float)Util.Clamp(pos.y, 0.5, rsy - 0.5); + + float ex, ey; if (dir.x == 0) { - if (dir.y == 0) - { - // Direction vector is 0,0 so return - // false since we're staying in the sim - return 0; - } - else - { - // Y is the only valid direction - edge.y = dir.y / Math.Abs(dir.y); - } + ex = px; + ey = dir.y > 0 ? rsy + 1.0f : -1.0f; + } + else if(dir.y == 0) + { + ex = dir.x > 0 ? rsx + 1.0f : -1.0f; + ey = py; } else { - LSL_Float mag; - if (dir.x > 0) - { - mag = (World.RegionInfo.RegionSizeX - pos.x) / dir.x; - } - else - { - mag = (pos.x/dir.x); - } - - mag = Math.Abs(mag); + float dx = (float) dir.x; + float dy = (float) dir.y; - edge.y = pos.y + (dir.y * mag); + float t1 = dx * dx + dy * dy; + t1 = (float)Math.Sqrt(t1); + dx /= t1; + dy /= t1; - if (edge.y > World.RegionInfo.RegionSizeY || edge.y < 0) - { - // Y goes out of bounds first - edge.y = dir.y / Math.Abs(dir.y); - } + if(dx > 0) + t1 = (rsx + 1f - px)/dx; else - { - // X goes out of bounds first or its a corner exit - edge.y = 0; - edge.x = dir.x / Math.Abs(dir.x); - } - } + t1 = -(px + 1f)/dx; - List neighbors = World.GridService.GetNeighbours(World.RegionInfo.ScopeID, World.RegionInfo.RegionID); + float t2; + if(dy > 0) + t2 = (rsy + 1f - py)/dy; + else + t2 = -(py + 1f)/dy; - uint neighborX = World.RegionInfo.RegionLocX + (uint)dir.x; - uint neighborY = World.RegionInfo.RegionLocY + (uint)dir.y; + if(t1 > t2) + t1 = t2; - foreach (GridRegion sri in neighbors) - { - if (sri.RegionCoordX == neighborX && sri.RegionCoordY == neighborY) - return 0; + ex = px + t1 * dx; + ey = py + t1 * dy; } + ex += World.RegionInfo.WorldLocX; + ey += World.RegionInfo.WorldLocY; + + if(World.GridService.GetRegionByPosition(World.RegionInfo.ScopeID, (int)ex, (int)ey) != null) + return 0; return 1; } @@ -5980,6 +6565,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api flags |= ScriptBaseClass.AGENT_AWAY; } + UUID busy = new UUID("efcf670c-2d18-8128-973a-034ebc806b67"); + UUID[] anims = agent.Animator.GetAnimationArray(); + if (Array.Exists(anims, a => { return a == busy; })) + { + flags |= ScriptBaseClass.AGENT_BUSY; + } + // seems to get unset, even if in mouselook, when avatar is sitting on a prim??? if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) { @@ -6027,6 +6619,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api flags |= ScriptBaseClass.AGENT_SITTING; } + if (agent.Appearance.VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MALE] > 0) + { + flags |= ScriptBaseClass.AGENT_MALE; + } + return flags; } @@ -6056,11 +6653,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// AGENT_LIST_PARCEL - all in the same parcel as the scripted object /// AGENT_LIST_PARCEL_OWNER - all in any parcel owned by the owner of the /// current parcel. + /// AGENT_LIST_EXCLUDENPC ignore NPCs (bit mask) /// public LSL_List llGetAgentList(LSL_Integer scope, LSL_List options) { m_host.AddScriptLPS(1); + // do our bit masks part + bool noNPC = (scope & ScriptBaseClass.AGENT_LIST_EXCLUDENPC) !=0; + + // remove bit masks part + scope &= ~ ScriptBaseClass.AGENT_LIST_EXCLUDENPC; + // the constants are 1, 2 and 4 so bits are being set, but you // get an error "INVALID_SCOPE" if it is anything but 1, 2 and 4 bool regionWide = scope == ScriptBaseClass.AGENT_LIST_REGION; @@ -6101,8 +6705,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.ForEachRootScenePresence( delegate (ScenePresence ssp) { + if(noNPC && ssp.IsNPC) + return; + // Gods are not listed in SL - if (!ssp.IsDeleted && ssp.GodLevel == 0.0 && !ssp.IsChildAgent) + if (!ssp.IsDeleted && !ssp.IsViewerUIGod && !ssp.IsChildAgent) { if (!regionWide) { @@ -6135,6 +6742,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); m_host.AdjustSoundGain(volume); + ScriptSleep(m_sleepMsOnAdjustSoundVolume); } public void llSetSoundRadius(double radius) @@ -6180,11 +6788,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api List parts = GetLinkParts(linknumber); - foreach (SceneObjectPart part in parts) + try { - SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate); + foreach (SceneObjectPart part in parts) + { + SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate); + } } - } + finally + { + } + } private void SetTextureAnim(SceneObjectPart part, int mode, int face, int sizex, int sizey, double start, double length, double rate) { @@ -6236,10 +6850,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_host.OwnerID == land.LandData.OwnerID) { - World.TeleportClientHome(agentID, presence.ControllingClient); + Vector3 p = World.GetNearestAllowedPosition(presence, land); + presence.TeleportOnEject(p); + presence.ControllingClient.SendAlertMessage("You have been ejected from this land"); } } } + ScriptSleep(m_sleepMsOnEjectFromLand); + } + + public LSL_List llParseString2List(string str, LSL_List separators, LSL_List in_spacers) + { + return ParseString2List(str, separators, in_spacers, false); } public LSL_Integer llOverMyLand(string id) @@ -6294,26 +6916,59 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - agentSize = GetAgentSize(avatar); +// agentSize = new LSL_Vector(0.45f, 0.6f, avatar.Appearance.AvatarHeight); + Vector3 s = avatar.Appearance.AvatarSize; + agentSize = new LSL_Vector(s.X, s.Y, s.Z); } - return agentSize; } - public LSL_Integer llSameGroup(string agent) + public LSL_Integer llSameGroup(string id) { m_host.AddScriptLPS(1); - UUID agentId = new UUID(); - if (!UUID.TryParse(agent, out agentId)) - return new LSL_Integer(0); - ScenePresence presence = World.GetScenePresence(agentId); - if (presence == null || presence.IsChildAgent) // Return flase for child agents + UUID uuid = new UUID(); + if (!UUID.TryParse(id, out uuid)) return new LSL_Integer(0); - IClientAPI client = presence.ControllingClient; - if (m_host.GroupID == client.ActiveGroupId) + + // Check if it's a group key + if (uuid == m_host.ParentGroup.RootPart.GroupID) return new LSL_Integer(1); - else + + // Handle object case + SceneObjectPart part = World.GetSceneObjectPart(uuid); + if (part != null) + { + + if(part.ParentGroup.IsAttachment) + { + uuid = part.ParentGroup.AttachedAvatar; + } + else + { + // This will handle both deed and non-deed and also the no + // group case + if (part.ParentGroup.RootPart.GroupID == m_host.ParentGroup.RootPart.GroupID) + return new LSL_Integer(1); + + return new LSL_Integer(0); + } + } + + // Handle the case where id names an avatar + ScenePresence presence = World.GetScenePresence(uuid); + if (presence != null) + { + if (presence.IsChildAgent) + return new LSL_Integer(0); + + IClientAPI client = presence.ControllingClient; + if (m_host.ParentGroup.RootPart.GroupID == client.ActiveGroupId) + return new LSL_Integer(1); + return new LSL_Integer(0); + } + + return new LSL_Integer(0); } public void llUnSit(string id) @@ -6441,6 +7096,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return m_host.ParentGroup.AttachmentPoint; } + public LSL_List llGetAttachedList(string id) + { + m_host.AddScriptLPS(1); + + ScenePresence av = World.GetScenePresence((UUID)id); + + if (av == null || av.IsDeleted) + return new LSL_List("NOT_FOUND"); + + if (av.IsChildAgent || av.IsInTransit) + return new LSL_List("NOT_ON_REGION"); + + LSL_List AttachmentsList = new LSL_List(); + List Attachments; + + Attachments = av.GetAttachments(); + + foreach (SceneObjectGroup Attachment in Attachments) + { + if(Attachment.HasPrivateAttachmentPoint) + continue; + AttachmentsList.Add(new LSL_Key(Attachment.UUID.ToString())); + } + + return AttachmentsList; + } + public virtual LSL_Integer llGetFreeMemory() { m_host.AddScriptLPS(1); @@ -7127,6 +7809,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected void SitTarget(SceneObjectPart part, LSL_Vector offset, LSL_Rotation rot) { + // LSL quaternions can normalize to 0, normal Quaternions can't. + if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0) + rot.s = 1; // ZERO_ROTATION = 0,0,0,1 + part.SitTargetPosition = offset; part.SitTargetOrientation = rot; part.ParentGroup.HasGroupChanged = true; @@ -7166,11 +7852,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); if(linknum == ScriptBaseClass.LINK_SET || - linknum == ScriptBaseClass.LINK_ALL_CHILDREN || - linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString(); + linknum == ScriptBaseClass.LINK_ALL_CHILDREN || + linknum == ScriptBaseClass.LINK_ALL_OTHERS || + linknum == 0) + return UUID.Zero.ToString(); List parts = GetLinkParts(linknum); - if (parts.Count == 0) return UUID.Zero.ToString(); + if (parts.Count == 0) + return UUID.Zero.ToString(); return parts[0].SitTargetAvatar.ToString(); } @@ -7181,7 +7870,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID key; ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); - if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) + if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManagePasses, false)) { int expires = 0; if (hours != 0) @@ -7214,6 +7903,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land); } } + ScriptSleep(m_sleepMsOnAddToLandPassList); } public void llSetTouchText(string text) @@ -7295,7 +7985,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llScriptDanger(LSL_Vector pos) { m_host.AddScriptLPS(1); - bool result = World.ScriptDanger(m_host.LocalId, pos); + bool result = World.LSLScriptDanger(m_host, pos); if (result) { return 1; @@ -7304,7 +7994,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { return 0; } - } public void llDialog(string avatar, string message, LSL_List buttons, int chat_channel) @@ -7321,35 +8010,51 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Error("llDialog", "First parameter must be a key"); return; } - if (buttons.Length < 1) + + int length = buttons.Length; + if (length < 1) { Error("llDialog", "At least 1 button must be shown"); return; } - if (buttons.Length > 12) + if (length > 12) { Error("llDialog", "No more than 12 buttons can be shown"); return; } - string[] buts = new string[buttons.Length]; - for (int i = 0; i < buttons.Length; i++) + + if (message == string.Empty) + { + Error("llDialog", "Empty message"); + } + else if (Encoding.UTF8.GetByteCount(message) > 512) + { + Error("llDialog", "Message longer than 512 bytes"); + } + + string[] buts = new string[length]; + for (int i = 0; i < length; i++) { if (buttons.Data[i].ToString() == String.Empty) { Error("llDialog", "Button label cannot be blank"); return; } +/* if (buttons.Data[i].ToString().Length > 24) { Error("llDialog", "Button label cannot be longer than 24 characters"); return; } +*/ buts[i] = buttons.Data[i].ToString(); } dm.SendDialogToUser( av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts); + + ScriptSleep(m_sleepMsOnDialog); } public void llVolumeDetect(int detect) @@ -7364,6 +8069,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); Deprecated("llRemoteLoadScript", "Use llRemoteLoadScriptPin instead"); + ScriptSleep(m_sleepMsOnRemoteLoadScript); } public void llSetRemoteScriptAccessPin(int pin) @@ -7400,8 +8106,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - // the rest of the permission checks are done in RezScript, so check the pin there as well - World.RezScriptFromPrim(item.ItemID, m_host, destId, pin, running, start_param); + SceneObjectPart dest = World.GetSceneObjectPart(destId); + if (dest != null) + { + if ((item.BasePermissions & (uint)PermissionMask.Transfer) != 0 || dest.ParentGroup.RootPart.OwnerID == m_host.ParentGroup.RootPart.OwnerID) + { + // the rest of the permission checks are done in RezScript, so check the pin there as well + World.RezScriptFromPrim(item.ItemID, m_host, destId, pin, running, start_param); + + if ((item.BasePermissions & (uint)PermissionMask.Copy) == 0) + m_host.Inventory.RemoveInventoryItem(item.ItemID); + } + } + // this will cause the delay even if the script pin or permissions were wrong - seems ok + ScriptSleep(m_sleepMsOnRemoteLoadScriptPin); } public void llOpenRemoteDataChannel() @@ -7432,12 +8150,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams("remote_data", resobj, new DetectParams[0])); } + ScriptSleep(m_sleepMsOnOpenRemoteDataChannel); } public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata) { m_host.AddScriptLPS(1); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); + ScriptSleep(m_sleepMsOnSendRemoteData); if (xmlrpcMod == null) return ""; return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString(); @@ -7449,6 +8169,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); if (xmlrpcMod != null) xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata); + ScriptSleep(m_sleepMsOnRemoteDataReply); } public void llCloseRemoteDataChannel(string channel) @@ -7464,24 +8185,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); if (xmlrpcMod != null) xmlrpcMod.CloseXMLRPCChannel((UUID)channel); + ScriptSleep(m_sleepMsOnCloseRemoteDataChannel); } public LSL_String llMD5String(string src, int nonce) { m_host.AddScriptLPS(1); - return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString())); + return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString()), Encoding.UTF8); } public LSL_String llSHA1String(string src) { m_host.AddScriptLPS(1); - return Util.SHA1Hash(src).ToLower(); + return Util.SHA1Hash(src, Encoding.UTF8).ToLower(); } protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve) { float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return shapeBlock; if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE && @@ -7586,6 +8310,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Prim type box, cylinder and prism. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock; @@ -7639,6 +8366,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Prim type sphere. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte profileshape, byte pathcurve) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + ObjectShapePacket.ObjectDataBlock shapeBlock; shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); @@ -7685,6 +8415,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Prim type torus, tube and ring. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte profileshape, byte pathcurve) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock; @@ -7820,6 +8553,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Prim type sculpt. protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type, byte pathcurve) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); UUID sculptId; @@ -7842,7 +8578,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api type != (ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS | flag)) { // default - type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE; + type = type | (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE; } part.Shape.SetSculptProperties((byte)type, sculptId); @@ -7855,6 +8591,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); SetLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams"); + + ScriptSleep(m_sleepMsOnSetPrimitiveParams); } public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) @@ -7862,6 +8600,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); SetLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams"); + + ScriptSleep(m_sleepMsOnSetLinkPrimitiveParams); } public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules) @@ -7871,9 +8611,51 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SetLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast"); } - protected void SetLinkPrimParams(int linknumber, LSL_List rules, string originFunc) + private void SetLinkPrimParams(int linknumber, LSL_List rules, string originFunc) { - SetEntityParams(GetLinkEntities(linknumber), rules, originFunc); + List parts = new List(); + List prims = GetLinkParts(linknumber); + List avatars = GetLinkAvatars(linknumber); + foreach (SceneObjectPart p in prims) + parts.Add(p); + foreach (ScenePresence p in avatars) + parts.Add(p); + + LSL_List remaining = new LSL_List(); + uint rulesParsed = 0; + + if (parts.Count > 0) + { + foreach (object part in parts) + { + if (part is SceneObjectPart) + remaining = SetPrimParams((SceneObjectPart)part, rules, originFunc, ref rulesParsed); + else + remaining = SetPrimParams((ScenePresence)part, rules, originFunc, ref rulesParsed); + } + + while (remaining.Length > 2) + { + linknumber = remaining.GetLSLIntegerItem(0); + rules = remaining.GetSublist(1, -1); + parts.Clear(); + prims = GetLinkParts(linknumber); + avatars = GetLinkAvatars(linknumber); + foreach (SceneObjectPart p in prims) + parts.Add(p); + foreach (ScenePresence p in avatars) + parts.Add(p); + + remaining = new LSL_List(); + foreach (object part in parts) + { + if (part is SceneObjectPart) + remaining = SetPrimParams((SceneObjectPart)part, rules, originFunc, ref rulesParsed); + else + remaining = SetPrimParams((ScenePresence)part, rules, originFunc, ref rulesParsed); + } + } + } } protected void SetEntityParams(List entities, LSL_List rules, string originFunc) @@ -8052,11 +8834,81 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public LSL_List llGetPhysicsMaterial() + { + LSL_List result = new LSL_List(); + + result.Add(new LSL_Float(m_host.GravityModifier)); + result.Add(new LSL_Float(m_host.Restitution)); + result.Add(new LSL_Float(m_host.Friction)); + result.Add(new LSL_Float(m_host.Density)); + + return result; + } + + private void SetPhysicsMaterial(SceneObjectPart part, int material_bits, + float material_density, float material_friction, + float material_restitution, float material_gravity_modifier) + { + ExtraPhysicsData physdata = new ExtraPhysicsData(); + physdata.PhysShapeType = (PhysShapeType)part.PhysicsShapeType; + physdata.Density = part.Density; + physdata.Friction = part.Friction; + physdata.Bounce = part.Restitution; + physdata.GravitationModifier = part.GravityModifier; + + if ((material_bits & (int)ScriptBaseClass.DENSITY) != 0) + physdata.Density = material_density; + if ((material_bits & (int)ScriptBaseClass.FRICTION) != 0) + physdata.Friction = material_friction; + if ((material_bits & (int)ScriptBaseClass.RESTITUTION) != 0) + physdata.Bounce = material_restitution; + if ((material_bits & (int)ScriptBaseClass.GRAVITY_MULTIPLIER) != 0) + physdata.GravitationModifier = material_gravity_modifier; + + part.UpdateExtraPhysics(physdata); + } + + public void llSetPhysicsMaterial(int material_bits, + LSL_Float material_gravity_modifier, LSL_Float material_restitution, + LSL_Float material_friction, LSL_Float material_density) + { + SetPhysicsMaterial(m_host, material_bits, (float)material_density, (float)material_friction, (float)material_restitution, (float)material_gravity_modifier); + } + + // vector up using libomv (c&p from sop ) + // vector up rotated by r + private Vector3 Zrot(Quaternion r) + { + double x, y, z, m; + + m = r.X * r.X + r.Y * r.Y + r.Z * r.Z + r.W * r.W; + if (Math.Abs(1.0 - m) > 0.000001) + { + m = 1.0 / Math.Sqrt(m); + r.X *= (float)m; + r.Y *= (float)m; + r.Z *= (float)m; + r.W *= (float)m; + } + + x = 2 * (r.X * r.Z + r.Y * r.W); + y = 2 * (-r.X * r.W + r.Y * r.Z); + z = -r.X * r.X - r.Y * r.Y + r.Z * r.Z + r.W * r.W; + + return new Vector3((float)x, (float)y, (float)z); + } + protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules, string originFunc, ref uint rulesParsed) { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return new LSL_List(); + int idx = 0; int idxStart = 0; + SceneObjectGroup parentgrp = part.ParentGroup; + bool positionChanged = false; LSL_Vector currentPosition = GetPartLocalPos(part); @@ -8092,8 +8944,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POS_LOCAL: arg #{1} - parameter 1 must be vector", rulesParsed, idx - idxStart - 1)); return new LSL_List(); } + if (part.IsRoot && !part.ParentGroup.IsAttachment) + currentPosition = GetSetPosTarget(part, v, currentPosition, true); + else + currentPosition = GetSetPosTarget(part, v, currentPosition, false); positionChanged = true; - currentPosition = GetSetPosTarget(part, v, currentPosition); break; case ScriptBaseClass.PRIM_SIZE: @@ -8118,7 +8973,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_List(); } // try to let this work as in SL... - if (part.ParentID == 0) + if (part.ParentID == 0 || (part.ParentGroup != null && part == part.ParentGroup.RootPart)) { // special case: If we are root, rotate complete SOG to new rotation SetRot(part, q); @@ -9119,7 +9974,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; - case ScriptBaseClass.PRIM_TEMP_ON_REZ: + case (int)ScriptBaseClass.PRIM_PHYSICS_MATERIAL: + if (remain < 5) + return new LSL_List(); + + int material_bits = rules.GetLSLIntegerItem(idx++); + float material_density = (float)rules.GetLSLFloatItem(idx++); + float material_friction = (float)rules.GetLSLFloatItem(idx++); + float material_restitution = (float)rules.GetLSLFloatItem(idx++); + float material_gravity_modifier = (float)rules.GetLSLFloatItem(idx++); + + SetPhysicsMaterial(part, material_bits, material_density, material_friction, material_restitution, material_gravity_modifier); + + break; + + case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ: if (remain < 1) return new LSL_List(); string temp = rules.Data[idx++].ToString(); @@ -9290,6 +10159,53 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.UpdateSlice((float)slice.x, (float)slice.y); break; + case ScriptBaseClass.PRIM_SIT_TARGET: + if (remain < 3) + return new LSL_List(); + + int active; + try + { + active = rules.GetLSLIntegerItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 1 must be integer", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + LSL_Vector offset; + try + { + offset = rules.GetVector3Item(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + LSL_Rotation sitrot; + try + { + sitrot = rules.GetQuaternionItem(idx++); + } + catch(InvalidCastException) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 3 must be rotation", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } + + // not SL compatible since we don't have a independent flag to control active target but use the values of offset and rotation + if(active == 1) + { + if(offset.x == 0 && offset.y == 0 && offset.z == 0 && sitrot.s == 1.0) + offset.z = 1e-5f; // hack + SitTarget(part,offset,sitrot); + } + else if(active == 0) + SitTarget(part, Vector3.Zero , Quaternion.Identity); + + break; + case ScriptBaseClass.PRIM_LINK_TARGET: if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. return new LSL_List(); @@ -9313,14 +10229,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (part.ParentGroup.RootPart == part) { SceneObjectGroup parent = part.ParentGroup; - parent.UpdateGroupPosition(currentPosition); +// Util.FireAndForget(delegate(object x) { + parent.UpdateGroupPosition(currentPosition); +// }); } else { part.OffsetPosition = currentPosition; - SceneObjectGroup parent = part.ParentGroup; - parent.HasGroupChanged = true; - parent.ScheduleGroupForTerseUpdate(); +// SceneObjectGroup parent = part.ParentGroup; +// parent.HasGroupChanged = true; +// parent.ScheduleGroupForTerseUpdate(); + part.ScheduleTerseUpdate(); } } } @@ -9368,7 +10287,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } break; - case ScriptBaseClass.PRIM_ROTATION: + case ScriptBaseClass.PRIM_ROTATION: if (remain < 1) return new LSL_List(); @@ -9387,7 +10306,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SceneObjectPart parentPart = sp.ParentPart; if (parentPart != null) - sp.Rotation = m_host.GetWorldRotation() * inRot; + sp.Rotation = m_host.GetWorldRotation() * inRot; break; @@ -9431,7 +10350,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api catch (InvalidCastException e) { Error( - originFunc, + originFunc, string.Format("Error running rule #{0}: arg #{1} - ", rulesParsed, idx - idxStart) + e.Message); } @@ -9472,9 +10391,104 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llXorBase64Strings(string str1, string str2) { + int padding = 0; + + string b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + ScriptSleep(300); m_host.AddScriptLPS(1); - Deprecated("llXorBase64Strings", "Use llXorBase64 instead"); - return String.Empty; + + if (str1 == String.Empty) + return String.Empty; + if (str2 == String.Empty) + return str1; + + int len = str2.Length; + if ((len % 4) != 0) // LL is EVIL!!!! + { + while (str2.EndsWith("=")) + str2 = str2.Substring(0, str2.Length - 1); + + len = str2.Length; + int mod = len % 4; + + if (mod == 1) + str2 = str2.Substring(0, str2.Length - 1); + else if (mod == 2) + str2 += "=="; + else if (mod == 3) + str2 += "="; + } + + byte[] data1; + byte[] data2; + try + { + data1 = Convert.FromBase64String(str1); + data2 = Convert.FromBase64String(str2); + } + catch (Exception) + { + return new LSL_String(String.Empty); + } + + // For cases where the decoded length of s2 is greater + // than the decoded length of s1, simply perform a normal + // decode and XOR + // + /* + if (data2.Length >= data1.Length) + { + for (int pos = 0 ; pos < data1.Length ; pos++ ) + data1[pos] ^= data2[pos]; + + return Convert.ToBase64String(data1); + } + */ + + // Remove padding + while (str1.EndsWith("=")) + { + str1 = str1.Substring(0, str1.Length - 1); + padding++; + } + while (str2.EndsWith("=")) + str2 = str2.Substring(0, str2.Length - 1); + + byte[] d1 = new byte[str1.Length]; + byte[] d2 = new byte[str2.Length]; + + for (int i = 0 ; i < str1.Length ; i++) + { + int idx = b64.IndexOf(str1.Substring(i, 1)); + if (idx == -1) + idx = 0; + d1[i] = (byte)idx; + } + + for (int i = 0 ; i < str2.Length ; i++) + { + int idx = b64.IndexOf(str2.Substring(i, 1)); + if (idx == -1) + idx = 0; + d2[i] = (byte)idx; + } + + string output = String.Empty; + + for (int pos = 0 ; pos < d1.Length ; pos++) + output += b64[d1[pos] ^ d2[pos % d2.Length]]; + + // Here's a funny thing: LL blithely violate the base64 + // standard pretty much everywhere. Here, padding is + // added only if the first input string had it, rather + // than when the data actually needs it. This can result + // in invalid base64 being returned. Go figure. + + while (padding-- > 0) + output += "="; + + return output; } public void llRemoteDataSetRegion() @@ -9520,6 +10534,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; land.SetMusicUrl(url); + + ScriptSleep(m_sleepMsOnSetParcelMusicURL); } public LSL_String llGetParcelMusicURL() @@ -9615,188 +10631,124 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List llGetBoundingBox(string obj) { m_host.AddScriptLPS(1); - - // Get target avatar if non-seated avatar or attachment, or prim and object UUID objID = UUID.Zero; - UUID.TryParse(obj, out objID); - ScenePresence agent = World.GetScenePresence(objID); - if (agent != null) - { - if (agent.ParentPart != null) - { - objID = agent.ParentPart.UUID; - agent = null; - } - } - SceneObjectGroup group = null; - SceneObjectPart target = World.GetSceneObjectPart(objID); - if (target != null) - { - group = target.ParentGroup; - if (group.IsAttachment) { - objID = group.AttachedAvatar; - agent = World.GetScenePresence(objID); - group = null; - target = null; - } - } - - // Initialize but break if no target LSL_List result = new LSL_List(); - int groupCount = 0; - int partCount = 0; - int vertexCount = 0; - if (target == null && agent == null) + + // If the ID is not valid, return null result + if (!UUID.TryParse(obj, out objID)) { result.Add(new LSL_Vector()); result.Add(new LSL_Vector()); - if (m_addStatsInGetBoundingBox) - result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); return result; } - Vector3 minPosition = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); - Vector3 maxPosition = new Vector3(float.MinValue, float.MinValue, float.MinValue); - // Try to get a mesher - IRendering primMesher = null; - List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); - if (renderers.Count > 0) - primMesher = RenderingLoader.LoadRenderer(renderers[0]); + // Check if this is an attached prim. If so, replace + // the UUID with the avatar UUID and report it's bounding box + SceneObjectPart part = World.GetSceneObjectPart(objID); + if (part != null && part.ParentGroup.IsAttachment) + objID = part.ParentGroup.AttachedAvatar; - // Get bounding box of just avatar, seated or not - if (agent != null) - { - bool hasParent = false; - Vector3 lower; - Vector3 upper; - BoundingBoxOfScenePresence(agent, out lower, out upper); - Vector3 offset = Vector3.Zero; - - // Since local bounding box unrotated and untilted, keep it simple - AddBoundingBoxOfSimpleBox(lower, upper, offset, agent.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); - partCount++; - groupCount++; - - // Return lower and upper bounding box corners - result.Add(new LSL_Vector(minPosition)); - result.Add(new LSL_Vector(maxPosition)); - if (m_addStatsInGetBoundingBox) - result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); - return result; - } - // Get bounding box of object including seated avatars - else if (group != null) + // Find out if this is an avatar ID. If so, return it's box + ScenePresence presence = World.GetScenePresence(objID); + if (presence != null) { - // Merge bounding boxes of all parts (prims and mesh) - foreach (SceneObjectPart part in group.Parts) - { - bool hasParent = (!part.IsRoot); - // When requested or if no mesher, keep it simple - if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) - { - AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); - } - // Do the full mounty - else - { - Primitive omvPrim = part.Shape.ToOmvPrimitive(part.OffsetPosition, part.RotationOffset); - byte[] sculptAsset = null; - if (omvPrim.Sculpt != null) - sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); - - // When part is mesh - // Quirk: Only imports as incompletely populated faceted mesh object, so needs an own handler. - if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) - { - AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); - FacetedMesh mesh = null; - FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); - meshAsset = null; - if (mesh != null) - { - AddBoundingBoxOfFacetedMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); - mesh = null; - } - } - - // When part is sculpt - // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. - else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) - { - IJ2KDecoder imgDecoder = World.RequestModuleInterface(); - if (imgDecoder != null) - { - Image sculpt = imgDecoder.DecodeToImage(sculptAsset); - if (sculpt != null) - { - SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); - sculpt.Dispose(); - if (mesh != null) - { - AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); - mesh = null; - } - } - } - } + // As per LSL Wiki, there is no difference between sitting + // and standing avatar since server 1.36 + LSL_Vector lower; + LSL_Vector upper; - // When part is prim - else if (omvPrim.Sculpt == null) - { - SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); - if (mesh != null) - { - AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); - mesh = null; - } - } - - // When all else fails, try fallback to simple box - else - { - AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); - } - } - partCount++; - } - } - - // Merge bounding boxes of seated avatars - foreach (ScenePresence sp in group.GetSittingAvatars()) - { - Vector3 lower; - Vector3 upper; - BoundingBoxOfScenePresence(sp, out lower, out upper); - Vector3 offset = sp.OffsetPosition; + Vector3 box = presence.Appearance.AvatarBoxSize * 0.5f; - bool hasParent = true; - // When requested or if no mesher, keep it simple - if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) + if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID + == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) +/* { - AddBoundingBoxOfSimpleBox(lower, upper, offset, sp.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + // This is for ground sitting avatars + float height = presence.Appearance.AvatarHeight / 2.66666667f; + lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f); + upper = new LSL_Vector(0.3375f, 0.45f, 0.0f); } - // Do the full mounty else { - // Prim shapes don't do center offsets, so add it here. - offset = offset + (lower + upper) * 0.5f * sp.Rotation; - Primitive omvPrim = MakeOpenMetaversePrim(upper - lower, offset, sp.Rotation, ScriptBaseClass.PRIM_TYPE_SPHERE); - SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); - AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); - mesh = null; + // This is for standing/flying avatars + float height = presence.Appearance.AvatarHeight / 2.0f; + lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f); + upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f); } - partCount++; + + // Adjust to the documented error offsets (see LSL Wiki) + lower += new LSL_Vector(0.05f, 0.05f, 0.05f); + upper -= new LSL_Vector(0.05f, 0.05f, 0.05f); +*/ + { + // This is for ground sitting avatars TODO! + lower = new LSL_Vector(-box.X - 0.1125, -box.Y, box.Z * -1.0f); + upper = new LSL_Vector(box.X + 0.1125, box.Y, box.Z * -1.0f); + } + else + { + // This is for standing/flying avatars + lower = new LSL_Vector(-box.X, -box.Y, -box.Z); + upper = new LSL_Vector(box.X, box.Y, box.Z); + } + + if (lower.x > upper.x) + lower.x = upper.x; + if (lower.y > upper.y) + lower.y = upper.y; + if (lower.z > upper.z) + lower.z = upper.z; + + result.Add(lower); + result.Add(upper); + return result; } - groupCount++; + part = World.GetSceneObjectPart(objID); + // Currently only works for single prims without a sitting avatar + if (part != null) + { + float minX; + float maxX; + float minY; + float maxY; + float minZ; + float maxZ; - // Return lower and upper bounding box corners - result.Add(new LSL_Vector(minPosition)); - result.Add(new LSL_Vector(maxPosition)); - if (m_addStatsInGetBoundingBox) - result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); + // This BBox is in sim coordinates, with the offset being + // a contained point. + Vector3[] offsets = Scene.GetCombinedBoundingBox(new List { part.ParentGroup }, + out minX, out maxX, out minY, out maxY, out minZ, out maxZ); + + minX -= offsets[0].X; + maxX -= offsets[0].X; + minY -= offsets[0].Y; + maxY -= offsets[0].Y; + minZ -= offsets[0].Z; + maxZ -= offsets[0].Z; + + LSL_Vector lower; + LSL_Vector upper; + + // Adjust to the documented error offsets (see LSL Wiki) + lower = new LSL_Vector(minX + 0.05f, minY + 0.05f, minZ + 0.05f); + upper = new LSL_Vector(maxX - 0.05f, maxY - 0.05f, maxZ - 0.05f); + + if (lower.x > upper.x) + lower.x = upper.x; + if (lower.y > upper.y) + lower.y = upper.y; + if (lower.z > upper.z) + lower.z = upper.z; + + result.Add(lower); + result.Add(upper); + return result; + } - primMesher = null; + // Not found so return empty values + result.Add(new LSL_Vector()); + result.Add(new LSL_Vector()); return result; } @@ -9836,430 +10788,80 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - /// - /// Helper to approximate a part with a simple box. - /// - private void AddBoundingBoxOfSimpleBox(Vector3 corner1, Vector3 corner2, Vector3 offset, Quaternion rotation, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) - { - // Parse the 8 box corners - for (int i = 0; i < 8; i++) - { - // Calculate each box corner - Vector3 position = corner1; - if ((i & 1) != 0) - position.X = corner2.X; - if ((i & 2) != 0) - position.Y = corner2.Y; - if ((i & 4) != 0) - position.Z = corner2.Z; - // Rotate part unless part is root - if (hasParent) - position = position * rotation; - position = position + offset; - // Adjust lower and upper bounding box corners if needed - lower = Vector3.Min(lower, position); - upper = Vector3.Max(upper, position); - count++; - } - } - - /// - /// Helper to parse a meshed prim and needed especially - /// for accuracy with tortured prims and sculpts. - /// - private void AddBoundingBoxOfSimpleMesh(SimpleMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) - { - // Quirk: A meshed box contains 10 instead of the 8 necessary vertices. - if (mesh != null) - { - // Parse each vertex in mesh - foreach (Vertex vertex in mesh.Vertices) - { - Vector3 position = vertex.Position; - position = position * prim.Scale; - // Rotate part unless part is root - if (hasParent) - position = position * prim.Rotation; - position = position + prim.Position; - // Adjust lower and upper bounding box corners if needed - lower = Vector3.Min(lower, position); - upper = Vector3.Max(upper, position); - count++; - } - } - } - - /// - /// Helper to parse mesh because no method exists - /// to parse mesh assets to SimpleMesh. - /// - private void AddBoundingBoxOfFacetedMesh(FacetedMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) - { - if (mesh != null) - { - // Parse each face in mesh - // since vertex array isn't populated. - // This parses each unique vertex 3-6 times. - foreach (Face face in mesh.Faces) - { - // Parse each vertex in face - foreach (Vertex vertex in face.Vertices) - { - Vector3 position = vertex.Position; - position = position * prim.Scale; - // Rotate part unless part is root - if (hasParent) - position = position * prim.Rotation; - position = position + prim.Position; - // Adjust lower and upper bounding box corners if needed - lower = Vector3.Min(lower, position); - upper = Vector3.Max(upper, position); - count++; - } - } - } - } - - /// - /// Helper to make up an OpenMetaverse prim - /// needed to create mesh from parts. - /// - private Primitive MakeOpenMetaversePrim(Vector3 scale, Vector3 position, Quaternion rotation, int primType) - { - // Initialize and set common parameters - Primitive prim = new OpenMetaverse.Primitive(); - prim.Scale = scale; - prim.Position = position; - prim.Rotation = rotation; - prim.PrimData.PathShearX = 0.0f; - prim.PrimData.PathShearY = 0.0f; - prim.PrimData.PathBegin = 0.0f; - prim.PrimData.PathEnd = 1.0f; - prim.PrimData.PathScaleX = 1.0f; - prim.PrimData.PathScaleY = 1.0f; - prim.PrimData.PathTaperX = 0.0f; - prim.PrimData.PathTaperY = 0.0f; - prim.PrimData.PathTwistBegin = 0.0f; - prim.PrimData.PathTwist = 0.0f; - prim.PrimData.ProfileBegin = 0.0f; - prim.PrimData.ProfileEnd = 1.0f; - prim.PrimData.ProfileHollow = 0.0f; - prim.PrimData.ProfileCurve = (ProfileCurve)1; - prim.PrimData.ProfileHole = (HoleType)0; - prim.PrimData.PathCurve = (PathCurve)16; - prim.PrimData.PathRadiusOffset = 0.0f; - prim.PrimData.PathRevolutions = 1.0f; - prim.PrimData.PathSkew = 0.0f; - prim.PrimData.PCode = OpenMetaverse.PCode.Prim; - prim.PrimData.State = (byte)0; - - // Set type specific parameters - switch (primType) - { - // Set specific parameters for box - case ScriptBaseClass.PRIM_TYPE_BOX: - prim.PrimData.PathScaleY = 1.0f; - prim.PrimData.ProfileCurve = (ProfileCurve)1; - prim.PrimData.PathCurve = (PathCurve)16; - break; - // Set specific parameters for cylinder - case ScriptBaseClass.PRIM_TYPE_CYLINDER: - prim.PrimData.PathScaleY = 1.0f; - prim.PrimData.ProfileCurve = (ProfileCurve)0; - prim.PrimData.PathCurve = (PathCurve)16; - break; - // Set specific parameters for prism - case ScriptBaseClass.PRIM_TYPE_PRISM: - prim.PrimData.PathScaleY = 1.0f; - prim.PrimData.ProfileCurve = (ProfileCurve)3; - prim.PrimData.PathCurve = (PathCurve)16; - break; - // Set specific parameters for sphere - case ScriptBaseClass.PRIM_TYPE_SPHERE: - prim.PrimData.PathScaleY = 1.0f; - prim.PrimData.ProfileCurve = (ProfileCurve)5; - prim.PrimData.PathCurve = (PathCurve)32; - break; - // Set specific parameters for torus - case ScriptBaseClass.PRIM_TYPE_TORUS: - prim.PrimData.PathScaleY = 0.5f; - prim.PrimData.ProfileCurve = (ProfileCurve)0; - prim.PrimData.PathCurve = (PathCurve)32; - break; - // Set specific parameters for tube - case ScriptBaseClass.PRIM_TYPE_TUBE: - prim.PrimData.PathScaleY = 0.5f; - prim.PrimData.ProfileCurve = (ProfileCurve)1; - prim.PrimData.PathCurve = (PathCurve)32; - break; - // Set specific parameters for ring - case ScriptBaseClass.PRIM_TYPE_RING: - prim.PrimData.PathScaleY = 0.5f; - prim.PrimData.ProfileCurve = (ProfileCurve)3; - prim.PrimData.PathCurve = (PathCurve)32; - break; - // Set specific parameters for sculpt - case ScriptBaseClass.PRIM_TYPE_SCULPT: - prim.PrimData.PathScaleY = 1.0f; - prim.PrimData.ProfileCurve = (ProfileCurve)5; - prim.PrimData.PathCurve = (PathCurve)32; - break; - // Default to specific parameters for box - default: - prim.PrimData.PathScaleY = 1.0f; - prim.PrimData.ProfileCurve = (ProfileCurve)1; - prim.PrimData.PathCurve = (PathCurve)16; - break; - } - - return prim; - } - /// - /// Implementation of llGetGeometricCenter according to SL 2015-04-30. - /// http://wiki.secondlife.com/wiki/LlGetGeometricCenter - /// Returns the average position offset of all linked parts, - /// including the root prim and seated avatars, - /// relative to the root prim in local coordinates. - /// public LSL_Vector llGetGeometricCenter() { - // Subtract whatever position the root prim has to make it zero - Vector3 offset = m_host.ParentGroup.RootPart.OffsetPosition * -1.0f; - - // Add all prim/part position offsets - foreach (SceneObjectPart part in m_host.ParentGroup.Parts) - offset = offset + part.OffsetPosition; - // Add all avatar/scene presence position offsets - foreach (ScenePresence sp in m_host.ParentGroup.GetSittingAvatars()) - offset = offset + sp.OffsetPosition; - - // Calculate and return the average offset - offset = offset / (float)(m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount()); - return new LSL_Vector(offset); + return new LSL_Vector(m_host.GetGeometricCenter()); } - public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules) + public LSL_List llGetPrimitiveParams(LSL_List rules) { - LSL_List result = new LSL_List(); - LSL_List remaining; - - while (true) - { -// m_log.DebugFormat( -// "[LSL API]: GetEntityParams has {0} rules with scene entity named {1}", -// rules.Length, entity != null ? entity.Name : "NULL"); - - if (entity == null) - return result; + m_host.AddScriptLPS(1); - if (entity is SceneObjectPart) - remaining = GetPrimParams((SceneObjectPart)entity, rules, ref result); - else - remaining = GetAgentParams((ScenePresence)entity, rules, ref result); + LSL_List result = new LSL_List(); - if (remaining == null || remaining.Length < 2) - return result; + LSL_List remaining = GetPrimParams(m_host, rules, ref result); + while ((object)remaining != null && remaining.Length > 2) + { int linknumber = remaining.GetLSLIntegerItem(0); rules = remaining.GetSublist(1, -1); - entity = GetLinkEntity(m_host, linknumber); - } - } + List parts = GetLinkParts(linknumber); - public LSL_List llGetPrimitiveParams(LSL_List rules) - { - m_host.AddScriptLPS(1); + foreach (SceneObjectPart part in parts) + remaining = GetPrimParams(part, rules, ref result); + } - return GetEntityParams(m_host, rules); + return result; } public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules) { m_host.AddScriptLPS(1); - return GetEntityParams(GetLinkEntity(m_host, linknumber), rules); - } + // acording to SL wiki this must indicate a single link number or link_root or link_this. + // keep other options as before - public LSL_Vector GetAgentSize(ScenePresence sp) - { - return new LSL_Vector(0.45, 0.6, sp.Appearance.AvatarHeight); - } + List parts; + List avatars; - /// - /// Gets params for a seated avatar in a linkset. - /// - /// - /// - /// - /// - public LSL_List GetAgentParams(ScenePresence sp, LSL_List rules, ref LSL_List res) - { - int idx = 0; - while (idx < rules.Length) + LSL_List res = new LSL_List(); + LSL_List remaining = new LSL_List(); + + while (rules.Length > 0) { - int code = (int)rules.GetLSLIntegerItem(idx++); - int remain = rules.Length-idx; + parts = GetLinkParts(linknumber); + avatars = GetLinkAvatars(linknumber); - switch (code) + remaining = new LSL_List(); + foreach (SceneObjectPart part in parts) { - case (int)ScriptBaseClass.PRIM_MATERIAL: - res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MATERIAL_FLESH)); - break; - - case (int)ScriptBaseClass.PRIM_PHYSICS: - res.Add(ScriptBaseClass.FALSE); - break; - - case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ: - res.Add(ScriptBaseClass.FALSE); - break; - - case (int)ScriptBaseClass.PRIM_PHANTOM: - res.Add(ScriptBaseClass.FALSE); - break; - - case (int)ScriptBaseClass.PRIM_POSITION: - res.Add(new LSL_Vector(sp.AbsolutePosition)); - break; - - case (int)ScriptBaseClass.PRIM_SIZE: - res.Add(GetAgentSize(sp)); - break; - - case (int)ScriptBaseClass.PRIM_ROTATION: - res.Add(sp.GetWorldRotation()); - break; - - case (int)ScriptBaseClass.PRIM_TYPE: - res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TYPE_BOX)); - res.Add(new LSL_Integer(ScriptBaseClass.PRIM_HOLE_DEFAULT)); - res.Add(new LSL_Vector(0, 1, 0)); - res.Add(new LSL_Float(0)); - res.Add(new LSL_Vector(0, 0, 0)); - res.Add(new LSL_Vector(1, 1, 0)); - res.Add(new LSL_Vector(0, 0, 0)); - break; - - case (int)ScriptBaseClass.PRIM_TEXTURE: - if (remain < 1) - return new LSL_List(); - - int face = (int)rules.GetLSLIntegerItem(idx++); - if (face > 21) - break; - - res.Add(new LSL_String("")); - res.Add(ScriptBaseClass.ZERO_VECTOR); - res.Add(ScriptBaseClass.ZERO_VECTOR); - res.Add(new LSL_Float(0)); - break; - - case (int)ScriptBaseClass.PRIM_COLOR: - if (remain < 1) - return new LSL_List(); - - face = (int)rules.GetLSLIntegerItem(idx++); - if (face > 21) - break; - - res.Add(ScriptBaseClass.ZERO_VECTOR); - res.Add(new LSL_Float(0)); - break; - - case (int)ScriptBaseClass.PRIM_BUMP_SHINY: - if (remain < 1) - return new LSL_List(); - - face = (int)rules.GetLSLIntegerItem(idx++); - if (face > 21) - break; - - res.Add(ScriptBaseClass.PRIM_SHINY_NONE); - res.Add(ScriptBaseClass.PRIM_BUMP_NONE); - break; - - case (int)ScriptBaseClass.PRIM_FULLBRIGHT: - if (remain < 1) - return new LSL_List(); - - face = (int)rules.GetLSLIntegerItem(idx++); - if (face > 21) - break; - - res.Add(ScriptBaseClass.FALSE); - break; - - case (int)ScriptBaseClass.PRIM_FLEXIBLE: - res.Add(ScriptBaseClass.FALSE); - res.Add(new LSL_Integer(0)); - res.Add(new LSL_Float(0)); - res.Add(new LSL_Float(0)); - res.Add(new LSL_Float(0)); - res.Add(new LSL_Float(0)); - res.Add(ScriptBaseClass.ZERO_VECTOR); - break; - - case (int)ScriptBaseClass.PRIM_TEXGEN: - if (remain < 1) - return new LSL_List(); - - face = (int)rules.GetLSLIntegerItem(idx++); - if (face > 21) - break; - - res.Add(ScriptBaseClass.PRIM_TEXGEN_DEFAULT); - break; - - case (int)ScriptBaseClass.PRIM_POINT_LIGHT: - res.Add(ScriptBaseClass.FALSE); - res.Add(ScriptBaseClass.ZERO_VECTOR); - res.Add(ScriptBaseClass.ZERO_VECTOR); - break; - - case (int)ScriptBaseClass.PRIM_GLOW: - if (remain < 1) - return new LSL_List(); - - face = (int)rules.GetLSLIntegerItem(idx++); - if (face > 21) - break; - - res.Add(new LSL_Float(0)); - break; - - case (int)ScriptBaseClass.PRIM_TEXT: - res.Add(new LSL_String("")); - res.Add(ScriptBaseClass.ZERO_VECTOR); - res.Add(new LSL_Float(1)); - break; - - case (int)ScriptBaseClass.PRIM_ROT_LOCAL: - res.Add(new LSL_Rotation(sp.Rotation)); - break; - - case (int)ScriptBaseClass.PRIM_POS_LOCAL: - res.Add(new LSL_Vector(sp.OffsetPosition)); - break; - - case (int)ScriptBaseClass.PRIM_SLICE: - res.Add(new LSL_Vector(0, 1, 0)); - break; - - case (int)ScriptBaseClass.PRIM_LINK_TARGET: - if(remain < 3) - return new LSL_List(); + remaining = GetPrimParams(part, rules, ref res); + } + foreach (ScenePresence avatar in avatars) + { + remaining = GetPrimParams(avatar, rules, ref res); + } - return rules.GetSublist(idx, -1); + if (remaining.Length > 0) + { + linknumber = remaining.GetLSLIntegerItem(0); + rules = remaining.GetSublist(1, -1); } + else + break; } - return new LSL_List(); + return res; } public LSL_List GetPrimParams(SceneObjectPart part, LSL_List rules, ref LSL_List res) { int idx = 0; + int face; + Primitive.TextureEntry tex; + int nsides = GetNumberOfSides(part); + while (idx < rules.Length) { int code = (int)rules.GetLSLIntegerItem(idx++); @@ -10293,19 +10895,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case (int)ScriptBaseClass.PRIM_POSITION: - LSL_Vector v = new LSL_Vector(part.AbsolutePosition); - - // For some reason, the part.AbsolutePosition.* values do not change if the - // linkset is rotated; they always reflect the child prim's world position - // as though the linkset is unrotated. This is incompatible behavior with SL's - // implementation, so will break scripts imported from there (not to mention it - // makes it more difficult to determine a child prim's actual inworld position). - if (!part.IsRoot) - { - LSL_Vector rootPos = new LSL_Vector(m_host.ParentGroup.AbsolutePosition); - v = ((v - rootPos) * llGetRootRotation()) + rootPos; - } - + LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X, + part.AbsolutePosition.Y, + part.AbsolutePosition.Z); res.Add(v); break; @@ -10410,11 +11002,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (remain < 1) return new LSL_List(); - int face = (int)rules.GetLSLIntegerItem(idx++); - Primitive.TextureEntry tex = part.Shape.Textures; + face = (int)rules.GetLSLIntegerItem(idx++); + tex = part.Shape.Textures; + if (face == ScriptBaseClass.ALL_SIDES) { - for (face = 0 ; face < GetNumberOfSides(part); face++) + for (face = 0; face < nsides; face++) { Primitive.TextureEntryFace texface = tex.GetFace((uint)face); @@ -10430,7 +11023,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - if (face >= 0 && face < GetNumberOfSides(part)) + if (face >= 0 && face < nsides) { Primitive.TextureEntryFace texface = tex.GetFace((uint)face); @@ -10450,13 +11043,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (remain < 1) return new LSL_List(); - face=(int)rules.GetLSLIntegerItem(idx++); - + face = (int)rules.GetLSLIntegerItem(idx++); tex = part.Shape.Textures; Color4 texcolor; + if (face == ScriptBaseClass.ALL_SIDES) { - for (face = 0 ; face < GetNumberOfSides(part); face++) + for (face = 0; face < nsides; face++) { texcolor = tex.GetFace((uint)face).RGBA; res.Add(new LSL_Vector(texcolor.R, @@ -10476,61 +11069,100 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case (int)ScriptBaseClass.PRIM_BUMP_SHINY: + { if (remain < 1) return new LSL_List(); - face=(int)rules.GetLSLIntegerItem(idx++); - + face = (int)rules.GetLSLIntegerItem(idx++); tex = part.Shape.Textures; + int shiny; if (face == ScriptBaseClass.ALL_SIDES) { - for (face = 0; face < GetNumberOfSides(part); face++) + for (face = 0; face < nsides; face++) { - Primitive.TextureEntryFace texface = tex.GetFace((uint)face); - // Convert Shininess to PRIM_SHINY_* - res.Add(new LSL_Integer((uint)texface.Shiny >> 6)); - // PRIM_BUMP_* - res.Add(new LSL_Integer((int)texface.Bump)); + Shininess shinyness = tex.GetFace((uint)face).Shiny; + if (shinyness == Shininess.High) + { + shiny = ScriptBaseClass.PRIM_SHINY_HIGH; + } + else if (shinyness == Shininess.Medium) + { + shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM; + } + else if (shinyness == Shininess.Low) + { + shiny = ScriptBaseClass.PRIM_SHINY_LOW; + } + else + { + shiny = ScriptBaseClass.PRIM_SHINY_NONE; + } + res.Add(new LSL_Integer(shiny)); + res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump)); } } else { - if (face >= 0 && face < GetNumberOfSides(part)) + Shininess shinyness = tex.GetFace((uint)face).Shiny; + if (shinyness == Shininess.High) { - Primitive.TextureEntryFace texface = tex.GetFace((uint)face); - // Convert Shininess to PRIM_SHINY_* - res.Add(new LSL_Integer((uint)texface.Shiny >> 6)); - // PRIM_BUMP_* - res.Add(new LSL_Integer((int)texface.Bump)); + shiny = ScriptBaseClass.PRIM_SHINY_HIGH; + } + else if (shinyness == Shininess.Medium) + { + shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM; + } + else if (shinyness == Shininess.Low) + { + shiny = ScriptBaseClass.PRIM_SHINY_LOW; + } + else + { + shiny = ScriptBaseClass.PRIM_SHINY_NONE; } + res.Add(new LSL_Integer(shiny)); + res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump)); } break; - + } case (int)ScriptBaseClass.PRIM_FULLBRIGHT: + { if (remain < 1) return new LSL_List(); face = (int)rules.GetLSLIntegerItem(idx++); tex = part.Shape.Textures; + int fullbright; if (face == ScriptBaseClass.ALL_SIDES) { - for (face = 0; face < GetNumberOfSides(part); face++) + for (face = 0; face < nsides; face++) { - Primitive.TextureEntryFace texface = tex.GetFace((uint)face); - res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0)); - } - } - else - { - if (face >= 0 && face < GetNumberOfSides(part)) + if (tex.GetFace((uint)face).Fullbright == true) + { + fullbright = ScriptBaseClass.TRUE; + } + else + { + fullbright = ScriptBaseClass.FALSE; + } + res.Add(new LSL_Integer(fullbright)); + } + } + else + { + if (tex.GetFace((uint)face).Fullbright == true) { - Primitive.TextureEntryFace texface = tex.GetFace((uint)face); - res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0)); + fullbright = ScriptBaseClass.TRUE; + } + else + { + fullbright = ScriptBaseClass.FALSE; } + res.Add(new LSL_Integer(fullbright)); } break; - + } case (int)ScriptBaseClass.PRIM_FLEXIBLE: PrimitiveBaseShape shape = part.Shape; @@ -10549,27 +11181,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case (int)ScriptBaseClass.PRIM_TEXGEN: + // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR) if (remain < 1) return new LSL_List(); - face=(int)rules.GetLSLIntegerItem(idx++); + face = (int)rules.GetLSLIntegerItem(idx++); tex = part.Shape.Textures; if (face == ScriptBaseClass.ALL_SIDES) { - for (face = 0; face < GetNumberOfSides(part); face++) + for (face = 0; face < nsides; face++) { - MappingType texgen = tex.GetFace((uint)face).TexMapType; - // Convert MappingType to PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR etc. - res.Add(new LSL_Integer((uint)texgen >> 1)); + if (tex.GetFace((uint)face).TexMapType == MappingType.Planar) + { + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR)); + } + else + { + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT)); + } } } else { - if (face >= 0 && face < GetNumberOfSides(part)) + if (tex.GetFace((uint)face).TexMapType == MappingType.Planar) + { + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR)); + } + else { - MappingType texgen = tex.GetFace((uint)face).TexMapType; - res.Add(new LSL_Integer((uint)texgen >> 1)); + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT)); } } break; @@ -10593,24 +11234,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (remain < 1) return new LSL_List(); - face=(int)rules.GetLSLIntegerItem(idx++); + face = (int)rules.GetLSLIntegerItem(idx++); tex = part.Shape.Textures; + float primglow; if (face == ScriptBaseClass.ALL_SIDES) { - for (face = 0; face < GetNumberOfSides(part); face++) + for (face = 0; face < nsides; face++) { - Primitive.TextureEntryFace texface = tex.GetFace((uint)face); - res.Add(new LSL_Float(texface.Glow)); + primglow = tex.GetFace((uint)face).Glow; + res.Add(new LSL_Float(primglow)); } } else { - if (face >= 0 && face < GetNumberOfSides(part)) - { - Primitive.TextureEntryFace texface = tex.GetFace((uint)face); - res.Add(new LSL_Float(texface.Glow)); - } + primglow = tex.GetFace((uint)face).Glow; + res.Add(new LSL_Float(primglow)); } break; @@ -10620,17 +11259,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api res.Add(new LSL_Vector(textColor.R, textColor.G, textColor.B)); - res.Add(new LSL_Float(1.0 - textColor.A)); + res.Add(new LSL_Float(textColor.A)); break; + case (int)ScriptBaseClass.PRIM_NAME: res.Add(new LSL_String(part.Name)); break; + case (int)ScriptBaseClass.PRIM_DESC: res.Add(new LSL_String(part.Description)); break; case (int)ScriptBaseClass.PRIM_ROT_LOCAL: res.Add(new LSL_Rotation(part.RotationOffset)); break; + case (int)ScriptBaseClass.PRIM_POS_LOCAL: res.Add(new LSL_Vector(GetPartLocalPos(part))); break; @@ -10643,6 +11285,71 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 0 )); break; + + case (int)ScriptBaseClass.PRIM_OMEGA: + // this may return values diferent from SL since we don't handle set the same way + float gain = 1.0f; // we don't use gain and don't store it + Vector3 axis = part.AngularVelocity; + float spin = axis.Length(); + if(spin < 1.0e-6) + { + axis = Vector3.Zero; + gain = 0.0f; + spin = 0.0f; + } + else + { + axis = axis * (1.0f/spin); + } + + res.Add(new LSL_Vector(axis.X, + axis.Y, + axis.Z)); + res.Add(new LSL_Float(spin)); + res.Add(new LSL_Float(gain)); + break; + + case (int)ScriptBaseClass.PRIM_SIT_TARGET: + if(part.IsSitTargetSet) + { + res.Add(new LSL_Integer(1)); + res.Add(new LSL_Vector(part.SitTargetPosition)); + res.Add(new LSL_Rotation(part.SitTargetOrientation)); + } + else + { + res.Add(new LSL_Integer(0)); + res.Add(new LSL_Vector(Vector3.Zero)); + res.Add(new LSL_Rotation(Quaternion.Identity)); + } + break; + + case (int)ScriptBaseClass.PRIM_NORMAL: + case (int)ScriptBaseClass.PRIM_SPECULAR: + case (int)ScriptBaseClass.PRIM_ALPHA_MODE: + if (remain < 1) + return new LSL_List(); + + face = (int)rules.GetLSLIntegerItem(idx++); + tex = part.Shape.Textures; + if (face == ScriptBaseClass.ALL_SIDES) + { + for (face = 0; face < nsides; face++) + { + Primitive.TextureEntryFace texface = tex.GetFace((uint)face); + getLSLFaceMaterial(ref res, code, part, texface); + } + } + else + { + if (face >= 0 && face < nsides) + { + Primitive.TextureEntryFace texface = tex.GetFace((uint)face); + getLSLFaceMaterial(ref res, code, part, texface); + } + } + break; + case (int)ScriptBaseClass.PRIM_LINK_TARGET: // TODO: Should be issuing a runtime script warning in this case. @@ -10656,15 +11363,120 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_List(); } +/* + private string filterTextureUUIDbyRights(UUID origID, SceneObjectPart part, bool checkTaskInventory, bool returnInvName) + { + if(checkTaskInventory) + { + lock (part.TaskInventory) + { + foreach (KeyValuePair inv in part.TaskInventory) + { + if (inv.Value.AssetID == origID) + { + if(inv.Value.InvType == (int)InventoryType.Texture) + { + if(returnInvName) + return inv.Value.Name; + else + return origID.ToString(); + } + else + return UUID.Zero.ToString(); + } + } + } + } + + if(World.Permissions.CanEditObject(m_host.ParentGroup.UUID, m_host.ParentGroup.RootPart.OwnerID)) + return origID.ToString(); + + return UUID.Zero.ToString(); + } +*/ + private void getLSLFaceMaterial(ref LSL_List res, int code, SceneObjectPart part, Primitive.TextureEntryFace texface) + { + UUID matID = texface.MaterialID; + if(matID != UUID.Zero) + { + AssetBase MatAsset = World.AssetService.Get(matID.ToString()); + if(MatAsset != null) + { + Byte[] data = MatAsset.Data; + OSDMap osdmat = (OSDMap)OSDParser.DeserializeLLSDXml(data); + if(osdmat != null && osdmat.ContainsKey("NormMap")) + { + string mapIDstr; + FaceMaterial mat = new FaceMaterial(matID, osdmat); + if(code == ScriptBaseClass.PRIM_NORMAL) + { +// mapIDstr = filterTextureUUIDbyRights(mat.NormalMapID, part, true, false); + mapIDstr = mat.NormalMapID.ToString(); + res.Add(new LSL_String(mapIDstr)); + res.Add(new LSL_Vector(mat.NormalRepeatX, mat.NormalRepeatY, 0)); + res.Add(new LSL_Vector(mat.NormalOffsetX, mat.NormalOffsetY, 0)); + res.Add(new LSL_Float(mat.NormalRotation)); + } + else if(code == ScriptBaseClass.PRIM_SPECULAR ) + { +// mapIDstr = filterTextureUUIDbyRights(mat.SpecularMapID, part, true, false); + const float colorScale = 1.0f/255f; + mapIDstr = mat.SpecularMapID.ToString(); + res.Add(new LSL_String(mapIDstr)); + res.Add(new LSL_Vector(mat.SpecularRepeatX, mat.SpecularRepeatY, 0)); + res.Add(new LSL_Vector(mat.SpecularOffsetX, mat.SpecularOffsetY, 0)); + res.Add(new LSL_Float(mat.SpecularRotation)); + res.Add(new LSL_Vector(mat.SpecularLightColor.R * colorScale, + mat.SpecularLightColor.G * colorScale, + mat.SpecularLightColor.B * colorScale)); + res.Add(new LSL_Integer(mat.SpecularLightExponent)); + res.Add(new LSL_Integer(mat.EnvironmentIntensity)); + } + else if(code == ScriptBaseClass.PRIM_ALPHA_MODE) + { + res.Add(new LSL_Integer(mat.DiffuseAlphaMode)); + res.Add(new LSL_Integer(mat.AlphaMaskCutoff)); + } + return; + } + } + matID = UUID.Zero; + } + if(matID == UUID.Zero) + { + if(code == (int)ScriptBaseClass.PRIM_NORMAL || code == (int)ScriptBaseClass.PRIM_SPECULAR ) + { + res.Add(new LSL_String(UUID.Zero.ToString())); + res.Add(new LSL_Vector(1.0, 1.0, 0)); + res.Add(new LSL_Vector(0, 0, 0)); + res.Add(new LSL_Float(0)); + + if(code == (int)ScriptBaseClass.PRIM_SPECULAR) + { + res.Add(new LSL_Vector(1.0, 1.0, 1.0)); + res.Add(new LSL_Integer(51)); + res.Add(new LSL_Integer(0)); + } + } + else if(code == (int)ScriptBaseClass.PRIM_ALPHA_MODE) + { + res.Add(new LSL_Integer(1)); + res.Add(new LSL_Integer(0)); + } + } + } + public LSL_List llGetPrimMediaParams(int face, LSL_List rules) { m_host.AddScriptLPS(1); + ScriptSleep(m_sleepMsOnGetPrimMediaParams); return GetPrimMediaParams(m_host, face, rules); } public LSL_List llGetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules) { m_host.AddScriptLPS(1); + ScriptSleep(m_sleepMsOnGetLinkMedia); if (link == ScriptBaseClass.LINK_ROOT) return GetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules); else if (link == ScriptBaseClass.LINK_THIS) @@ -10784,12 +11596,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llSetPrimMediaParams(LSL_Integer face, LSL_List rules) { m_host.AddScriptLPS(1); + ScriptSleep(m_sleepMsOnSetPrimMediaParams); return SetPrimMediaParams(m_host, face, rules); } public LSL_Integer llSetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules) { m_host.AddScriptLPS(1); + ScriptSleep(m_sleepMsOnSetLinkMedia); if (link == ScriptBaseClass.LINK_ROOT) return SetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules); else if (link == ScriptBaseClass.LINK_THIS) @@ -10908,12 +11722,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llClearPrimMedia(LSL_Integer face) { m_host.AddScriptLPS(1); + ScriptSleep(m_sleepMsOnClearPrimMedia); return ClearPrimMedia(m_host, face); } public LSL_Integer llClearLinkMedia(LSL_Integer link, LSL_Integer face) { m_host.AddScriptLPS(1); + ScriptSleep(m_sleepMsOnClearLinkMedia); if (link == ScriptBaseClass.LINK_ROOT) return ClearPrimMedia(m_host.ParentGroup.RootPart, face); else if (link == ScriptBaseClass.LINK_THIS) @@ -11237,8 +12053,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // The function returns an ordered list // representing the tokens found in the supplied // sources string. If two successive tokenizers - // are encountered, then a NULL entry is added - // to the list. + // are encountered, then a null-string entry is + // added to the list. // // It is a precondition that the source and // toekizer lisst are non-null. If they are null, @@ -11246,7 +12062,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // while their lengths are being determined. // // A small amount of working memoryis required - // of approximately 8*#tokenizers. + // of approximately 8*#tokenizers + 8*srcstrlen. // // There are many ways in which this function // can be implemented, this implementation is @@ -11262,155 +12078,124 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // and eliminates redundant tokenizers as soon // as is possible. // - // The implementation tries to avoid any copying - // of arrays or other objects. + // The implementation tries to minimize temporary + // garbage generation. // - private LSL_List ParseString(string src, LSL_List separators, LSL_List spacers, bool keepNulls) + public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers) { - int beginning = 0; - int srclen = src.Length; - int seplen = separators.Length; - object[] separray = separators.Data; - int spclen = spacers.Length; - object[] spcarray = spacers.Data; - int mlen = seplen+spclen; - - int[] offset = new int[mlen+1]; - bool[] active = new bool[mlen]; - - int best; - int j; - - // Initial capacity reduces resize cost + return ParseString2List(src, separators, spacers, true); + } - LSL_List tokens = new LSL_List(); + private LSL_List ParseString2List(string src, LSL_List separators, LSL_List spacers, bool keepNulls) + { + int srclen = src.Length; + int seplen = separators.Length; + object[] separray = separators.Data; + int spclen = spacers.Length; + object[] spcarray = spacers.Data; + int dellen = 0; + string[] delarray = new string[seplen+spclen]; - // All entries are initially valid + int outlen = 0; + string[] outarray = new string[srclen*2+1]; - for (int i = 0; i < mlen; i++) - active[i] = true; + int i, j; + string d; - offset[mlen] = srclen; + m_host.AddScriptLPS(1); - while (beginning < srclen) + /* + * Convert separator and spacer lists to C# strings. + * Also filter out null strings so we don't hang. + */ + for (i = 0; i < seplen; i ++) { + d = separray[i].ToString(); + if (d.Length > 0) + { + delarray[dellen++] = d; + } + } + seplen = dellen; - best = mlen; // as bad as it gets + for (i = 0; i < spclen; i ++) + { + d = spcarray[i].ToString(); + if (d.Length > 0) + { + delarray[dellen++] = d; + } + } - // Scan for separators + /* + * Scan through source string from beginning to end. + */ + for (i = 0;;) + { - for (j = 0; j < seplen; j++) + /* + * Find earliest delimeter in src starting at i (if any). + */ + int earliestDel = -1; + int earliestSrc = srclen; + string earliestStr = null; + for (j = 0; j < dellen; j ++) { - if (separray[j].ToString() == String.Empty) - active[j] = false; - - if (active[j]) + d = delarray[j]; + if (d != null) { - // scan all of the markers - if ((offset[j] = src.IndexOf(separray[j].ToString(), beginning)) == -1) + int index = src.IndexOf(d, i); + if (index < 0) { - // not present at all - active[j] = false; + delarray[j] = null; // delim nowhere in src, don't check it anymore } - else + else if (index < earliestSrc) { - // present and correct - if (offset[j] < offset[best]) - { - // closest so far - best = j; - if (offset[best] == beginning) - break; - } + earliestSrc = index; // where delimeter starts in source string + earliestDel = j; // where delimeter is in delarray[] + earliestStr = d; // the delimeter string from delarray[] + if (index == i) break; // can't do any better than found at beg of string } } } - // Scan for spacers - - if (offset[best] != beginning) + /* + * Output source string starting at i through start of earliest delimeter. + */ + if (keepNulls || (earliestSrc > i)) { - for (j = seplen; (j < mlen) && (offset[best] > beginning); j++) - { - if (spcarray[j-seplen].ToString() == String.Empty) - active[j] = false; - - if (active[j]) - { - // scan all of the markers - if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1) - { - // not present at all - active[j] = false; - } - else - { - // present and correct - if (offset[j] < offset[best]) - { - // closest so far - best = j; - } - } - } - } + outarray[outlen++] = src.Substring(i, earliestSrc - i); } - // This is the normal exit from the scanning loop + /* + * If no delimeter found at or after i, we're done scanning. + */ + if (earliestDel < 0) break; - if (best == mlen) + /* + * If delimeter was a spacer, output the spacer. + */ + if (earliestDel >= seplen) { - // no markers were found on this pass - // so we're pretty much done - if ((keepNulls) || ((!keepNulls) && (srclen - beginning) > 0)) - tokens.Add(new LSL_String(src.Substring(beginning, srclen - beginning))); - break; + outarray[outlen++] = earliestStr; } - // Otherwise we just add the newly delimited token - // and recalculate where the search should continue. - if ((keepNulls) || ((!keepNulls) && (offset[best] - beginning) > 0)) - tokens.Add(new LSL_String(src.Substring(beginning,offset[best]-beginning))); - - if (best < seplen) - { - beginning = offset[best] + (separray[best].ToString()).Length; - } - else - { - beginning = offset[best] + (spcarray[best - seplen].ToString()).Length; - string str = spcarray[best - seplen].ToString(); - if ((keepNulls) || ((!keepNulls) && (str.Length > 0))) - tokens.Add(new LSL_String(str)); - } + /* + * Look at rest of src string following delimeter. + */ + i = earliestSrc + earliestStr.Length; } - // This an awkward an not very intuitive boundary case. If the - // last substring is a tokenizer, then there is an implied trailing - // null list entry. Hopefully the single comparison will not be too - // arduous. Alternatively the 'break' could be replced with a return - // but that's shabby programming. - - if ((beginning == srclen) && (keepNulls)) + /* + * Make up an exact-sized output array suitable for an LSL_List object. + */ + object[] outlist = new object[outlen]; + for (i = 0; i < outlen; i ++) { - if (srclen != 0) - tokens.Add(new LSL_String("")); + outlist[i] = new LSL_String(outarray[i]); } - - return tokens; - } - - public LSL_List llParseString2List(string src, LSL_List separators, LSL_List spacers) - { - m_host.AddScriptLPS(1); - return this.ParseString(src, separators, spacers, false); - } - - public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers) - { - m_host.AddScriptLPS(1); - return this.ParseString(src, separators, spacers, true); + return new LSL_List(outlist); } public LSL_Integer llGetObjectPermMask(int mask) @@ -11453,7 +12238,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false)) { - if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID)) + if (World.Permissions.IsAdministrator(m_host.OwnerID)) { if (mask == ScriptBaseClass.MASK_BASE)//0 { @@ -11515,7 +12300,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false)) { - if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID)) + if (World.Permissions.IsAdministrator(m_host.OwnerID)) { TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName); @@ -11574,7 +12359,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); if (m_UrlModule != null) - return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString(); + return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID, null).ToString(); return UUID.Zero.ToString(); } @@ -11600,6 +12385,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.DATA_SIM_POS: if (info == null) { + ScriptSleep(m_sleepMsOnRequestSimulatorData); return UUID.Zero.ToString(); } @@ -11646,6 +12432,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.DATA_SIM_RATING: if (info == null) { + ScriptSleep(m_sleepMsOnRequestSimulatorData); return UUID.Zero.ToString(); } int access = info.Maturity; @@ -11660,14 +12447,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case ScriptBaseClass.DATA_SIM_RELEASE: if (ossl != null) - { -//// TODO - double check this. - if (!ossl.CheckThreatLevel(ThreatLevel.High, "llRequestSimulatorData")) - return UUID.Zero.ToString(); // Raise no event - } + ossl.CheckThreatLevel(ThreatLevel.High, "llRequestSimulatorData"); reply = "OpenSim"; break; default: + ScriptSleep(m_sleepMsOnRequestSimulatorData); return UUID.Zero.ToString(); // Raise no event } UUID rq = UUID.Random(); @@ -11678,6 +12462,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AsyncCommands. DataserverPlugin.DataserverReply(rq.ToString(), reply); + ScriptSleep(m_sleepMsOnRequestSimulatorData); return tid.ToString(); } catch(Exception) @@ -11692,7 +12477,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_UrlModule != null) - return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString(); + return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID, null).ToString(); return UUID.Zero.ToString(); } @@ -11708,31 +12493,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID key = new UUID(); if (UUID.TryParse(id, out key)) { - try - { - SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId); - if (obj != null) - return (double)obj.GetMass(); - // the object is null so the key is for an avatar - ScenePresence avatar = World.GetScenePresence(key); - if (avatar != null) - if (avatar.IsChildAgent) - // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass - // child agents have a mass of 1.0 - return 1; - else - return (double)avatar.GetMass(); - } - catch (KeyNotFoundException) + // return total object mass + SceneObjectPart part = World.GetSceneObjectPart(key); + if (part != null) + return part.ParentGroup.GetMass(); + + // the object is null so the key is for an avatar + ScenePresence avatar = World.GetScenePresence(key); + if (avatar != null) { - return 0; // The Object/Agent not in the region so just return zero + if (avatar.IsChildAgent) + { + // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass + // child agents have a mass of 1.0 + return 1; + } + else + { + return (double)avatar.GetMass(); + } } } return 0; } /// - /// illListReplaceList removes the sub-list defined by the inclusive indices + /// llListReplaceList removes the sub-list defined by the inclusive indices /// start and end and inserts the src list in its place. The inclusive /// nature of the indices means that at least one element must be deleted /// if the indices are within the bounds of the existing list. I.e. 2,2 @@ -11789,16 +12575,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // based upon end. Note that if end exceeds the upper // bound in this case, the entire destination list // is removed. - else + else if (start == 0) { if (end + 1 < dest.Length) - { return src + dest.GetSublist(end + 1, -1); - } else - { return src; - } + } + else // Start < 0 + { + if (end + 1 < dest.Length) + return dest.GetSublist(end + 1, -1); + else + return new LSL_List(); } } // Finally, if start > end, we strip away a prefix and @@ -11821,6 +12610,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (null != dm) dm.SendUrlToUser( new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url); + + ScriptSleep(m_sleepMsOnLoadURL); } public void llParcelMediaCommandList(LSL_List commandList) @@ -11833,7 +12624,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // according to the docs, this command only works if script owner and land owner are the same // lets add estate owners and gods, too, and use the generic permission check. ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition); - if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return; + if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia, false)) return; bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? byte loop = 0; @@ -12051,18 +12842,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (sp.currentParcelUUID == landData.GlobalID) { sp.ControllingClient.SendParcelMediaCommand(0x4, // TODO what is this? - (ParcelMediaCommandEnum)commandToSend, - time); + (ParcelMediaCommandEnum)commandToSend, time); } }); } else if (!presence.IsChildAgent) { presence.ControllingClient.SendParcelMediaCommand(0x4, // TODO what is this? - (ParcelMediaCommandEnum)commandToSend, - time); + (ParcelMediaCommandEnum)commandToSend, time); } } + ScriptSleep(m_sleepMsOnParcelMediaCommandList); } public LSL_List llParcelMediaQuery(LSL_List aList) @@ -12076,7 +12866,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (aList.Data[i] != null) { - switch ((ParcelMediaCommandEnum) aList.Data[i]) + switch ((ParcelMediaCommandEnum) Convert.ToInt32(aList.Data[i].ToString())) { case ParcelMediaCommandEnum.Url: list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaURL)); @@ -12102,6 +12892,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + ScriptSleep(m_sleepMsOnParcelMediaQuery); return list; } @@ -12110,6 +12901,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); Int64 tmp = 0; Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp); + ScriptSleep(m_sleepMsOnModPow); return Convert.ToInt32(tmp); } @@ -12131,15 +12923,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (quick_pay_buttons.Data.Length < 4) { - Error("llSetPayPrice", "List must have at least 4 elements"); - return; + int x; + for (x=quick_pay_buttons.Data.Length; x<= 4; x++) + { + quick_pay_buttons.Add(ScriptBaseClass.PAY_HIDE); + } } - m_host.ParentGroup.RootPart.PayPrice[0]=price; - - m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0]; - m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1]; - m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2]; - m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3]; + int[] nPrice = new int[5]; + nPrice[0] = price; + nPrice[1] = quick_pay_buttons.GetLSLIntegerItem(0); + nPrice[2] = quick_pay_buttons.GetLSLIntegerItem(1); + nPrice[3] = quick_pay_buttons.GetLSLIntegerItem(2); + nPrice[4] = quick_pay_buttons.GetLSLIntegerItem(3); + m_host.ParentGroup.RootPart.PayPrice = nPrice; m_host.ParentGroup.HasGroupChanged = true; } @@ -12156,7 +12952,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return Vector3.Zero; } - ScenePresence presence = World.GetScenePresence(m_host.OwnerID); +// ScenePresence presence = World.GetScenePresence(m_host.OwnerID); + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); if (presence != null) { LSL_Vector pos = new LSL_Vector(presence.CameraPosition); @@ -12179,7 +12976,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return Quaternion.Identity; } - ScenePresence presence = World.GetScenePresence(m_host.OwnerID); +// ScenePresence presence = World.GetScenePresence(m_host.OwnerID); + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); if (presence != null) { return new LSL_Rotation(presence.CameraRotation); @@ -12192,12 +12990,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); Deprecated("llSetPrimURL", "Use llSetPrimMediaParams instead"); + ScriptSleep(m_sleepMsOnSetPrimURL); } public void llRefreshPrimURL() { m_host.AddScriptLPS(1); Deprecated("llRefreshPrimURL"); + ScriptSleep(m_sleepMsOnRefreshPrimURL); } public LSL_String llEscapeURL(string url) @@ -12230,7 +13030,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, 0); - if (detectedParams == null) return; // only works on the first detected avatar + if (detectedParams == null) + { + if (m_host.ParentGroup.IsAttachment == true) + { + detectedParams = new DetectParams(); + detectedParams.Key = m_host.OwnerID; + } + else + { + return; + } + } ScenePresence avatar = World.GetScenePresence(detectedParams.Key); if (avatar != null) @@ -12238,6 +13049,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api avatar.ControllingClient.SendScriptTeleportRequest(m_host.Name, simname, pos, lookAt); } + ScriptSleep(m_sleepMsOnMapDestination); } public void llAddToLandBanList(string avatar, double hours) @@ -12245,7 +13057,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); UUID key; ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); - if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) + if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned, false)) { int expires = 0; if (hours != 0) @@ -12278,6 +13090,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land); } } + ScriptSleep(m_sleepMsOnAddToLandBanList); } public void llRemoveFromLandPassList(string avatar) @@ -12285,7 +13098,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); UUID key; ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); - if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed)) + if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManagePasses, false)) { if (UUID.TryParse(avatar, out key)) { @@ -12304,6 +13117,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } + ScriptSleep(m_sleepMsOnRemoveFromLandPassList); } public void llRemoveFromLandBanList(string avatar) @@ -12311,7 +13125,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); UUID key; ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); - if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) + if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned, false)) { if (UUID.TryParse(avatar, out key)) { @@ -12330,6 +13144,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } + ScriptSleep(m_sleepMsOnRemoveFromLandBanList); } public void llSetCameraParams(LSL_List rules) @@ -12542,19 +13357,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llXorBase64StringsCorrect(string str1, string str2) { m_host.AddScriptLPS(1); - string ret = String.Empty; - string src1 = llBase64ToString(str1); - string src2 = llBase64ToString(str2); - int c = 0; - for (int i = 0; i < src1.Length; i++) + + if (str1 == String.Empty) + return String.Empty; + if (str2 == String.Empty) + return str1; + + int len = str2.Length; + if ((len % 4) != 0) // LL is EVIL!!!! + { + while (str2.EndsWith("=")) + str2 = str2.Substring(0, str2.Length - 1); + + len = str2.Length; + int mod = len % 4; + + if (mod == 1) + str2 = str2.Substring(0, str2.Length - 1); + else if (mod == 2) + str2 += "=="; + else if (mod == 3) + str2 += "="; + } + + byte[] data1; + byte[] data2; + try + { + data1 = Convert.FromBase64String(str1); + data2 = Convert.FromBase64String(str2); + } + catch (Exception) + { + return new LSL_String(String.Empty); + } + + byte[] d2 = new Byte[data1.Length]; + int pos = 0; + + if (data1.Length <= data2.Length) + { + Array.Copy(data2, 0, d2, 0, data1.Length); + } + else { - ret += (char) (src1[i] ^ src2[c]); + while (pos < data1.Length) + { + len = data1.Length - pos; + if (len > data2.Length) + len = data2.Length; - c++; - if (c >= src2.Length) - c = 0; + Array.Copy(data2, 0, d2, pos, len); + pos += len; + } } - return llStringToBase64(ret); + + for (pos = 0 ; pos < data1.Length ; pos++ ) + data1[pos] ^= d2[pos]; + + return Convert.ToBase64String(data1); } public LSL_String llHTTPRequest(string url, LSL_List parameters, string body) @@ -12570,6 +13431,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api List param = new List(); bool ok; Int32 flag; + int nCustomHeaders = 0; for (int i = 0; i < parameters.Data.Length; i += 2) { @@ -12596,6 +13458,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //Second Life documentation for llHTTPRequest. for (int count = 1; count <= 8; ++count) { + if(nCustomHeaders >= 8) + { + Error("llHTTPRequest", "Max number of custom headers is 8, excess ignored"); + break; + } + //Enough parameters remaining for (another) header? if (parameters.Data.Length - i < 2) { @@ -12610,15 +13478,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api param.Add(parameters.Data[i].ToString()); param.Add(parameters.Data[i+1].ToString()); + nCustomHeaders++; //Have we reached the end of the list of headers? //End is marked by a string with a single digit. - if (i+2 >= parameters.Data.Length || - Char.IsDigit(parameters.Data[i].ToString()[0])) + if (i + 2 >= parameters.Data.Length || + Char.IsDigit(parameters.Data[i + 2].ToString()[0])) { break; } - i += 2; } } @@ -12658,16 +13526,72 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (userAgent != null) httpHeaders["User-Agent"] = userAgent; + // See if the URL contains any header hacks + string[] urlParts = url.Split(new char[] {'\n'}); + if (urlParts.Length > 1) + { + // Iterate the passed headers and parse them + for (int i = 1 ; i < urlParts.Length ; i++ ) + { + // The rest of those would be added to the body in SL. + // Let's not do that. + if (urlParts[i] == String.Empty) + break; + + // See if this could be a valid header + string[] headerParts = urlParts[i].Split(new char[] {':'}, 2); + if (headerParts.Length != 2) + continue; + + string headerName = headerParts[0].Trim(); + string headerValue = headerParts[1].Trim(); + + // Filter out headers that could be used to abuse + // another system or cloak the request + if (headerName.ToLower() == "x-secondlife-shard" || + headerName.ToLower() == "x-secondlife-object-name" || + headerName.ToLower() == "x-secondlife-object-key" || + headerName.ToLower() == "x-secondlife-region" || + headerName.ToLower() == "x-secondlife-local-position" || + headerName.ToLower() == "x-secondlife-local-velocity" || + headerName.ToLower() == "x-secondlife-local-rotation" || + headerName.ToLower() == "x-secondlife-owner-name" || + headerName.ToLower() == "x-secondlife-owner-key" || + headerName.ToLower() == "connection" || + headerName.ToLower() == "content-length" || + headerName.ToLower() == "from" || + headerName.ToLower() == "host" || + headerName.ToLower() == "proxy-authorization" || + headerName.ToLower() == "referer" || + headerName.ToLower() == "trailer" || + headerName.ToLower() == "transfer-encoding" || + headerName.ToLower() == "via" || + headerName.ToLower() == "authorization") + continue; + + httpHeaders[headerName] = headerValue; + } + + // Finally, strip any protocol specifier from the URL + url = urlParts[0].Trim(); + int idx = url.IndexOf(" HTTP/"); + if (idx != -1) + url = url.Substring(0, idx); + } + string authregex = @"^(https?:\/\/)(\w+):(\w+)@(.*)$"; Regex r = new Regex(authregex); int[] gnums = r.GetGroupNumbers(); Match m = r.Match(url); - if (m.Success) { - for (int i = 1; i < gnums.Length; i++) { + if (m.Success) + { + for (int i = 1; i < gnums.Length; i++) + { //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]]; //CaptureCollection cc = g.Captures; } - if (m.Groups.Count == 5) { + if (m.Groups.Count == 5) + { httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString()))); url = m.Groups[1].ToString() + m.Groups[4].ToString(); } @@ -12712,6 +13636,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } + ScriptSleep(m_sleepMsOnResetLandBanList); } public void llResetLandPassList() @@ -12728,6 +13653,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } + ScriptSleep(m_sleepMsOnResetLandPassList); } public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide) @@ -12785,6 +13711,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_Integer(detectedParams.Value)); } } + ScriptSleep(m_sleepMsOnGetParcelPrimOwners); return ret; } @@ -12871,6 +13798,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSL_List ret = new LSL_List(); UUID key = new UUID(); + + if (UUID.TryParse(id, out key)) { ScenePresence av = World.GetScenePresence(key); @@ -12888,13 +13817,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_String("")); break; case ScriptBaseClass.OBJECT_POS: - ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z)); - break; - case ScriptBaseClass.OBJECT_ROT: - ret.Add(new LSL_Rotation(av.GetWorldRotation())); + Vector3 avpos; + + if (av.ParentID != 0 && av.ParentPart != null && + av.ParentPart.ParentGroup != null && av.ParentPart.ParentGroup.RootPart != null ) + { + avpos = av.OffsetPosition; + + if(!av.LegacySitOffsets) + { + Vector3 sitOffset = (Zrot(av.Rotation)) * (av.Appearance.AvatarHeight * 0.02638f *2.0f); + avpos -= sitOffset; + } + + SceneObjectPart sitRoot = av.ParentPart.ParentGroup.RootPart; + avpos = sitRoot.GetWorldPosition() + avpos * sitRoot.GetWorldRotation(); + } + else + avpos = av.AbsolutePosition; + + ret.Add(new LSL_Vector((double)avpos.X, (double)avpos.Y, (double)avpos.Z)); + break; + case ScriptBaseClass.OBJECT_ROT: + Quaternion avrot = av.GetWorldRotation(); + ret.Add(new LSL_Rotation(avrot)); break; case ScriptBaseClass.OBJECT_VELOCITY: - ret.Add(new LSL_Vector(av.GetWorldVelocity())); + Vector3 avvel = av.GetWorldVelocity(); + ret.Add(new LSL_Vector((double)avvel.X, (double)avvel.Y, (double)avvel.Z)); break; case ScriptBaseClass.OBJECT_OWNER: ret.Add(new LSL_String(id)); @@ -12976,6 +13926,46 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_LAST_OWNER_ID: ret.Add(new LSL_Key(ScriptBaseClass.NULL_KEY)); break; + case ScriptBaseClass.OBJECT_CLICK_ACTION: + ret.Add(new LSL_Integer(0)); + break; + case ScriptBaseClass.OBJECT_OMEGA: + ret.Add(new LSL_Vector(Vector3.Zero)); + break; + case ScriptBaseClass.OBJECT_PRIM_COUNT: + List Attachments = av.GetAttachments(); + int count = 0; + try + { + foreach (SceneObjectGroup Attachment in Attachments) + count += Attachment.PrimCount; + } catch { }; + ret.Add(new LSL_Integer(count)); + break; + case ScriptBaseClass.OBJECT_TOTAL_INVENTORY_COUNT: + List invAttachments = av.GetAttachments(); + int invcount = 0; + try + { + foreach (SceneObjectGroup Attachment in invAttachments) + { + SceneObjectPart[] parts = Attachment.Parts; + int nparts = parts.Count(); + for(int i = 0; i < nparts; i++) + invcount += parts[i].Inventory.Count; + } + } catch { }; + ret.Add(new LSL_Integer(invcount)); + break; + case ScriptBaseClass.OBJECT_REZZER_KEY: + ret.Add(new LSL_Key(id)); + break; + case ScriptBaseClass.OBJECT_GROUP_TAG: + ret.Add(new LSL_String(av.Grouptitle)); + break; + case ScriptBaseClass.OBJECT_TEMP_ATTACHED: + ret.Add(new LSL_Integer(0)); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -13000,7 +13990,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_String(obj.Description)); break; case ScriptBaseClass.OBJECT_POS: - ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z)); + Vector3 opos = obj.AbsolutePosition; + ret.Add(new LSL_Vector(opos.X, opos.Y, opos.Z)); break; case ScriptBaseClass.OBJECT_ROT: Quaternion rot = Quaternion.Identity; @@ -13036,7 +14027,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - vel = obj.Velocity; + vel = obj.Velocity; } ret.Add(vel); @@ -13073,9 +14064,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // The value returned in SL for normal prims is prim count ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount)); break; - // The following 3 costs I have intentionaly coded to return zero. They are part of - // "Land Impact" calculations. These calculations are probably not applicable - // to OpenSim and are not yet complete in SL + + // costs below may need to be diferent for root parts, need to check case ScriptBaseClass.OBJECT_SERVER_COST: // The linden calculation is here // http://wiki.secondlife.com/wiki/Mesh/Mesh_Server_Weight @@ -13083,16 +14073,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_Float(0)); break; case ScriptBaseClass.OBJECT_STREAMING_COST: - // The linden calculation is here - // http://wiki.secondlife.com/wiki/Mesh/Mesh_Streaming_Cost - // The value returned in SL for normal prims looks like the prim count * 0.06 - ret.Add(new LSL_Float(0)); + // The value returned in SL for normal prims is prim count * 0.06 + ret.Add(new LSL_Float(obj.StreamingCost)); break; case ScriptBaseClass.OBJECT_PHYSICS_COST: - // The linden calculation is here - // http://wiki.secondlife.com/wiki/Mesh/Mesh_physics - // The value returned in SL for normal prims looks like the prim count - ret.Add(new LSL_Float(0)); + // The value returned in SL for normal prims is prim count + ret.Add(new LSL_Float(obj.PhysicsCost)); break; case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding ret.Add(new LSL_Float(0)); @@ -13152,6 +14138,39 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_LAST_OWNER_ID: ret.Add(new LSL_Key(obj.ParentGroup.LastOwnerID.ToString())); break; + case ScriptBaseClass.OBJECT_CLICK_ACTION: + ret.Add(new LSL_Integer(obj.ClickAction)); + break; + case ScriptBaseClass.OBJECT_OMEGA: + ret.Add(new LSL_Vector(obj.AngularVelocity)); + break; + case ScriptBaseClass.OBJECT_PRIM_COUNT: + ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount)); + break; + case ScriptBaseClass.OBJECT_TOTAL_INVENTORY_COUNT: + SceneObjectPart[] parts = obj.ParentGroup.Parts; + int nparts = parts.Count(); + int count = 0; + for(int i = 0; i < nparts; i++) + count += parts[i].Inventory.Count; + ret.Add(new LSL_Integer(count)); + break; + case ScriptBaseClass.OBJECT_REZZER_KEY: + ret.Add(new LSL_Key(obj.ParentGroup.RezzerID.ToString())); + break; + case ScriptBaseClass.OBJECT_GROUP_TAG: + ret.Add(new LSL_String(String.Empty)); + break; + case ScriptBaseClass.OBJECT_TEMP_ATTACHED: + if (obj.ParentGroup.AttachmentPoint != 0 && obj.ParentGroup.FromItemID == UUID.Zero) + { + ret.Add(new LSL_Integer(1)); + } + else + { + ret.Add(new LSL_Integer(0)); + } + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -13286,6 +14305,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(assetID).ToString()); + ScriptSleep(m_sleepMsOnGetNumberOfNotecardLines); return tid.ToString(); } @@ -13301,6 +14321,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(id).ToString()); }); + ScriptSleep(m_sleepMsOnGetNumberOfNotecardLines); return tid.ToString(); } @@ -13336,6 +14357,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AsyncCommands.DataserverPlugin.DataserverReply( reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); + ScriptSleep(m_sleepMsOnGetNotecardLine); return tid.ToString(); } @@ -13354,6 +14376,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); }); + ScriptSleep(m_sleepMsOnGetNotecardLine); return tid.ToString(); } @@ -13371,12 +14394,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules) { - SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim)); + SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim)); + + LSL_List result = new LSL_List(); if (obj != null && obj.OwnerID == m_host.OwnerID) - return GetEntityParams(obj, rules); + { + LSL_List remaining = GetPrimParams(obj, rules, ref result); - return new LSL_List(); + while (remaining.Length > 2) + { + int linknumber = remaining.GetLSLIntegerItem(0); + rules = remaining.GetSublist(1, -1); + List parts = GetLinkParts(linknumber); + + foreach (SceneObjectPart part in parts) + remaining = GetPrimParams(part, rules, ref result); + } + } + + return result; } public void print(string str) @@ -13390,6 +14427,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link) + { + List parts = GetLinkParts(link); + if (parts.Count < 1) + return 0; + + return GetNumberOfSides(parts[0]); + } + private string Name2Username(string name) { string[] parts = name.Split(new char[] {' '}); @@ -13432,7 +14478,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return rq.ToString(); } - +/* + private void SayShoutTimerElapsed(Object sender, ElapsedEventArgs args) + { + m_SayShoutCount = 0; + } +*/ private struct Tri { public Vector3 p1; @@ -13453,18 +14504,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return false; } - private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd) + private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd, bool skipPhys) { List contacts = new List(); Vector3 ab = rayEnd - rayStart; + float ablen = ab.Length(); World.ForEachScenePresence(delegate(ScenePresence sp) { + if(skipPhys && sp.PhysicsActor != null) + return; + Vector3 ac = sp.AbsolutePosition - rayStart; -// Vector3 bc = sp.AbsolutePosition - rayEnd; - double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); + double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / ablen); if (d > 1.5) return; @@ -13581,9 +14635,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ContactResult result = new ContactResult (); result.ConsumerID = group.LocalId; - result.Depth = intersection.distance; +// result.Depth = intersection.distance; result.Normal = intersection.normal; result.Pos = intersection.ipoint; + result.Depth = Vector3.Mag(rayStart - result.Pos); contacts.Add(result); }); @@ -13716,6 +14771,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return contacts[0]; } +/* + // not done: + private ContactResult[] testRay2NonPhysicalPhantom(Vector3 rayStart, Vector3 raydir, float raylenght) + { + ContactResult[] contacts = null; + World.ForEachSOG(delegate(SceneObjectGroup group) + { + if (m_host.ParentGroup == group) + return; + + if (group.IsAttachment) + return; + + if(group.RootPart.PhysActor != null) + return; + + contacts = group.RayCastGroupPartsOBBNonPhysicalPhantom(rayStart, raydir, raylenght); + }); + return contacts; + } +*/ public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) { @@ -13731,7 +14807,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Vector3 rayEnd = end; Vector3 dir = rayEnd - rayStart; - float dist = Vector3.Mag(dir); + float dist = dir.Length(); int count = 1; bool detectPhantom = false; @@ -13760,17 +14836,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL); bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); - if (World.SupportsRayCastFiltered()) { if (dist == 0) return list; - RayFilterFlags rayfilter = RayFilterFlags.ClosestAndBackCull; + RayFilterFlags rayfilter = RayFilterFlags.BackFaceCull; if (checkTerrain) rayfilter |= RayFilterFlags.land; -// if (checkAgents) -// rayfilter |= RayFilterFlags.agent; + if (checkAgents) + rayfilter |= RayFilterFlags.agent; if (checkPhysical) rayfilter |= RayFilterFlags.physical; if (checkNonPhysical) @@ -13796,16 +14871,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (physresults == null) { - list.Add(new LSL_Integer(-3)); // timeout error - return list; +// list.Add(new LSL_Integer(-3)); // timeout error +// return list; + results = new List(); } - - results = (List)physresults; + else + results = (List)physresults; // for now physics doesn't detect sitted avatars so do it outside physics if (checkAgents) { - ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd); + ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd, true); foreach (ContactResult r in agentHits) results.Add(r); } @@ -13821,12 +14897,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (ContactResult r in objectHits) results.Add(r); } + // Double check this because of current ODE distance problems + if (checkTerrain && dist > 60) + { + bool skipGroundCheck = false; + + foreach (ContactResult c in results) + { + if (c.ConsumerID == 0) // Physics gave us a ground collision + skipGroundCheck = true; + } + + if (!skipGroundCheck) + { + float tmp = dir.X * dir.X + dir.Y * dir.Y; + if(tmp > 2500) + { + ContactResult? groundContact = GroundIntersection(rayStart, rayEnd); + if (groundContact != null) + results.Add((ContactResult)groundContact); + } + } + } } else { if (checkAgents) { - ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd); + ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd, false); foreach (ContactResult r in agentHits) results.Add(r); } @@ -13841,13 +14939,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api results.Add(objectHits[iter]); } } - } - if (checkTerrain) - { - ContactResult? groundContact = GroundIntersection(rayStart, rayEnd); - if (groundContact != null) - results.Add((ContactResult)groundContact); + if (checkTerrain) + { + ContactResult? groundContact = GroundIntersection(rayStart, rayEnd); + if (groundContact != null) + results.Add((ContactResult)groundContact); + } } results.Sort(delegate(ContactResult a, ContactResult b) @@ -13908,10 +15006,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } list.Add(new LSL_Integer(values)); - return list; } + /// /// Implementation of llCastRay similar to SL 2015-04-21. /// http://wiki.secondlife.com/wiki/LlCastRay @@ -13935,7 +15033,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID userId = UUID.Zero; int msAvailable = 0; // Throttle per owner when attachment or "vehicle" (sat upon) - if (m_host.ParentGroup.IsAttachment || m_host.ParentGroup.GetSittingAvatars().Count > 0) + if (m_host.ParentGroup.IsAttachment || m_host.ParentGroup.GetSittingAvatarsCount() > 0) { userId = m_host.OwnerID; msAvailable = m_msPerAvatarInCastRay; @@ -13968,13 +15066,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api msAvailable -= m_castRayCalls[i].UsedMs; } } - } - // Return failure if not enough available time - if (msAvailable < m_msMinInCastRay) - { - result.Add(new LSL_Integer(ScriptBaseClass.RCERR_CAST_TIME_EXCEEDED)); - return result; + // Return failure if not enough available time + if (msAvailable < m_msMinInCastRay) + { + result.Add(new LSL_Integer(ScriptBaseClass.RCERR_CAST_TIME_EXCEEDED)); + return result; + } } // Initialize @@ -13987,7 +15085,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api int rejectTypes = 0; int dataFlags = 0; int maxHits = 1; - bool detectPhantom = false; + bool notdetectPhantom = true; for (int i = 0; i < options.Length; i += 2) { if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) @@ -13997,7 +15095,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) maxHits = options.GetLSLIntegerItem(i + 1); else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) - detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0); + notdetectPhantom = (options.GetLSLIntegerItem(i + 1) == 0); } if (maxHits > m_maxHitsInCastRay) maxHits = m_maxHitsInCastRay; @@ -14027,157 +15125,153 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.ForEachSOG( delegate(SceneObjectGroup group) { + if(group.IsDeleted || group.RootPart == null) + return; // Check group filters unless part filters are configured - bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); + bool isPhysical = (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); bool isNonphysical = !isPhysical; bool isPhantom = group.IsPhantom || group.IsVolumeDetect; bool isAttachment = group.IsAttachment; - bool doGroup = true; if (isPhysical && rejectPhysical) - doGroup = false; + return; if (isNonphysical && rejectNonphysical) - doGroup = false; - if (isPhantom && detectPhantom) - doGroup = true; - if (m_filterPartsInCastRay) - doGroup = true; + return; + if (isPhantom && notdetectPhantom) + return; if (isAttachment && !m_doAttachmentsInCastRay) - doGroup = false; + return; + // Parse object/group if passed filters - if (doGroup) + // Iterate over all prims/parts in object/group + foreach(SceneObjectPart part in group.Parts) { - // Iterate over all prims/parts in object/group - foreach(SceneObjectPart part in group.Parts) + // ignore PhysicsShapeType.None as physics engines do + // or we will get into trouble in future + if(part.PhysicsShapeType == (byte)PhysicsShapeType.None) + continue; + isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); + isNonphysical = !isPhysical; + isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || + (part.VolumeDetectActive); + + if (isPhysical && rejectPhysical) + continue; + if (isNonphysical && rejectNonphysical) + continue; + if (isPhantom && notdetectPhantom) + continue; + + // Parse prim/part and project ray if passed filters + Vector3 scalePart = part.Scale; + Vector3 posPart = part.GetWorldPosition(); + Quaternion rotPart = part.GetWorldRotation(); + Quaternion rotPartInv = Quaternion.Inverse(rotPart); + Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; + Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; + + // Filter parts by shape bounding boxes + Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); + if (!part.Shape.SculptEntry) + shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); + shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); + if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) { - // Check part filters if configured - if (m_filterPartsInCastRay) - { - isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); - isNonphysical = !isPhysical; - isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive); - bool doPart = true; - if (isPhysical && rejectPhysical) - doPart = false; - if (isNonphysical && rejectNonphysical) - doPart = false; - if (isPhantom && detectPhantom) - doPart = true; - if (!doPart) - continue; - } - - // Parse prim/part and project ray if passed filters - Vector3 scalePart = part.Scale; - Vector3 posPart = part.GetWorldPosition(); - Quaternion rotPart = part.GetWorldRotation(); - Quaternion rotPartInv = Quaternion.Inverse(rotPart); - Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; - Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; - - // Filter parts by shape bounding boxes - Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); - if (!part.Shape.SculptEntry) - shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); - shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); - if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) - { - // Prepare data needed to check for ray hits - RayTrans rayTrans = new RayTrans(); - rayTrans.PartId = part.UUID; - rayTrans.GroupId = part.ParentGroup.UUID; - rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; - rayTrans.ScalePart = scalePart; - rayTrans.PositionPart = posPart; - rayTrans.RotationPart = rotPart; - rayTrans.ShapeNeedsEnds = true; - rayTrans.Position1Ray = pos1Ray; - rayTrans.Position1RayProj = pos1RayProj; - rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; - - // Get detail level depending on type - int lod = 0; - // Mesh detail level - if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) - lod = (int)m_meshLodInCastRay; - // Sculpt detail level - else if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) - lod = (int)m_sculptLodInCastRay; - // Shape detail level - else if (!part.Shape.SculptEntry) - lod = (int)m_primLodInCastRay; - - // Try to get cached mesh if configured - ulong meshKey = 0; - FacetedMesh mesh = null; - if (m_useMeshCacheInCastRay) + // Prepare data needed to check for ray hits + RayTrans rayTrans = new RayTrans(); + rayTrans.PartId = part.UUID; + rayTrans.GroupId = part.ParentGroup.UUID; + rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; + rayTrans.ScalePart = scalePart; + rayTrans.PositionPart = posPart; + rayTrans.RotationPart = rotPart; + rayTrans.ShapeNeedsEnds = true; + rayTrans.Position1Ray = pos1Ray; + rayTrans.Position1RayProj = pos1RayProj; + rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; + + // Get detail level depending on type + int lod = 0; + // Mesh detail level + if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) + lod = (int)m_meshLodInCastRay; + // Sculpt detail level + else if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) + lod = (int)m_sculptLodInCastRay; + // Shape detail level + else if (!part.Shape.SculptEntry) + lod = (int)m_primLodInCastRay; + + // Try to get cached mesh if configured + ulong meshKey = 0; + FacetedMesh mesh = null; + if (m_useMeshCacheInCastRay) + { + meshKey = part.Shape.GetMeshKey(Vector3.One, (float)(4 << lod)); + lock (m_cachedMeshes) { - meshKey = part.Shape.GetMeshKey(Vector3.One, (float)(4 << lod)); - lock (m_cachedMeshes) - { - m_cachedMeshes.TryGetValue(meshKey, out mesh); - } + m_cachedMeshes.TryGetValue(meshKey, out mesh); } + } - // Create mesh if no cached mesh - if (mesh == null) + // Create mesh if no cached mesh + if (mesh == null) + { + // Make an OMV prim to be able to mesh part + Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); + byte[] sculptAsset = null; + if (omvPrim.Sculpt != null) + sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); + + // When part is mesh, get mesh + if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) { - // Make an OMV prim to be able to mesh part - Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); - byte[] sculptAsset = null; - if (omvPrim.Sculpt != null) - sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); - - // When part is mesh, get mesh - if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) - { - AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); - FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); - meshAsset = null; - } + AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); + FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); + meshAsset = null; + } - // When part is sculpt, create mesh - // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. - else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) + // When part is sculpt, create mesh + // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. + else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) + { + IJ2KDecoder imgDecoder = World.RequestModuleInterface(); + if (imgDecoder != null) { - IJ2KDecoder imgDecoder = World.RequestModuleInterface(); - if (imgDecoder != null) + Image sculpt = imgDecoder.DecodeToImage(sculptAsset); + if (sculpt != null) { - Image sculpt = imgDecoder.DecodeToImage(sculptAsset); - if (sculpt != null) - { - mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); - sculpt.Dispose(); - } + mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); + sculpt.Dispose(); } - } - - // When part is shape, create mesh - else if (omvPrim.Sculpt == null) - { - if ( - omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && - omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && - omvPrim.PrimData.PathSkew == 0.0 && - omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 - ) - rayTrans.ShapeNeedsEnds = false; - mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); } + } + + // When part is shape, create mesh + else if (omvPrim.Sculpt == null) + { + if ( + omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && + omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && + omvPrim.PrimData.PathSkew == 0.0 && + omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 + ) + rayTrans.ShapeNeedsEnds = false; + mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); + } - // Cache mesh if configured - if (m_useMeshCacheInCastRay && mesh != null) + // Cache mesh if configured + if (m_useMeshCacheInCastRay && mesh != null) + { + lock(m_cachedMeshes) { - lock(m_cachedMeshes) - { - if (!m_cachedMeshes.ContainsKey(meshKey)) - m_cachedMeshes.Add(meshKey, mesh); - } + if (!m_cachedMeshes.ContainsKey(meshKey)) + m_cachedMeshes.Add(meshKey, mesh); } } - // Check mesh for ray hits - AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); - mesh = null; } + // Check mesh for ray hits + AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); + mesh = null; } } } @@ -14362,13 +15456,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Add to throttle data stopWatch.Stop(); - CastRayCall castRayCall = new CastRayCall(); - castRayCall.RegionId = regionId; - castRayCall.UserId = userId; - castRayCall.CalledMs = calledMs; - castRayCall.UsedMs = (int)stopWatch.ElapsedMilliseconds; lock (m_castRayCalls) { + CastRayCall castRayCall = new CastRayCall(); + castRayCall.RegionId = regionId; + castRayCall.UserId = userId; + castRayCall.CalledMs = calledMs; + castRayCall.UsedMs = (int)stopWatch.ElapsedMilliseconds; m_castRayCalls.Add(castRayCall); } @@ -14813,7 +15907,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_ADD: if (!isAccount) return 0; if (estate.HasAccess(id)) return 1; - if (estate.IsBanned(id)) + if (estate.IsBanned(id, World.GetUserFlags(id))) estate.RemoveBan(id); estate.AddEstateUser(id); break; @@ -14832,14 +15926,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_ADD: if (!isAccount) return 0; - if (estate.IsBanned(id)) return 1; + if (estate.IsBanned(id, World.GetUserFlags(id))) return 1; EstateBan ban = new EstateBan(); ban.EstateID = estate.EstateID; ban.BannedUserID = id; estate.AddBan(ban); break; case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_REMOVE: - if (!isAccount || !estate.IsBanned(id)) return 0; + if (!isAccount || !estate.IsBanned(id, World.GetUserFlags(id))) return 0; estate.RemoveBan(id); break; default: return 0; @@ -14898,13 +15992,62 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llCollisionSprite(string impact_sprite) { m_host.AddScriptLPS(1); - NotImplemented("llCollisionSprite"); + // Viewer 2.0 broke this and it's likely LL has no intention + // of fixing it. Therefore, letting this be a NOP seems appropriate. } public void llGodLikeRezObject(string inventory, LSL_Vector pos) { m_host.AddScriptLPS(1); - NotImplemented("llGodLikeRezObject"); + + if (!World.Permissions.IsGod(m_host.OwnerID)) + NotImplemented("llGodLikeRezObject"); + + AssetBase rezAsset = World.AssetService.Get(inventory); + if (rezAsset == null) + { + llSay(0, "Asset not found"); + return; + } + + SceneObjectGroup group = null; + + try + { + string xmlData = Utils.BytesToString(rezAsset.Data); + group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); + } + catch + { + llSay(0, "Asset not found"); + return; + } + + if (group == null) + { + llSay(0, "Asset not found"); + return; + } + + group.RootPart.AttachedPos = group.AbsolutePosition; + + group.ResetIDs(); + + Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z); + World.AddNewSceneObject(group, true, llpos, Quaternion.Identity, Vector3.Zero); + group.CreateScriptInstances(0, true, World.DefaultScriptEngine, 3); + group.ScheduleGroupForFullUpdate(); + + // 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])); } public LSL_String llTransferLindenDollars(string destination, int amount) @@ -14918,6 +16061,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api try { + if (amount <= 0) + { + replydata = "INVALID_AMOUNT"; + return; + } + TaskInventoryItem item = m_item; if (item == null) { @@ -14925,6 +16074,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } + if (m_host.OwnerID == m_host.GroupID) + { + replydata = "GROUP_OWNED"; + return; + } + m_host.AddScriptLPS(1); if (item.PermsGranter == UUID.Zero) @@ -14947,6 +16102,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } + UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, toID); + if (account == null) + { + replydata = "LINDENDOLLAR_ENTITYDOESNOTEXIST"; + return; + } + IMoneyModule money = World.RequestModuleInterface(); if (money == null) @@ -14955,8 +16117,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - bool result = money.ObjectGiveMoney( - m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount); + string reason; + bool result = money.ObjectGiveMoney( m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount, txn, out reason); if (result) { @@ -14964,7 +16126,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - replydata = "LINDENDOLLAR_INSUFFICIENTFUNDS"; + replydata = reason; } finally { @@ -14981,6 +16143,1366 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } #endregion + + + protected LSL_List SetPrimParams(ScenePresence av, LSL_List rules, string originFunc, ref uint rulesParsed) + { + //This is a special version of SetPrimParams to deal with avatars which are sitting on the linkset. + + int idx = 0; + int idxStart = 0; + + bool positionChanged = false; + try + { + while (idx < rules.Length) + { + ++rulesParsed; + int code = rules.GetLSLIntegerItem(idx++); + + int remain = rules.Length - idx; + idxStart = idx; + + switch (code) + { + case (int)ScriptBaseClass.PRIM_POSITION: + case (int)ScriptBaseClass.PRIM_POS_LOCAL: + { + if (remain < 1) + return new LSL_List(); + + LSL_Vector v; + v = rules.GetVector3Item(idx++); + + if(!av.LegacySitOffsets) + { + LSL_Vector sitOffset = (llRot2Up(new LSL_Rotation(av.Rotation.X, av.Rotation.Y, av.Rotation.Z, av.Rotation.W)) * av.Appearance.AvatarHeight * 0.02638f); + + v = v + 2 * sitOffset; + } + + av.OffsetPosition = new Vector3((float)v.x, (float)v.y, (float)v.z); + positionChanged = true; + } + break; + + case (int)ScriptBaseClass.PRIM_ROTATION: + { + if (remain < 1) + return new LSL_List(); + + Quaternion r; + r = rules.GetQuaternionItem(idx++); + + av.Rotation = m_host.GetWorldRotation() * r; + positionChanged = true; + } + break; + + case (int)ScriptBaseClass.PRIM_ROT_LOCAL: + { + if (remain < 1) + return new LSL_List(); + + LSL_Rotation r; + r = rules.GetQuaternionItem(idx++); + + av.Rotation = r; + positionChanged = true; + } + break; + + // parse rest doing nothing but number of parameters error check + case (int)ScriptBaseClass.PRIM_SIZE: + case (int)ScriptBaseClass.PRIM_MATERIAL: + case (int)ScriptBaseClass.PRIM_PHANTOM: + case (int)ScriptBaseClass.PRIM_PHYSICS: + case (int)ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE: + case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ: + case (int)ScriptBaseClass.PRIM_NAME: + case (int)ScriptBaseClass.PRIM_DESC: + if (remain < 1) + return new LSL_List(); + idx++; + break; + + case (int)ScriptBaseClass.PRIM_GLOW: + case (int)ScriptBaseClass.PRIM_FULLBRIGHT: + case (int)ScriptBaseClass.PRIM_TEXGEN: + if (remain < 2) + return new LSL_List(); + idx += 2; + break; + + case (int)ScriptBaseClass.PRIM_TYPE: + if (remain < 3) + return new LSL_List(); + code = (int)rules.GetLSLIntegerItem(idx++); + remain = rules.Length - idx; + switch (code) + { + case (int)ScriptBaseClass.PRIM_TYPE_BOX: + case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER: + case (int)ScriptBaseClass.PRIM_TYPE_PRISM: + if (remain < 6) + return new LSL_List(); + idx += 6; + break; + + case (int)ScriptBaseClass.PRIM_TYPE_SPHERE: + if (remain < 5) + return new LSL_List(); + idx += 5; + break; + + case (int)ScriptBaseClass.PRIM_TYPE_TORUS: + case (int)ScriptBaseClass.PRIM_TYPE_TUBE: + case (int)ScriptBaseClass.PRIM_TYPE_RING: + if (remain < 11) + return new LSL_List(); + idx += 11; + break; + + case (int)ScriptBaseClass.PRIM_TYPE_SCULPT: + if (remain < 2) + return new LSL_List(); + idx += 2; + break; + } + break; + + case (int)ScriptBaseClass.PRIM_COLOR: + case (int)ScriptBaseClass.PRIM_TEXT: + case (int)ScriptBaseClass.PRIM_BUMP_SHINY: + case (int)ScriptBaseClass.PRIM_OMEGA: + case (int)ScriptBaseClass.PRIM_SIT_TARGET: + if (remain < 3) + return new LSL_List(); + idx += 3; + break; + + case (int)ScriptBaseClass.PRIM_TEXTURE: + case (int)ScriptBaseClass.PRIM_POINT_LIGHT: + case (int)ScriptBaseClass.PRIM_PHYSICS_MATERIAL: + if (remain < 5) + return new LSL_List(); + idx += 5; + break; + + case (int)ScriptBaseClass.PRIM_FLEXIBLE: + if (remain < 7) + return new LSL_List(); + + idx += 7; + break; + + case (int)ScriptBaseClass.PRIM_LINK_TARGET: + if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. + return new LSL_List(); + + return rules.GetSublist(idx, -1); + } + } + } + catch (InvalidCastException e) + { + Error(originFunc,string.Format( + " error running rule #{0}: arg #{1} {2}", + rulesParsed, idx - idxStart, e.Message)); + } + finally + { + if (positionChanged) + av.SendTerseUpdateToAllClients(); + } + return new LSL_List(); + } + + public LSL_List GetPrimParams(ScenePresence avatar, LSL_List rules, ref LSL_List res) + { + // avatars case + // replies as SL wiki + +// SceneObjectPart sitPart = avatar.ParentPart; // most likelly it will be needed + SceneObjectPart sitPart = World.GetSceneObjectPart(avatar.ParentID); // maybe better do this expensive search for it in case it's gone?? + + int idx = 0; + while (idx < rules.Length) + { + int code = (int)rules.GetLSLIntegerItem(idx++); + int remain = rules.Length - idx; + + switch (code) + { + case (int)ScriptBaseClass.PRIM_MATERIAL: + res.Add(new LSL_Integer((int)SOPMaterialData.SopMaterial.Flesh)); + break; + + case (int)ScriptBaseClass.PRIM_PHYSICS: + res.Add(new LSL_Integer(0)); + break; + + case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ: + res.Add(new LSL_Integer(0)); + break; + + case (int)ScriptBaseClass.PRIM_PHANTOM: + res.Add(new LSL_Integer(0)); + break; + + case (int)ScriptBaseClass.PRIM_POSITION: + Vector3 pos; + + if (sitPart.ParentGroup.RootPart != null) + { + pos = avatar.OffsetPosition; + + if(!avatar.LegacySitOffsets) + { + Vector3 sitOffset = (Zrot(avatar.Rotation)) * (avatar.Appearance.AvatarHeight * 0.02638f *2.0f); + pos -= sitOffset; + } + + SceneObjectPart sitroot = sitPart.ParentGroup.RootPart; + pos = sitroot.AbsolutePosition + pos * sitroot.GetWorldRotation(); + } + else + pos = avatar.AbsolutePosition; + + res.Add(new LSL_Vector(pos.X,pos.Y,pos.Z)); + break; + + case (int)ScriptBaseClass.PRIM_SIZE: + Vector3 s = avatar.Appearance.AvatarSize; + res.Add(new LSL_Vector(s.X, s.Y, s.Z)); + + break; + + case (int)ScriptBaseClass.PRIM_ROTATION: + res.Add(new LSL_Rotation(avatar.GetWorldRotation())); + break; + + case (int)ScriptBaseClass.PRIM_TYPE: + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TYPE_BOX)); + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_HOLE_DEFAULT)); + res.Add(new LSL_Vector(0f,1.0f,0f)); + res.Add(new LSL_Float(0.0f)); + res.Add(new LSL_Vector(0, 0, 0)); + res.Add(new LSL_Vector(1.0f,1.0f,0f)); + res.Add(new LSL_Vector(0, 0, 0)); + break; + + case (int)ScriptBaseClass.PRIM_TEXTURE: + if (remain < 1) + return new LSL_List(); + + int face = (int)rules.GetLSLIntegerItem(idx++); + if (face == ScriptBaseClass.ALL_SIDES) + { + for (face = 0; face < 21; face++) + { + res.Add(new LSL_String("")); + res.Add(new LSL_Vector(0,0,0)); + res.Add(new LSL_Vector(0,0,0)); + res.Add(new LSL_Float(0.0)); + } + } + else + { + if (face >= 0 && face < 21) + { + res.Add(new LSL_String("")); + res.Add(new LSL_Vector(0,0,0)); + res.Add(new LSL_Vector(0,0,0)); + res.Add(new LSL_Float(0.0)); + } + } + break; + + case (int)ScriptBaseClass.PRIM_COLOR: + if (remain < 1) + return new LSL_List(); + + face = (int)rules.GetLSLIntegerItem(idx++); + + if (face == ScriptBaseClass.ALL_SIDES) + { + for (face = 0; face < 21; face++) + { + res.Add(new LSL_Vector(0,0,0)); + res.Add(new LSL_Float(0)); + } + } + else + { + res.Add(new LSL_Vector(0,0,0)); + res.Add(new LSL_Float(0)); + } + break; + + case (int)ScriptBaseClass.PRIM_BUMP_SHINY: + if (remain < 1) + return new LSL_List(); + face = (int)rules.GetLSLIntegerItem(idx++); + + if (face == ScriptBaseClass.ALL_SIDES) + { + for (face = 0; face < 21; face++) + { + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_SHINY_NONE)); + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_BUMP_NONE)); + } + } + else + { + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_SHINY_NONE)); + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_BUMP_NONE)); + } + break; + + case (int)ScriptBaseClass.PRIM_FULLBRIGHT: + if (remain < 1) + return new LSL_List(); + face = (int)rules.GetLSLIntegerItem(idx++); + + if (face == ScriptBaseClass.ALL_SIDES) + { + for (face = 0; face < 21; face++) + { + res.Add(new LSL_Integer(ScriptBaseClass.FALSE)); + } + } + else + { + res.Add(new LSL_Integer(ScriptBaseClass.FALSE)); + } + break; + + case (int)ScriptBaseClass.PRIM_FLEXIBLE: + res.Add(new LSL_Integer(0)); + res.Add(new LSL_Integer(0));// softness + res.Add(new LSL_Float(0.0f)); // gravity + res.Add(new LSL_Float(0.0f)); // friction + res.Add(new LSL_Float(0.0f)); // wind + res.Add(new LSL_Float(0.0f)); // tension + res.Add(new LSL_Vector(0f,0f,0f)); + break; + + case (int)ScriptBaseClass.PRIM_TEXGEN: + // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR) + if (remain < 1) + return new LSL_List(); + face = (int)rules.GetLSLIntegerItem(idx++); + + if (face == ScriptBaseClass.ALL_SIDES) + { + for (face = 0; face < 21; face++) + { + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT)); + } + } + else + { + res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT)); + } + break; + + case (int)ScriptBaseClass.PRIM_POINT_LIGHT: + res.Add(new LSL_Integer(0)); + res.Add(new LSL_Vector(0f,0f,0f)); + res.Add(new LSL_Float(0f)); // intensity + res.Add(new LSL_Float(0f)); // radius + res.Add(new LSL_Float(0f)); // falloff + break; + + case (int)ScriptBaseClass.PRIM_GLOW: + if (remain < 1) + return new LSL_List(); + face = (int)rules.GetLSLIntegerItem(idx++); + + if (face == ScriptBaseClass.ALL_SIDES) + { + for (face = 0; face < 21; face++) + { + res.Add(new LSL_Float(0f)); + } + } + else + { + res.Add(new LSL_Float(0f)); + } + break; + + case (int)ScriptBaseClass.PRIM_TEXT: + res.Add(new LSL_String("")); + res.Add(new LSL_Vector(0f,0f,0f)); + res.Add(new LSL_Float(1.0f)); + break; + + case (int)ScriptBaseClass.PRIM_NAME: + res.Add(new LSL_String(avatar.Name)); + break; + + case (int)ScriptBaseClass.PRIM_DESC: + res.Add(new LSL_String("")); + break; + + case (int)ScriptBaseClass.PRIM_ROT_LOCAL: + Quaternion lrot = avatar.Rotation; + res.Add(new LSL_Rotation(lrot.X, lrot.Y, lrot.Z, lrot.W)); + break; + + case (int)ScriptBaseClass.PRIM_POS_LOCAL: + Vector3 lpos = avatar.OffsetPosition; + + if(!avatar.LegacySitOffsets) + { + Vector3 lsitOffset = (Zrot(avatar.Rotation)) * (avatar.Appearance.AvatarHeight * 0.02638f * 2.0f); + lpos -= lsitOffset; + } + + res.Add(new LSL_Vector(lpos.X,lpos.Y,lpos.Z)); + break; + + case (int)ScriptBaseClass.PRIM_LINK_TARGET: + if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless. + return new LSL_List(); + + return rules.GetSublist(idx, -1); + } + } + + return new LSL_List(); + } + + public void llSetAnimationOverride(LSL_String animState, LSL_String anim) + { + string state = String.Empty; + + foreach (KeyValuePair kvp in MovementAnimationsForLSL) + { + if (kvp.Value.ToLower() == ((string)animState).ToLower()) + { + state = kvp.Key; + break; + } + } + + if (state == String.Empty) + { + llShout(ScriptBaseClass.DEBUG_CHANNEL, "Invalid animation state " + animState); + return; + } + + if (m_item.PermsGranter == UUID.Zero) + { + llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations"); + return; + } + + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_OVERRIDE_ANIMATIONS) == 0) + { + llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations"); + return; + } + + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); + + if (presence == null) + return; + + UUID animID; + + animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation); + + if (animID == UUID.Zero) + { + String animupper = ((string)anim).ToUpperInvariant(); + DefaultAvatarAnimations.AnimsUUID.TryGetValue(animupper, out animID); + } + + if (animID == UUID.Zero) + { + llShout(ScriptBaseClass.DEBUG_CHANNEL, "Animation not found"); + return; + } + + presence.SetAnimationOverride(state, animID); + } + + public void llResetAnimationOverride(LSL_String animState) + { + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); + if (presence == null) + return; + + if (m_item.PermsGranter == UUID.Zero) + { + llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations"); + return; + } + + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_OVERRIDE_ANIMATIONS) == 0) + { + llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations"); + return; + } + + if (animState == "ALL") + { + presence.SetAnimationOverride("ALL", UUID.Zero); + return; + } + + string state = String.Empty; + + foreach (KeyValuePair kvp in MovementAnimationsForLSL) + { + if (kvp.Value.ToLower() == ((string)animState).ToLower()) + { + state = kvp.Key; + break; + } + } + + if (state == String.Empty) + { + return; + } + + presence.SetAnimationOverride(state, UUID.Zero); + } + + public LSL_String llGetAnimationOverride(LSL_String animState) + { + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); + if (presence == null) + return String.Empty; + + if (m_item.PermsGranter == UUID.Zero) + { + llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations"); + return String.Empty; + } + + if ((m_item.PermsMask & (ScriptBaseClass.PERMISSION_OVERRIDE_ANIMATIONS | ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION)) == 0) + { + llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations"); + return String.Empty; + } + + string state = String.Empty; + + foreach (KeyValuePair kvp in MovementAnimationsForLSL) + { + if (kvp.Value.ToLower() == ((string)animState).ToLower()) + { + state = kvp.Key; + break; + } + } + + if (state == String.Empty) + { + return String.Empty; + } + + UUID animID = presence.GetAnimationOverride(state); + if (animID == UUID.Zero) + return animState; + + foreach (KeyValuePair kvp in DefaultAvatarAnimations.AnimsUUID) + { + if (kvp.Value == animID) + return kvp.Key.ToLower(); + } + + foreach (TaskInventoryItem item in m_host.Inventory.GetInventoryItems()) + { + if (item.AssetID == animID) + return item.Name; + } + + return String.Empty; + } + + public LSL_List llJson2List(LSL_String json) + { + if(String.IsNullOrEmpty(json)) + return new LSL_List(); + if(json == "[]") + return new LSL_List(); + if(json == "{}") + return new LSL_List(); + char first = ((string)json)[0]; + + if(first != '[' && first !='{') + { + // we already have a single element + LSL_List l = new LSL_List(); + l.Add(json); + return l; + } + + LitJson.JsonData jsdata; + try + { + jsdata = LitJson.JsonMapper.ToObject(json); + } + catch (Exception e) + { + string m = e.Message; // debug point + return json; + } + try + { + return JsonParseTop(jsdata); + } + catch (Exception e) + { + string m = e.Message; // debug point + return (LSL_String)ScriptBaseClass.JSON_INVALID; + } + } + + private LSL_List JsonParseTop(LitJson.JsonData elem) + { + LSL_List retl = new LSL_List(); + if(elem == null) + retl.Add((LSL_String)ScriptBaseClass.JSON_NULL); + + LitJson.JsonType elemType = elem.GetJsonType(); + switch (elemType) + { + case LitJson.JsonType.Int: + retl.Add(new LSL_Integer((int)elem)); + return retl; + case LitJson.JsonType.Boolean: + retl.Add((LSL_String)((bool)elem ? ScriptBaseClass.JSON_TRUE : ScriptBaseClass.JSON_FALSE)); + return retl; + case LitJson.JsonType.Double: + retl.Add(new LSL_Float((double)elem)); + return retl; + case LitJson.JsonType.None: + retl.Add((LSL_String)ScriptBaseClass.JSON_NULL); + return retl; + case LitJson.JsonType.String: + retl.Add(new LSL_String((string)elem)); + return retl; + case LitJson.JsonType.Array: + foreach (LitJson.JsonData subelem in elem) + retl.Add(JsonParseTopNodes(subelem)); + return retl; + case LitJson.JsonType.Object: + IDictionaryEnumerator e = ((IOrderedDictionary)elem).GetEnumerator(); + while (e.MoveNext()) + { + retl.Add(new LSL_String((string)e.Key)); + retl.Add(JsonParseTopNodes((LitJson.JsonData)e.Value)); + } + return retl; + default: + throw new Exception(ScriptBaseClass.JSON_INVALID); + } + } + + private object JsonParseTopNodes(LitJson.JsonData elem) + { + if(elem == null) + return ((LSL_String)ScriptBaseClass.JSON_NULL); + + LitJson.JsonType elemType = elem.GetJsonType(); + switch (elemType) + { + case LitJson.JsonType.Int: + return (new LSL_Integer((int)elem)); + case LitJson.JsonType.Boolean: + return ((bool)elem ? (LSL_String)ScriptBaseClass.JSON_TRUE : (LSL_String)ScriptBaseClass.JSON_FALSE); + case LitJson.JsonType.Double: + return (new LSL_Float((double)elem)); + case LitJson.JsonType.None: + return ((LSL_String)ScriptBaseClass.JSON_NULL); + case LitJson.JsonType.String: + return (new LSL_String((string)elem)); + case LitJson.JsonType.Array: + case LitJson.JsonType.Object: + string s = LitJson.JsonMapper.ToJson(elem); + return (LSL_String)s; + default: + throw new Exception(ScriptBaseClass.JSON_INVALID); + } + } + + public LSL_String llList2Json(LSL_String type, LSL_List values) + { + try + { + StringBuilder sb = new StringBuilder(); + if (type == ScriptBaseClass.JSON_ARRAY) + { + sb.Append("["); + int i= 0; + foreach (object o in values.Data) + { + sb.Append(ListToJson(o)); + if((i++) < values.Data.Length - 1) + sb.Append(","); + } + sb.Append("]"); + return (LSL_String)sb.ToString();; + } + else if (type == ScriptBaseClass.JSON_OBJECT) + { + sb.Append("{"); + for (int i = 0; i < values.Data.Length; i += 2) + { + if (!(values.Data[i] is LSL_String)) + return ScriptBaseClass.JSON_INVALID; + string key = ((LSL_String)values.Data[i]).m_string; + key = EscapeForJSON(key, true); + sb.Append(key); + sb.Append(":"); + sb.Append(ListToJson(values.Data[i+1])); + if(i < values.Data.Length - 2) + sb.Append(","); + } + sb.Append("}"); + return (LSL_String)sb.ToString(); + } + return ScriptBaseClass.JSON_INVALID; + } + catch + { + return ScriptBaseClass.JSON_INVALID; + } + } + + private string ListToJson(object o) + { + if (o is LSL_Float || o is double) + { + double float_val; + if (o is double) + float_val = ((double)o); + else + float_val = ((LSL_Float)o).value; + + if(double.IsInfinity(float_val)) + return "\"Inf\""; + if(double.IsNaN(float_val)) + return "\"NaN\""; + + return ((LSL_Float)float_val).ToString(); + } + if (o is LSL_Integer || o is int) + { + int i; + if (o is int) + i = ((int)o); + else + i = ((LSL_Integer)o).value; + return i.ToString(); + } + if (o is LSL_Rotation) + { + StringBuilder sb = new StringBuilder(128); + sb.Append("\""); + LSL_Rotation r = (LSL_Rotation)o; + sb.Append(r.ToString()); + sb.Append("\""); + return sb.ToString(); + } + if (o is LSL_Vector) + { + StringBuilder sb = new StringBuilder(128); + sb.Append("\""); + LSL_Vector v = (LSL_Vector)o; + sb.Append(v.ToString()); + sb.Append("\""); + return sb.ToString(); + } + if (o is LSL_String || o is string) + { + string str; + if (o is string) + str = ((string)o); + else + str = ((LSL_String)o).m_string; + + if(str == ScriptBaseClass.JSON_TRUE || str == "true") + return "true"; + if(str == ScriptBaseClass.JSON_FALSE ||str == "false") + return "false"; + if(str == ScriptBaseClass.JSON_NULL || str == "null") + return "null"; + str.Trim(); + if (str[0] == '{') + return str; + if (str[0] == '[') + return str; + return EscapeForJSON(str, true); + } + throw new IndexOutOfRangeException(); + } + + private string EscapeForJSON(string s, bool AddOuter) + { + int i; + char c; + String t; + int len = s.Length; + + StringBuilder sb = new StringBuilder(len + 64); + if(AddOuter) + sb.Append("\""); + + for (i = 0; i < len; i++) + { + c = s[i]; + switch (c) + { + case '\\': + case '"': + case '/': + sb.Append('\\'); + sb.Append(c); + break; + case '\b': + sb.Append("\\b"); + break; + case '\t': + sb.Append("\\t"); + break; + case '\n': + sb.Append("\\n"); + break; + case '\f': + sb.Append("\\f"); + break; + case '\r': + sb.Append("\\r"); + break; + default: + if (c < ' ') + { + t = "000" + String.Format("X", c); + sb.Append("\\u" + t.Substring(t.Length - 4)); + } + else + { + sb.Append(c); + } + break; + } + } + if(AddOuter) + sb.Append("\""); + return sb.ToString(); + } + + public LSL_String llJsonSetValue(LSL_String json, LSL_List specifiers, LSL_String value) + { + bool noSpecifiers = specifiers.Length == 0; + LitJson.JsonData workData; + try + { + if(noSpecifiers) + specifiers.Add(new LSL_Integer(0)); + + if(!String.IsNullOrEmpty(json)) + workData = LitJson.JsonMapper.ToObject(json); + else + { + workData = new LitJson.JsonData(); + workData.SetJsonType(LitJson.JsonType.Array); + } + } + catch (Exception e) + { + string m = e.Message; // debug point + return ScriptBaseClass.JSON_INVALID; + } + try + { + LitJson.JsonData replace = JsonSetSpecific(workData, specifiers, 0, value); + if(replace != null) + workData = replace; + } + catch (Exception e) + { + string m = e.Message; // debug point + return ScriptBaseClass.JSON_INVALID; + } + + try + { + string r = LitJson.JsonMapper.ToJson(workData); + if(noSpecifiers) + r = r.Substring(1,r.Length -2); // strip leading and trailing brakets + return r; + } + catch (Exception e) + { + string m = e.Message; // debug point + } + return ScriptBaseClass.JSON_INVALID; + } + + private LitJson.JsonData JsonSetSpecific(LitJson.JsonData elem, LSL_List specifiers, int level, LSL_String val) + { + object spec = specifiers.Data[level]; + if(spec is LSL_String) + spec = ((LSL_String)spec).m_string; + else if (spec is LSL_Integer) + spec = ((LSL_Integer)spec).value; + + if(!(spec is string || spec is int)) + throw new IndexOutOfRangeException(); + + int speclen = specifiers.Data.Length - 1; + + bool hasvalue = false; + LitJson.JsonData value = null; + + LitJson.JsonType elemType = elem.GetJsonType(); + if (elemType == LitJson.JsonType.Array) + { + if (spec is int) + { + int v = (int)spec; + int c = elem.Count; + if(v < 0 || (v != 0 && v > c)) + throw new IndexOutOfRangeException(); + if(v == c) + elem.Add(JsonBuildRestOfSpec(specifiers, level + 1, val)); + else + { + hasvalue = true; + value = elem[v]; + } + } + else if (spec is string) + { + if((string)spec == ScriptBaseClass.JSON_APPEND) + elem.Add(JsonBuildRestOfSpec(specifiers, level + 1, val)); + else if(elem.Count < 2) + { + // our initial guess of array was wrong + LitJson.JsonData newdata = new LitJson.JsonData(); + newdata.SetJsonType(LitJson.JsonType.Object); + IOrderedDictionary no = newdata as IOrderedDictionary; + no.Add((string)spec,JsonBuildRestOfSpec(specifiers, level + 1, val)); + return newdata; + } + } + } + else if (elemType == LitJson.JsonType.Object) + { + if (spec is string) + { + IOrderedDictionary e = elem as IOrderedDictionary; + string key = (string)spec; + if(e.Contains(key)) + { + hasvalue = true; + value = (LitJson.JsonData)e[key]; + } + else + e.Add(key, JsonBuildRestOfSpec(specifiers, level + 1, val)); + } + else if(spec is int && (int)spec == 0) + { + //we are replacing a object by a array + LitJson.JsonData newData = new LitJson.JsonData(); + newData.SetJsonType(LitJson.JsonType.Array); + newData.Add(JsonBuildRestOfSpec(specifiers, level + 1, val)); + return newData; + } + } + else + { + LitJson.JsonData newData = JsonBuildRestOfSpec(specifiers, level, val); + return newData; + } + + if (hasvalue) + { + if (level < speclen) + { + LitJson.JsonData replace = JsonSetSpecific(value, specifiers, level + 1, val); + if(replace != null) + { + if(elemType == LitJson.JsonType.Array) + { + if(spec is int) + elem[(int)spec] = replace; + else if( spec is string) + { + LitJson.JsonData newdata = new LitJson.JsonData(); + newdata.SetJsonType(LitJson.JsonType.Object); + IOrderedDictionary no = newdata as IOrderedDictionary; + no.Add((string)spec, replace); + return newdata; + } + } + else if(elemType == LitJson.JsonType.Object) + { + if(spec is string) + elem[(string)spec] = replace; + else if(spec is int && (int)spec == 0) + { + LitJson.JsonData newdata = new LitJson.JsonData(); + newdata.SetJsonType(LitJson.JsonType.Array); + newdata.Add(replace); + return newdata; + } + } + } + return null; + } + else if(speclen == level) + { + if(val == ScriptBaseClass.JSON_DELETE) + { + if(elemType == LitJson.JsonType.Array) + { + if(spec is int) + { + IList el = elem as IList; + el.RemoveAt((int)spec); + } + } + else if(elemType == LitJson.JsonType.Object) + { + if(spec is string) + { + IOrderedDictionary eo = elem as IOrderedDictionary; + eo.Remove((string) spec); + } + } + return null; + } + + LitJson.JsonData newval = null; + float num; + if(val == null || val == ScriptBaseClass.JSON_NULL || val == "null") + newval = null; + else if(val == ScriptBaseClass.JSON_TRUE || val == "true") + newval = new LitJson.JsonData(true); + else if(val == ScriptBaseClass.JSON_FALSE || val == "false") + newval = new LitJson.JsonData(false); + else if(float.TryParse(val, out num)) + { + // assuming we are at en.us already + if(num - (int)num == 0.0f && !val.Contains(".")) + newval = new LitJson.JsonData((int)num); + else + { + num = (float)Math.Round(num,6); + newval = new LitJson.JsonData((double)num); + } + } + else + { + string str = val.m_string; + newval = new LitJson.JsonData(str); + } + + if(elemType == LitJson.JsonType.Array) + { + if(spec is int) + elem[(int)spec] = newval; + else if( spec is string) + { + LitJson.JsonData newdata = new LitJson.JsonData(); + newdata.SetJsonType(LitJson.JsonType.Object); + IOrderedDictionary no = newdata as IOrderedDictionary; + no.Add((string)spec,newval); + return newdata; + } + } + else if(elemType == LitJson.JsonType.Object) + { + if(spec is string) + elem[(string)spec] = newval; + else if(spec is int && (int)spec == 0) + { + LitJson.JsonData newdata = new LitJson.JsonData(); + newdata.SetJsonType(LitJson.JsonType.Array); + newdata.Add(newval); + return newdata; + } + } + } + } + if(val == ScriptBaseClass.JSON_DELETE) + throw new IndexOutOfRangeException(); + return null; + } + + private LitJson.JsonData JsonBuildRestOfSpec(LSL_List specifiers, int level, LSL_String val) + { + object spec = level >= specifiers.Data.Length ? null : specifiers.Data[level]; + // 20131224 not used object specNext = i+1 >= specifiers.Data.Length ? null : specifiers.Data[i+1]; + + float num; + if (spec == null) + { + if(val == null || val == ScriptBaseClass.JSON_NULL || val == "null") + return null; + if(val == ScriptBaseClass.JSON_DELETE) + throw new IndexOutOfRangeException(); + if(val == ScriptBaseClass.JSON_TRUE || val == "true") + return new LitJson.JsonData(true); + if(val == ScriptBaseClass.JSON_FALSE || val == "false") + return new LitJson.JsonData(false); + if(val == null || val == ScriptBaseClass.JSON_NULL || val == "null") + return null; + if(float.TryParse(val, out num)) + { + // assuming we are at en.us already + if(num - (int)num == 0.0f && !val.Contains(".")) + return new LitJson.JsonData((int)num); + else + { + num = (float)Math.Round(num,6); + return new LitJson.JsonData(num); + } + } + else + { + string str = val.m_string; + return new LitJson.JsonData(str); + } + throw new IndexOutOfRangeException(); + } + + if(spec is LSL_String) + spec = ((LSL_String)spec).m_string; + else if (spec is LSL_Integer) + spec = ((LSL_Integer)spec).value; + + if (spec is int || + (spec is string && ((string)spec) == ScriptBaseClass.JSON_APPEND) ) + { + if(spec is int && (int)spec != 0) + throw new IndexOutOfRangeException(); + LitJson.JsonData newdata = new LitJson.JsonData(); + newdata.SetJsonType(LitJson.JsonType.Array); + newdata.Add(JsonBuildRestOfSpec(specifiers, level + 1, val)); + return newdata; + } + else if (spec is string) + { + LitJson.JsonData newdata = new LitJson.JsonData(); + newdata.SetJsonType(LitJson.JsonType.Object); + IOrderedDictionary no = newdata as IOrderedDictionary; + no.Add((string)spec,JsonBuildRestOfSpec(specifiers, level + 1, val)); + return newdata; + } + throw new IndexOutOfRangeException(); + } + + private bool JsonFind(LitJson.JsonData elem, LSL_List specifiers, int level, out LitJson.JsonData value) + { + value = null; + if(elem == null) + return false; + + object spec; + spec = specifiers.Data[level]; + + bool haveVal = false; + LitJson.JsonData next = null; + + if (elem.GetJsonType() == LitJson.JsonType.Array) + { + if (spec is LSL_Integer) + { + int indx = (LSL_Integer)spec; + if(indx >= 0 && indx < elem.Count) + { + haveVal = true; + next = (LitJson.JsonData)elem[indx]; + } + } + } + else if (elem.GetJsonType() == LitJson.JsonType.Object) + { + if (spec is LSL_String) + { + IOrderedDictionary e = elem as IOrderedDictionary; + string key = (LSL_String)spec; + if(e.Contains(key)) + { + haveVal = true; + next = (LitJson.JsonData)e[key]; + } + } + } + + if (haveVal) + { + if(level == specifiers.Data.Length - 1) + { + value = next; + return true; + } + + level++; + if(next == null) + return false; + + LitJson.JsonType nextType = next.GetJsonType(); + if(nextType != LitJson.JsonType.Object && nextType != LitJson.JsonType.Array) + return false; + + return JsonFind(next, specifiers, level, out value); + } + return false; + } + + public LSL_String llJsonGetValue(LSL_String json, LSL_List specifiers) + { + if(String.IsNullOrWhiteSpace(json)) + return ScriptBaseClass.JSON_INVALID; + + if(specifiers.Length > 0 && (json == "{}" || json == "[]")) + return ScriptBaseClass.JSON_INVALID; + + char first = ((string)json)[0]; + if((first != '[' && first !='{')) + { + if(specifiers.Length > 0) + return ScriptBaseClass.JSON_INVALID; + json = "[" + json + "]"; // could handle single element case.. but easier like this + specifiers.Add((LSL_Integer)0); + } + + LitJson.JsonData jsonData; + try + { + jsonData = LitJson.JsonMapper.ToObject(json); + } + catch (Exception e) + { + string m = e.Message; // debug point + return ScriptBaseClass.JSON_INVALID; + } + + LitJson.JsonData elem = null; + if(specifiers.Length == 0) + elem = jsonData; + else + { + if(!JsonFind(jsonData, specifiers, 0, out elem)) + return ScriptBaseClass.JSON_INVALID; + } + return JsonElementToString(elem); + } + + private LSL_String JsonElementToString(LitJson.JsonData elem) + { + if(elem == null) + return ScriptBaseClass.JSON_NULL; + + LitJson.JsonType elemType = elem.GetJsonType(); + switch(elemType) + { + case LitJson.JsonType.Array: + return new LSL_String(LitJson.JsonMapper.ToJson(elem)); + case LitJson.JsonType.Boolean: + return new LSL_String((bool)elem ? ScriptBaseClass.JSON_TRUE : ScriptBaseClass.JSON_FALSE); + case LitJson.JsonType.Double: + double d= (double)elem; + string sd = String.Format(Culture.FormatProvider, "{0:0.0#####}",d); + return new LSL_String(sd); + case LitJson.JsonType.Int: + int i = (int)elem; + return new LSL_String(i.ToString()); + case LitJson.JsonType.Long: + long l = (long)elem; + return new LSL_String(l.ToString()); + case LitJson.JsonType.Object: + return new LSL_String(LitJson.JsonMapper.ToJson(elem)); + case LitJson.JsonType.String: + string s = (string)elem; + return new LSL_String(s); + case LitJson.JsonType.None: + return ScriptBaseClass.JSON_NULL; + default: + return ScriptBaseClass.JSON_INVALID; + } + } + + public LSL_String llJsonValueType(LSL_String json, LSL_List specifiers) + { + if(String.IsNullOrWhiteSpace(json)) + return ScriptBaseClass.JSON_INVALID; + + if(specifiers.Length > 0 && (json == "{}" || json == "[]")) + return ScriptBaseClass.JSON_INVALID; + + char first = ((string)json)[0]; + if((first != '[' && first !='{')) + { + if(specifiers.Length > 0) + return ScriptBaseClass.JSON_INVALID; + json = "[" + json + "]"; // could handle single element case.. but easier like this + specifiers.Add((LSL_Integer)0); + } + + LitJson.JsonData jsonData; + try + { + jsonData = LitJson.JsonMapper.ToObject(json); + } + catch (Exception e) + { + string m = e.Message; // debug point + return ScriptBaseClass.JSON_INVALID; + } + + LitJson.JsonData elem = null; + if(specifiers.Length == 0) + elem = jsonData; + else + { + if(!JsonFind(jsonData, specifiers, 0, out elem)) + return ScriptBaseClass.JSON_INVALID; + } + + if(elem == null) + return ScriptBaseClass.JSON_NULL; + + LitJson.JsonType elemType = elem.GetJsonType(); + switch(elemType) + { + case LitJson.JsonType.Array: + return ScriptBaseClass.JSON_ARRAY; + case LitJson.JsonType.Boolean: + return (bool)elem ? ScriptBaseClass.JSON_TRUE : ScriptBaseClass.JSON_FALSE; + case LitJson.JsonType.Double: + case LitJson.JsonType.Int: + case LitJson.JsonType.Long: + return ScriptBaseClass.JSON_NUMBER; + case LitJson.JsonType.Object: + return ScriptBaseClass.JSON_OBJECT; + case LitJson.JsonType.String: + string s = (string)elem; + if(s == ScriptBaseClass.JSON_NULL) + return ScriptBaseClass.JSON_NULL; + if(s == ScriptBaseClass.JSON_TRUE) + return ScriptBaseClass.JSON_TRUE; + if(s == ScriptBaseClass.JSON_FALSE) + return ScriptBaseClass.JSON_FALSE; + return ScriptBaseClass.JSON_STRING; + case LitJson.JsonType.None: + return ScriptBaseClass.JSON_NULL; + default: + return ScriptBaseClass.JSON_INVALID; + } + } } public class NotecardCache diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index e5e43f8..238fefb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs @@ -295,7 +295,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx++; try { - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); } catch (InvalidCastException) { @@ -319,7 +319,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx++; try { - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); } catch (InvalidCastException) { @@ -342,7 +342,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx++; try { - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); } catch (InvalidCastException) { @@ -532,7 +532,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx++; try { - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); } catch (InvalidCastException) { @@ -654,7 +654,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case (int)ScriptBaseClass.WL_SUN_MOON_COLOR: idx++; - iQ = rules.GetQuaternionItem(idx); + iQ = rules.GetVector4Item(idx); try { wl.sunMoonColor = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); @@ -721,7 +721,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { ScenePresence sp = World.GetScenePresence(m_host.OwnerID); - if (sp == null || sp.GodLevel < 200) + if (sp == null || !sp.IsViewerUIGod) { LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); return 0; @@ -768,7 +768,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { ScenePresence sp = World.GetScenePresence(m_host.OwnerID); - if (sp == null || sp.GodLevel < 200) + if (sp == null || !sp.IsViewerUIGod) { LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); return; @@ -799,7 +799,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { ScenePresence sp = World.GetScenePresence(m_host.OwnerID); - if (sp == null || sp.GodLevel < 200) + if (sp == null || !sp.IsViewerUIGod) { LSShoutError("lsSetWindlightSceneTargeted can only be used by estate managers or owners."); return 0; @@ -831,6 +831,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } return success; - } + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 1458c95..692bec0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -107,14 +107,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Dumps an error message on the debug console. /// /// - internal void MODShoutError(string message) + internal void MODShoutError(string message) { if (message.Length > 1023) message = message.Substring(0, 1023); World.SimChat( Utils.StringToBytes(message), - ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, + ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false); IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); @@ -122,7 +122,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// + /// /// /// The name of the function to invoke /// List of parameters @@ -130,13 +130,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void modInvokeN(string fname, params object[] parms) { // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type returntype = m_comms.LookupReturnType(fname); - if (returntype != typeof(string)) + if (returntype != typeof(void)) MODError(String.Format("return type mismatch for {0}",fname)); modInvoke(fname,parms); @@ -145,9 +145,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String modInvokeS(string fname, params object[] parms) { // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type returntype = m_comms.LookupReturnType(fname); @@ -161,9 +161,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer modInvokeI(string fname, params object[] parms) { // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type returntype = m_comms.LookupReturnType(fname); @@ -173,13 +173,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api int result = (int)modInvoke(fname,parms); return new LSL_Integer(result); } - + public LSL_Float modInvokeF(string fname, params object[] parms) { // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type returntype = m_comms.LookupReturnType(fname); @@ -193,9 +193,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Key modInvokeK(string fname, params object[] parms) { // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type returntype = m_comms.LookupReturnType(fname); @@ -209,9 +209,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector modInvokeV(string fname, params object[] parms) { // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type returntype = m_comms.LookupReturnType(fname); @@ -225,9 +225,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Rotation modInvokeR(string fname, params object[] parms) { // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type returntype = m_comms.LookupReturnType(fname); @@ -241,9 +241,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List modInvokeL(string fname, params object[] parms) { // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type returntype = m_comms.LookupReturnType(fname); @@ -308,27 +308,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } // m_log.DebugFormat( -// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", -// fname, -// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), +// "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type", +// fname, +// string.Join(",", Array.ConvertAll(parms, o => o.ToString())), // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType); Type[] signature = m_comms.LookupTypeSignature(fname); if (signature.Length != parms.Length) MODError(String.Format("wrong number of parameters to function {0}",fname)); - + object[] convertedParms = new object[parms.Length]; for (int i = 0; i < parms.Length; i++) convertedParms[i] = ConvertFromLSL(parms[i], signature[i], fname); // now call the function, the contract with the function is that it will always return // non-null but don't trust it completely - try + try { object result = m_comms.InvokeOperation(m_host.UUID, m_item.ItemID, fname, convertedParms); if (result != null) return result; + Type returntype = m_comms.LookupReturnType(fname); + if (returntype == typeof(void)) + return null; + MODError(String.Format("Invocation of {0} failed; null return value",fname)); } catch (Exception e) @@ -338,7 +342,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return null; } - + /// /// Send a command to functions registered on an event /// @@ -361,8 +365,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// protected object ConvertFromLSL(object lslparm, Type type, string fname) { + + if(lslparm.GetType() == type) + return lslparm; + // ---------- String ---------- - if (lslparm is LSL_String) + else if (lslparm is LSL_String) { if (type == typeof(string)) return (string)(LSL_String)lslparm; @@ -421,7 +429,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api for (int i = 0; i < plist.Length; i++) { if (plist[i] is LSL_String) - result[i] = (string)(LSL_String)plist[i]; + result[i] = (string)(LSL_String)plist[i]; else if (plist[i] is LSL_Integer) result[i] = (int)(LSL_Integer)plist[i]; // The int check exists because of the many plain old int script constants in ScriptBase which @@ -443,7 +451,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return result; } } - + MODError(String.Format("{0}: parameter type mismatch; expecting {1}, type(parm)={2}", fname, type.Name, lslparm.GetType())); return null; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 83aa245..6e28fe0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -45,6 +45,7 @@ using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Scripting; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; @@ -138,8 +139,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal TaskInventoryItem m_item; internal bool m_OSFunctionsEnabled = false; internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow; + internal float m_ScriptDelayFactor = 1.0f; + internal float m_ScriptDistanceFactor = 1.0f; + internal bool m_debuggerSafe = false; internal Dictionary m_FunctionPerms = new Dictionary(); - protected IUrlModule m_UrlModule = null; public void Initialize( @@ -148,6 +151,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine = scriptEngine; m_host = host; m_item = item; + m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); @@ -157,6 +161,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // m_log.Warn("[OSSL] OSSL FUNCTIONS ENABLED"); } + m_ScriptDelayFactor = + m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); + m_ScriptDistanceFactor = + m_ScriptEngine.Config.GetFloat("ScriptDistanceLimitFactor", 1.0f); + string risk = m_ScriptEngine.Config.GetString("OSFunctionThreatLevel", "VeryLow"); switch (risk) { @@ -187,7 +196,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api default: break; } - } + } public override Object InitializeLifetimeService() { @@ -209,7 +218,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal void OSSLError(string msg) { - OSSLShoutError("OSSL Runtime Error: " + msg); + if (m_debuggerSafe) + { + OSSLShoutError(msg); + } + else + { + throw new ScriptException("OSSL Runtime Error: " + msg); + } } /// @@ -244,22 +260,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); } - // Returns of the function is allowed. Throws a script exception if not allowed. - public bool CheckThreatLevel(ThreatLevel level, string function) + // Returns if OSSL is enabled. Throws a script exception if OSSL is not allowed.. + // for safe funtions always active + public void CheckThreatLevel() { + m_host.AddScriptLPS(1); if (!m_OSFunctionsEnabled) - { - OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); - return false; - } + OSSLError(String.Format("{0} permission denied. All OS functions are disabled.")); // throws + } + + // Returns if the function is allowed. Throws a script exception if not allowed. + public void CheckThreatLevel(ThreatLevel level, string function) + { + m_host.AddScriptLPS(1); + if (!m_OSFunctionsEnabled) + OSSLError(String.Format("{0} permission denied. All OS functions are disabled.", function)); // throws string reasonWhyNot = CheckThreatLevelTest(level, function); if (!String.IsNullOrEmpty(reasonWhyNot)) { OSSLError(reasonWhyNot); - return false; } - return true; } // Check to see if function is allowed. Returns an empty string if function permitted @@ -299,7 +320,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (string id in ids) { string current = id.Trim(); - if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER") + if (current.ToUpper() == "PARCEL_GROUP_MEMBER" || current.ToUpper() == "PARCEL_OWNER" || current.ToUpper() == "ESTATE_MANAGER" || current.ToUpper() == "ESTATE_OWNER" || current.ToUpper() == "ACTIVE_GOD" || current.ToUpper() == "GRID_GOD" || current.ToUpper() == "GOD") { if (!perms.AllowedOwnerClasses.Contains(current)) perms.AllowedOwnerClasses.Add(current.ToUpper()); @@ -404,6 +425,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + + //Only grid gods may use the function + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GRID_GOD")) + { + if (World.Permissions.IsGridGod(ownerID)) + { + return String.Empty; + } + } + + //Any god may use the function + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("GOD")) + { + if (World.Permissions.IsAdministrator(ownerID)) + { + return String.Empty; + } + } + + //Only active gods may use the function + if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("ACTIVE_GOD")) + { + ScenePresence sp = World.GetScenePresence(ownerID); + if (sp != null && !sp.IsDeleted && sp.IsGod) + { + return String.Empty; + } + } + if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) return( String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", @@ -425,16 +475,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api OSSLShoutError(string.Format("Use of function {0} is deprecated. Use {1} instead.", function, replacement)); } + protected void ScriptSleep(int delay) + { + delay = (int)((float)delay * m_ScriptDelayFactor); + if (delay == 0) + return; + System.Threading.Thread.Sleep(delay); + } + public LSL_Integer osSetTerrainHeight(int x, int y, double val) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetTerrainHeight")) return 0; + CheckThreatLevel(ThreatLevel.High, "osSetTerrainHeight"); return SetTerrainHeight(x, y, val); } public LSL_Integer osTerrainSetHeight(int x, int y, double val) { - if (!CheckThreatLevel(ThreatLevel.High, "osTerrainSetHeight")) return 0; + CheckThreatLevel(ThreatLevel.High, "osTerrainSetHeight"); OSSLDeprecated("osTerrainSetHeight", "osSetTerrainHeight"); return SetTerrainHeight(x, y, val); @@ -442,8 +500,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private LSL_Integer SetTerrainHeight(int x, int y, double val) { - m_host.AddScriptLPS(1); - if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0) OSSLError("osSetTerrainHeight: Coordinate out of bounds"); @@ -460,18 +516,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float osGetTerrainHeight(int x, int y) { + CheckThreatLevel(); return GetTerrainHeight(x, y); } public LSL_Float osTerrainGetHeight(int x, int y) { + CheckThreatLevel(); OSSLDeprecated("osTerrainGetHeight", "osGetTerrainHeight"); return GetTerrainHeight(x, y); } private LSL_Float GetTerrainHeight(int x, int y) { - m_host.AddScriptLPS(1); if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0) OSSLError("osGetTerrainHeight: Coordinate out of bounds"); @@ -480,8 +537,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osTerrainFlush() { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osTerrainFlush")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osTerrainFlush"); ITerrainModule terrainModule = World.RequestModuleInterface(); if (terrainModule != null) terrainModule.TaintTerrain(); @@ -495,31 +551,40 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // The underlying functionality is fixed, since the security // as such is sound // - if (!CheckThreatLevel(ThreatLevel.High, "osRegionRestart")) return 0; + CheckThreatLevel(ThreatLevel.High, "osRegionRestart"); IRestartModule restartModule = World.RequestModuleInterface(); - m_host.AddScriptLPS(1); if (World.Permissions.CanIssueEstateCommand(m_host.OwnerID, false) && (restartModule != null)) { if (seconds < 15) { - restartModule.AbortRestart("Restart aborted"); + restartModule.AbortRestart("Region restart has been aborted\n"); return 1; } - List times = new List(); - while (seconds > 0) + RegionRestart(seconds, String.Empty); + return 1; + } + else + { + return 0; + } + } + + public int osRegionRestart(double seconds, string msg) + { + CheckThreatLevel(ThreatLevel.High, "osRegionRestart"); + + IRestartModule restartModule = World.RequestModuleInterface(); + if (World.Permissions.CanIssueEstateCommand(m_host.OwnerID, false) && (restartModule != null)) + { + if (seconds < 15) { - times.Add((int)seconds); - if (seconds > 300) - seconds -= 120; - else if (seconds > 30) - seconds -= 30; - else - seconds -= 15; + restartModule.AbortRestart("Region restart has been aborted\n"); + return 1; } - restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); + RegionRestart(seconds, msg); return 1; } else @@ -528,15 +593,38 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + private void RegionRestart(double seconds, string msg) + { + IRestartModule restartModule = World.RequestModuleInterface(); + + List times = new List(); + while (seconds > 0) + { + times.Add((int)seconds); + if (seconds > 300) + seconds -= 120; + else if (seconds > 120) + seconds -= 60; + else if (seconds > 60) + seconds -= 30; + else + seconds -= 15; + } + + if (msg == String.Empty) + restartModule.ScheduleRestart(UUID.Zero, "Region: " + World.RegionInfo.RegionName + " is about to restart.\n\nIf you stay here you will be logged out.\n\n\nTime remaining: {0}.\n", times.ToArray(), true); + + else + restartModule.ScheduleRestart(UUID.Zero, msg + "\n\nTime remaining: {0}.\n", times.ToArray(), true); + } + public void osRegionNotice(string msg) { // This implementation provides absolutely no security // It's high griefing potential makes this classification // necessary // - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osRegionNotice")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osRegionNotice"); IDialogModule dm = World.RequestModuleInterface(); @@ -549,9 +637,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // This function has no security. It can be used to destroy // arbitrary builds the user would normally have no rights to // - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osSetRot")) return; + CheckThreatLevel(ThreatLevel.VeryHigh, "osSetRot"); - m_host.AddScriptLPS(1); if (World.Entities.ContainsKey(target)) { EntityBase entity; @@ -572,13 +659,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureURL(string dynamicID, string contentType, string url, string extraParams, int timer) { - m_host.AddScriptLPS(1); + // This may be upgraded depending on the griefing or DOS + // potential, or guarded with a delay + // + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureURL"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); UUID createdTexture = textureManager.AddDynamicTextureURL(World.RegionInfo.RegionID, m_host.UUID, contentType, url, - extraParams, timer); + extraParams); return createdTexture.ToString(); } else @@ -592,13 +683,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureURLBlend(string dynamicID, string contentType, string url, string extraParams, int timer, int alpha) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureURLBlend"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); UUID createdTexture = textureManager.AddDynamicTextureURL(World.RegionInfo.RegionID, m_host.UUID, contentType, url, - extraParams, timer, true, (byte) alpha); + extraParams, true, (byte) alpha); return createdTexture.ToString(); } else @@ -612,13 +704,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureURLBlendFace(string dynamicID, string contentType, string url, string extraParams, bool blend, int disp, int timer, int alpha, int face) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureURLBlendFace"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); UUID createdTexture = textureManager.AddDynamicTextureURL(World.RegionInfo.RegionID, m_host.UUID, contentType, url, - extraParams, timer, blend, disp, (byte) alpha, face); + extraParams, blend, disp, (byte) alpha, face); return createdTexture.ToString(); } else @@ -632,7 +725,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureData(string dynamicID, string contentType, string data, string extraParams, int timer) { - m_host.AddScriptLPS(1); + return osSetDynamicTextureDataFace(dynamicID, contentType, data, extraParams, timer, -1); + } + + public string osSetDynamicTextureDataFace(string dynamicID, string contentType, string data, string extraParams, + int timer, int face) + { + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureData"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); @@ -644,7 +744,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } UUID createdTexture = textureManager.AddDynamicTextureData(World.RegionInfo.RegionID, m_host.UUID, contentType, data, - extraParams, timer); + extraParams, false, 3, 255, face); + return createdTexture.ToString(); } } @@ -659,7 +760,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureDataBlend(string dynamicID, string contentType, string data, string extraParams, int timer, int alpha) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetDynamicTextureDataBlend"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); @@ -671,7 +773,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } UUID createdTexture = textureManager.AddDynamicTextureData(World.RegionInfo.RegionID, m_host.UUID, contentType, data, - extraParams, timer, true, (byte) alpha); + extraParams, true, (byte) alpha); return createdTexture.ToString(); } } @@ -686,7 +788,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetDynamicTextureDataBlendFace(string dynamicID, string contentType, string data, string extraParams, bool blend, int disp, int timer, int alpha, int face) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow , "osSetDynamicTextureDataBlendFace"); + if (dynamicID == String.Empty) { IDynamicTextureManager textureManager = World.RequestModuleInterface(); @@ -698,7 +801,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } UUID createdTexture = textureManager.AddDynamicTextureData(World.RegionInfo.RegionID, m_host.UUID, contentType, data, - extraParams, timer, blend, disp, (byte) alpha, face); + extraParams, blend, disp, (byte) alpha, face); return createdTexture.ToString(); } } @@ -712,9 +815,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public bool osConsoleCommand(string command) { - if (!CheckThreatLevel(ThreatLevel.Severe, "osConsoleCommand")) return false; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Severe, "osConsoleCommand"); // For safety, we add another permission check here, and don't rely only on the standard OSSL permissions if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID)) @@ -728,123 +829,183 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSetPrimFloatOnWater(int floatYN) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osSetPrimFloatOnWater")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetPrimFloatOnWater"); m_host.ParentGroup.RootPart.SetFloatOnWater(floatYN); } + private bool checkAllowAgentTPbyLandOwner(UUID agentId, Vector3 pos) + { + UUID hostOwner = m_host.OwnerID; + + if(hostOwner == agentId) + return true; + + if (m_item.PermsGranter == agentId) + { + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TELEPORT) != 0) + return true; + } + + ILandObject land = World.LandChannel.GetLandObject(pos); + if(land == null) + return true; + + LandData landdata = land.LandData; + if(landdata == null) + return true; + + if(landdata.OwnerID == hostOwner) + return true; + + EstateSettings es = World.RegionInfo.EstateSettings; + if(es != null && es.IsEstateManagerOrOwner(hostOwner)) + return true; + + if(!landdata.IsGroupOwned) + return false; + + UUID landGroup = landdata.GroupID; + if(landGroup == UUID.Zero) + return false; + + if(landGroup == m_host.GroupID) + return true; + + return false; + } + // Teleport functions public void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { // High because there is no security check. High griefer potential // - if (!CheckThreatLevel(ThreatLevel.High, "osTeleportAgent")) return; + CheckThreatLevel(ThreatLevel.Severe, "osTeleportAgent"); - TeleportAgent(agent, regionName, position, lookat, false); + TeleportAgent(agent, regionName, position, lookat); } private void TeleportAgent(string agent, string regionName, - LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions) + LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - m_host.AddScriptLPS(1); - UUID agentId = new UUID(); + if(String.IsNullOrEmpty(regionName)) + regionName = World.RegionInfo.RegionName; + + UUID agentId; if (UUID.TryParse(agent, out agentId)) { ScenePresence presence = World.GetScenePresence(agentId); - if (presence != null) + if (presence == null || presence.IsDeleted || presence.IsInTransit) + return; + + Vector3 pos = presence.AbsolutePosition; + if(!checkAllowAgentTPbyLandOwner(agentId, pos)) { - // For osTeleportAgent, agent must be over owners land to avoid abuse - // For osTeleportOwner, this restriction isn't necessary - - // commented out because its redundant and uneeded please remove eventually. - // if (relaxRestrictions || - // m_host.OwnerID - // == World.LandChannel.GetLandObject( - // presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) - // { - - // We will launch the teleport on a new thread so that when the script threads are terminated - // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. - Util.FireAndForget( - o => World.RequestTeleportLocation( - presence.ControllingClient, regionName, position, - lookat, (uint)TPFlags.ViaLocation), - null, "OSSL_Api.TeleportAgentByRegionCoords"); - // } + ScriptSleep(500); + return; + } + if(regionName == World.RegionInfo.RegionName) + { + // should be faster than going to threadpool + World.RequestTeleportLocation(presence.ControllingClient, regionName, position, + lookat, (uint)TPFlags.ViaLocation); + ScriptSleep(500); + } + else + { + // We will launch the teleport on a new thread so that when the script threads are terminated + // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. + Util.FireAndForget( + o => World.RequestTeleportLocation( + presence.ControllingClient, regionName, position, + lookat, (uint)TPFlags.ViaLocation), + null, "OSSL_Api.TeleportAgentByRegionCoords"); + ScriptSleep(5000); } } } - public void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) + public void osTeleportAgent(string agent, int regionGridX, int regionGridY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { // High because there is no security check. High griefer potential // - if (!CheckThreatLevel(ThreatLevel.High, "osTeleportAgent")) return; + CheckThreatLevel(ThreatLevel.Severe, "osTeleportAgent"); - TeleportAgent(agent, regionX, regionY, position, lookat, false); + TeleportAgent(agent, regionGridX, regionGridY, position, lookat); } - private void TeleportAgent(string agent, int regionX, int regionY, - LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions) + private void TeleportAgent(string agent, int regionGridX, int regionGridY, + LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - // ulong regionHandle = Util.UIntsToLong(((uint)regionX * (uint)Constants.RegionSize), ((uint)regionY * (uint)Constants.RegionSize)); - ulong regionHandle = Util.RegionLocToHandle((uint)regionX, (uint)regionY); + ulong regionHandle = Util.RegionGridLocToHandle((uint)regionGridX, (uint)regionGridY); - m_host.AddScriptLPS(1); - UUID agentId = new UUID(); + UUID agentId; if (UUID.TryParse(agent, out agentId)) { ScenePresence presence = World.GetScenePresence(agentId); - if (presence != null) - { - // For osTeleportAgent, agent must be over owners land to avoid abuse - // For osTeleportOwner, this restriction isn't necessary - - // commented out because its redundant and uneeded please remove eventually. - // if (relaxRestrictions || - // m_host.OwnerID - // == World.LandChannel.GetLandObject( - // presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) - // { - - // We will launch the teleport on a new thread so that when the script threads are terminated - // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. - Util.FireAndForget( - o => World.RequestTeleportLocation( - presence.ControllingClient, regionHandle, - position, lookat, (uint)TPFlags.ViaLocation), - null, "OSSL_Api.TeleportAgentByRegionName"); - // } + if (presence == null || presence.IsDeleted || presence.IsInTransit) + return; + Vector3 pos = presence.AbsolutePosition; + if(!checkAllowAgentTPbyLandOwner(agentId, pos)) + { + ScriptSleep(500); + return; } + + Util.FireAndForget( + o => World.RequestTeleportLocation( + presence.ControllingClient, regionHandle, + position, lookat, (uint)TPFlags.ViaLocation), + null, "OSSL_Api.TeleportAgentByRegionName"); + + ScriptSleep(5000); } } public void osTeleportAgent(string agent, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - // High because there is no security check. High griefer potential - // - if (!CheckThreatLevel(ThreatLevel.High, "osTeleportAgent")) return; + UUID agentId; + if (UUID.TryParse(agent, out agentId)) + { + ScenePresence presence = World.GetScenePresence(agentId); + if (presence == null || presence.IsDeleted || presence.IsInTransit) + return; - osTeleportAgent(agent, World.RegionInfo.RegionName, position, lookat); + Vector3 pos = presence.AbsolutePosition; + if(!checkAllowAgentTPbyLandOwner(agentId, pos)) + { + ScriptSleep(500); + return; + } + + World.RequestTeleportLocation(presence.ControllingClient, World.RegionInfo.RegionName, position, + lookat, (uint)TPFlags.ViaLocation); + ScriptSleep(500); + } } public void osTeleportOwner(string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - TeleportAgent(m_host.OwnerID.ToString(), regionName, position, lookat, true); + // Threat level None because this is what can already be done with the World Map in the viewer + CheckThreatLevel(ThreatLevel.None, "osTeleportOwner"); + + TeleportAgent(m_host.OwnerID.ToString(), regionName, position, lookat); } - public void osTeleportOwner(LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) + public void osTeleportOwner(int regionGridX, int regionGridY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - osTeleportOwner(World.RegionInfo.RegionName, position, lookat); + CheckThreatLevel(ThreatLevel.None, "osTeleportOwner"); + + TeleportAgent(m_host.OwnerID.ToString(), regionGridX, regionGridY, position, lookat); } - public void osTeleportOwner(int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) + public void osTeleportOwner(LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { - TeleportAgent(m_host.OwnerID.ToString(), regionX, regionY, position, lookat, true); + CheckThreatLevel(ThreatLevel.None, "osTeleportOwner"); + + osTeleportAgent(m_host.OwnerID.ToString(), position, lookat); } /// @@ -856,9 +1017,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osForceOtherSit(string avatar) { - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit"); ForceSit(avatar, m_host.UUID); } @@ -871,9 +1030,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osForceOtherSit(string avatar, string target) { - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceOtherSit"); UUID targetID = new UUID(target); @@ -882,7 +1039,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void ForceSit(string avatar, UUID targetID) { - UUID agentID; + UUID agentID; if (!UUID.TryParse(avatar, out agentID)) return; @@ -900,21 +1057,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.SitTargetPosition); } - // Functions that get information from the agent itself. - // - // osGetAgentIP - this is used to determine the IP address of - //the client. This is needed to help configure other in world - //resources based on the IP address of the clients connected. - //I think High is a good risk level for this, as it is an - //information leak. - // Severe is even better coz privacy is important. + // Get a list of all the avatars/agents in the region + public LSL_List osGetAgents() + { + // threat level is None as we could get this information with an + // in-world script as well, just not as efficient + CheckThreatLevel(ThreatLevel.None, "osGetAgents"); + + LSL_List result = new LSL_List(); + World.ForEachRootScenePresence(delegate(ScenePresence sp) + { + result.Add(new LSL_String(sp.Name)); + }); + return result; + } + public string osGetAgentIP(string agent) { - if (!CheckThreatLevel(ThreatLevel.Severe, "osGetAgentIP")) return ""; + CheckThreatLevel(ThreatLevel.Severe, "osGetAgentIP"); + if(!(World.Permissions.IsGod(m_host.OwnerID))) // user god always needed + return ""; UUID avatarID = (UUID)agent; - m_host.AddScriptLPS(1); if (World.Entities.ContainsKey((UUID)agent) && World.Entities[avatarID] is ScenePresence) { ScenePresence target = (ScenePresence)World.Entities[avatarID]; @@ -925,61 +1090,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ""; } - // Get a list of all the avatars/agents in the region - public LSL_List osGetAgents() - { - m_host.AddScriptLPS(1); - - LSL_List result = new LSL_List(); - World.ForEachRootScenePresence(delegate(ScenePresence sp) - { - result.Add(new LSL_String(sp.Name)); - }); - return result; - } - // Adam's super super custom animation functions public void osAvatarPlayAnimation(string avatar, string animation) { - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarPlayAnimation")) return; + CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarPlayAnimation"); AvatarPlayAnimation(avatar, animation); } private void AvatarPlayAnimation(string avatar, string animation) { - UUID avatarID = (UUID)avatar; + UUID avatarID; + if(!UUID.TryParse(avatar, out avatarID)) + return; - m_host.AddScriptLPS(1); - if (World.Entities.ContainsKey((UUID)avatar) && World.Entities[avatarID] is ScenePresence) + ScenePresence target = World.GetScenePresence(avatarID); + if (target == null) + return; + + UUID animID = UUID.Zero; + m_host.TaskInventory.LockItemsForRead(true); + foreach (KeyValuePair inv in m_host.TaskInventory) { - ScenePresence target = (ScenePresence)World.Entities[avatarID]; - if (target != null) + if (inv.Value.Type == (int)AssetType.Animation) { - UUID animID=UUID.Zero; - lock (m_host.TaskInventory) - { - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == animation) - { - if (inv.Value.Type == (int)AssetType.Animation) - animID = inv.Value.AssetID; - continue; - } - } - } - if (animID == UUID.Zero) - target.Animator.AddAnimation(animation, m_host.UUID); - else - target.Animator.AddAnimation(animID, m_host.UUID); + if (inv.Value.Name == animation) + { + animID = inv.Value.AssetID; + break; + } } } + m_host.TaskInventory.LockItemsForRead(false); + + if (animID == UUID.Zero) + target.Animator.AddAnimation(animation, m_host.UUID); + else + target.Animator.AddAnimation(animID, m_host.UUID); } public void osAvatarStopAnimation(string avatar, string animation) { - if (!CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarStopAnimation")) return; + CheckThreatLevel(ThreatLevel.VeryHigh, "osAvatarStopAnimation"); AvatarStopAnimation(avatar, animation); } @@ -988,8 +1140,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID avatarID = (UUID)avatar; - m_host.AddScriptLPS(1); - // FIXME: What we really want to do here is factor out the similar code in llStopAnimation() to a common // method (though see that doesn't do the is animation check, which is probably a bug) and have both // these functions call that common code. However, this does mean navigating the brain-dead requirement @@ -1010,6 +1160,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api animID = UUID.Zero; } + if (animID == UUID.Zero) target.Animator.RemoveAnimation(animation); else @@ -1019,58 +1170,106 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } //Texture draw functions + + public string osDrawResetTransform(string drawList) + { + CheckThreatLevel(); + + drawList += "ResetTransf;"; + return drawList; + } + + public string osDrawRotationTransform(string drawList, LSL_Float x) + { + CheckThreatLevel(); + + drawList += "RotTransf " + x + ";"; + return drawList; + } + + public string osDrawScaleTransform(string drawList, LSL_Float x, LSL_Float y) + { + CheckThreatLevel(); + + drawList += "ScaleTransf " + x + "," + y + ";"; + return drawList; + } + + public string osDrawTranslationTransform(string drawList, LSL_Float x, LSL_Float y) + { + CheckThreatLevel(); + + drawList += "TransTransf " + x + "," + y + ";"; + return drawList; + } + public string osMovePen(string drawList, int x, int y) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "MoveTo " + x + "," + y + ";"; return drawList; } public string osDrawLine(string drawList, int startX, int startY, int endX, int endY) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "MoveTo "+ startX+","+ startY +"; LineTo "+endX +","+endY +"; "; return drawList; } public string osDrawLine(string drawList, int endX, int endY) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "LineTo " + endX + "," + endY + "; "; return drawList; } public string osDrawText(string drawList, string text) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osDrawText"); + drawList += "Text " + text + "; "; return drawList; } public string osDrawEllipse(string drawList, int width, int height) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "Ellipse " + width + "," + height + "; "; return drawList; } + public string osDrawFilledEllipse(string drawList, int width, int height) + { + CheckThreatLevel(); + + drawList += "FillEllipse " + width + "," + height + "; "; + return drawList; + } + public string osDrawRectangle(string drawList, int width, int height) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "Rectangle " + width + "," + height + "; "; return drawList; } public string osDrawFilledRectangle(string drawList, int width, int height) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "FillRectangle " + width + "," + height + "; "; return drawList; } public string osDrawFilledPolygon(string drawList, LSL_List x, LSL_List y) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); if (x.Length != y.Length || x.Length < 3) { @@ -1087,7 +1286,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osDrawPolygon(string drawList, LSL_List x, LSL_List y) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); if (x.Length != y.Length || x.Length < 3) { @@ -1104,28 +1303,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osSetFontSize(string drawList, int fontSize) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "FontSize "+ fontSize +"; "; return drawList; } public string osSetFontName(string drawList, string fontName) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "FontName "+ fontName +"; "; return drawList; } public string osSetPenSize(string drawList, int penSize) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "PenSize " + penSize + "; "; return drawList; } public string osSetPenColor(string drawList, string color) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "PenColor " + color + "; "; return drawList; } @@ -1133,30 +1336,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Deprecated public string osSetPenColour(string drawList, string colour) { + CheckThreatLevel(); OSSLDeprecated("osSetPenColour", "osSetPenColor"); - m_host.AddScriptLPS(1); drawList += "PenColour " + colour + "; "; return drawList; } public string osSetPenCap(string drawList, string direction, string type) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList += "PenCap " + direction + "," + type + "; "; return drawList; } public string osDrawImage(string drawList, int width, int height, string imageUrl) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + drawList +="Image " +width + "," + height+ ","+ imageUrl +"; " ; return drawList; } public LSL_Vector osGetDrawStringSize(string contentType, string text, string fontName, int fontSize) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); LSL_Vector vec = new LSL_Vector(0,0,0); IDynamicTextureManager textureManager = World.RequestModuleInterface(); @@ -1178,17 +1383,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // It was probably added as a crutch or debugging aid, and // should be removed // - if (!CheckThreatLevel(ThreatLevel.High, "osSetStateEvents")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetStateEvents"); m_host.SetScriptEvents(m_item.ItemID, events); } public void osSetRegionWaterHeight(double height) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetRegionWaterHeight")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetRegionWaterHeight"); World.EventManager.TriggerRequestChangeWaterHeight((float)height); } @@ -1201,9 +1403,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The "Sun Hour" that is desired, 0...24, with 0 just after SunRise public void osSetRegionSunSettings(bool useEstateSun, bool sunFixed, double sunHour) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetRegionSunSettings")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetRegionSunSettings"); while (sunHour > 24.0) sunHour -= 24.0; @@ -1226,9 +1426,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The "Sun Hour" that is desired, 0...24, with 0 just after SunRise public void osSetEstateSunSettings(bool sunFixed, double sunHour) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetEstateSunSettings")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetEstateSunSettings"); while (sunHour > 24.0) sunHour -= 24.0; @@ -1250,7 +1448,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public double osGetCurrentSunHour() { - m_host.AddScriptLPS(1); + CheckThreatLevel(); // Must adjust for the fact that Region Sun Settings are still LL offset double sunHour = World.RegionInfo.RegionSettings.SunPosition - 6; @@ -1267,19 +1465,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public double osSunGetParam(string param) { + CheckThreatLevel(ThreatLevel.None, "osSunGetParam"); OSSLDeprecated("osSunGetParam", "osGetSunParam"); return GetSunParam(param); } public double osGetSunParam(string param) { + CheckThreatLevel(); return GetSunParam(param); } private double GetSunParam(string param) { - m_host.AddScriptLPS(1); - double value = 0.0; ISunModule module = World.RequestModuleInterface(); @@ -1293,21 +1491,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSunSetParam(string param, double value) { -//// if (!CheckThreatLevel(ThreatLevel.None, "osSunSetParam")) return; + CheckThreatLevel(ThreatLevel.None, "osSunSetParam"); OSSLDeprecated("osSunSetParam", "osSetSunParam"); SetSunParam(param, value); } public void osSetSunParam(string param, double value) { -//// if (!CheckThreatLevel(ThreatLevel.None, "osSetSunParam")) return; + CheckThreatLevel(ThreatLevel.None, "osSetSunParam"); SetSunParam(param, value); } private void SetSunParam(string param, double value) { - m_host.AddScriptLPS(1); - ISunModule module = World.RequestModuleInterface(); if (module != null) { @@ -1317,7 +1513,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osWindActiveModelPluginName() { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osWindActiveModelPluginName"); IWindModule module = World.RequestModuleInterface(); if (module != null) @@ -1330,8 +1526,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSetWindParam(string plugin, string param, LSL_Float value) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osSetWindParam")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetWindParam"); IWindModule module = World.RequestModuleInterface(); if (module != null) @@ -1346,7 +1541,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float osGetWindParam(string plugin, string param) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osGetWindParam"); IWindModule module = World.RequestModuleInterface(); if (module != null) @@ -1360,8 +1555,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Routines for creating and managing parcels programmatically public void osParcelJoin(LSL_Vector pos1, LSL_Vector pos2) { - if (!CheckThreatLevel(ThreatLevel.High, "osParcelJoin")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osParcelJoin"); int startx = (int)(pos1.x < pos2.x ? pos1.x : pos2.x); int starty = (int)(pos1.y < pos2.y ? pos1.y : pos2.y); @@ -1373,8 +1567,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osParcelSubdivide(LSL_Vector pos1, LSL_Vector pos2) { - if (!CheckThreatLevel(ThreatLevel.High, "osParcelSubdivide")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osParcelSubdivide"); int startx = (int)(pos1.x < pos2.x ? pos1.x : pos2.x); int starty = (int)(pos1.y < pos2.y ? pos1.y : pos2.y); @@ -1387,7 +1580,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osParcelSetDetails(LSL_Vector pos, LSL_List rules) { const string functionName = "osParcelSetDetails"; - if (!CheckThreatLevel(ThreatLevel.High, functionName)) return; + CheckThreatLevel(ThreatLevel.High, functionName); OSSLDeprecated(functionName, "osSetParcelDetails"); SetParcelDetails(pos, rules, functionName); } @@ -1395,14 +1588,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSetParcelDetails(LSL_Vector pos, LSL_List rules) { const string functionName = "osSetParcelDetails"; - if (!CheckThreatLevel(ThreatLevel.High, functionName)) return; + CheckThreatLevel(ThreatLevel.High, functionName); SetParcelDetails(pos, rules, functionName); } private void SetParcelDetails(LSL_Vector pos, LSL_List rules, string functionName) { - m_host.AddScriptLPS(1); - // Get a reference to the land data and make sure the owner of the script // can modify it @@ -1413,15 +1604,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, startLandObject, GroupPowers.LandOptions)) + if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, startLandObject, GroupPowers.LandOptions, false)) { - OSSLShoutError("You do not have permission to modify the parcel"); + OSSLShoutError("script owner does not have permission to modify the parcel"); return; } // Create a new land data object we can modify LandData newLand = startLandObject.LandData.Copy(); UUID uuid; + EstateSettings es = World.RegionInfo.EstateSettings; + + bool changed = false; + bool changedSeeAvs = false; + bool changedoverlay = false; + bool changedneedupdate = false; // Process the rules, not sure what the impact would be of changing owner or group for (int idx = 0; idx < rules.Length;) @@ -1431,35 +1628,151 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api switch (code) { case ScriptBaseClass.PARCEL_DETAILS_NAME: - newLand.Name = arg; + if(newLand.Name != arg) + { + newLand.Name = arg; + changed = true; + } break; case ScriptBaseClass.PARCEL_DETAILS_DESC: - newLand.Description = arg; + if(newLand.Description != arg) + { + newLand.Description = arg; + changed = true; + } break; case ScriptBaseClass.PARCEL_DETAILS_OWNER: - if (!CheckThreatLevel(ThreatLevel.VeryHigh, functionName)) return; - if (UUID.TryParse(arg, out uuid)) - newLand.OwnerID = uuid; + if(es != null && !es.IsEstateManagerOrOwner(m_host.OwnerID)) + { + OSSLError("script owner does not have permission to modify the parcel owner"); + } + else + { + if (UUID.TryParse(arg, out uuid)) + { + if(newLand.OwnerID != uuid) + { + changed = true; + newLand.OwnerID = uuid; + newLand.GroupID = UUID.Zero; + } + } + } break; case ScriptBaseClass.PARCEL_DETAILS_GROUP: - if (!CheckThreatLevel(ThreatLevel.VeryHigh, functionName)) return; - if (UUID.TryParse(arg, out uuid)) - newLand.GroupID = uuid; + if(m_host.OwnerID == newLand.OwnerID || es == null || es.IsEstateManagerOrOwner(m_host.OwnerID)) + { + if (UUID.TryParse(arg, out uuid)) + { + if(newLand.GroupID != uuid) + { + if(uuid == UUID.Zero) + { + changed = true; + newLand.GroupID = uuid; + } + else + { + IGroupsModule groupsModule = m_ScriptEngine.World.RequestModuleInterface(); + GroupMembershipData member = null; + if (groupsModule != null) + member = groupsModule.GetMembershipData(uuid, newLand.OwnerID); + if (member == null) + OSSLError(string.Format("land owner is not member of the new group for parcel")); + else + { + changed = true; + newLand.GroupID = uuid; + } + } + } + } + } + else + { + OSSLError("script owner does not have permission to modify the parcel group"); + } break; case ScriptBaseClass.PARCEL_DETAILS_CLAIMDATE: - if (!CheckThreatLevel(ThreatLevel.VeryHigh, functionName)) return; - newLand.ClaimDate = Convert.ToInt32(arg); - if (newLand.ClaimDate == 0) - newLand.ClaimDate = Util.UnixTimeSinceEpoch(); + if(es != null && !es.IsEstateManagerOrOwner(m_host.OwnerID)) + { + OSSLError("script owner does not have permission to modify the parcel CLAIM DATE"); + } + else + { + int date = Convert.ToInt32(arg); + if (date == 0) + date = Util.UnixTimeSinceEpoch(); + if(newLand.ClaimDate != date) + { + changed = true; + newLand.ClaimDate = date; + } + } + break; + + case ScriptBaseClass.PARCEL_DETAILS_SEE_AVATARS: + bool newavs = (Convert.ToInt32(arg) != 0); + if(newLand.SeeAVs != newavs) + { + changed = true; + changedSeeAvs = true; + changedoverlay = true; + changedneedupdate = true; + newLand.SeeAVs = newavs; + } + break; + + case ScriptBaseClass.PARCEL_DETAILS_ANY_AVATAR_SOUNDS: + bool newavsounds = (Convert.ToInt32(arg) != 0); + if(newLand.AnyAVSounds != newavsounds) + { + changed = true; + newLand.AnyAVSounds = newavsounds; + } + break; + + case ScriptBaseClass.PARCEL_DETAILS_GROUP_SOUNDS: + bool newgrpsounds = (Convert.ToInt32(arg) != 0); + if(newLand.GroupAVSounds != newgrpsounds) + { + changed = true; + newLand.GroupAVSounds = newgrpsounds; + } break; - } - } + } + } + if(changed) + { + World.LandChannel.UpdateLandObject(newLand.LocalID, newLand); + + if(changedneedupdate) + { + UUID parcelID= newLand.GlobalID; + World.ForEachRootScenePresence(delegate (ScenePresence avatar) + { + if (avatar == null || avatar.IsDeleted || avatar.IsInTransit) + return; + + if(changedSeeAvs && avatar.currentParcelUUID == parcelID ) + avatar.currentParcelUUID = parcelID; // force parcel flags review + + if(avatar.ControllingClient == null) + return; + + // this will be needed for some things like damage etc +// if(avatar.currentParcelUUID == parcelID) +// startLandObject.SendLandUpdateToClient(avatar.ControllingClient); - World.LandChannel.UpdateLandObject(newLand.LocalID,newLand); + if(changedoverlay && !avatar.IsNPC) + World.LandChannel.SendParcelsOverlay(avatar.ControllingClient); + }); + } + } } public double osList2Double(LSL_Types.list src, int index) @@ -1469,7 +1782,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // is not allowed to contain any. // This really should be removed. // - m_host.AddScriptLPS(1); + CheckThreatLevel(); + if (index < 0) { index = src.Length + index; @@ -1485,9 +1799,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // What actually is the difference to the LL function? // - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelMediaURL")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelMediaURL"); ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); @@ -1501,9 +1813,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // What actually is the difference to the LL function? // - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelSIPAddress")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osSetParcelSIPAddress"); ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); @@ -1529,9 +1839,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // that trigger engine-specific failures. // Besides, public grid users aren't supposed to know. // - // On the other hand, what other script engines are there? - // - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osGetScriptEngineName"); int scriptEngineNameIndex = 0; @@ -1557,7 +1865,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer osCheckODE() { - m_host.AddScriptLPS(1); + CheckThreatLevel(); + LSL_Integer ret = 0; // false if (m_ScriptEngine.World.PhysicsScene != null) { @@ -1580,22 +1889,46 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // about the physics engine, this function returns an empty string if // the user does not have permission to see it. This as opposed to // throwing an exception. + m_host.AddScriptLPS(1); string ret = String.Empty; + if (String.IsNullOrEmpty(CheckThreatLevelTest(ThreatLevel.High, "osGetPhysicsEngineType"))) + { + if (m_ScriptEngine.World.PhysicsScene != null) + { + ret = m_ScriptEngine.World.PhysicsScene.EngineType; + // An old physics engine might have an uninitialized engine type + if (ret == null) + ret = "unknown"; + } + } + + return ret; + } + + public string osGetPhysicsEngineName() + { + CheckThreatLevel(); + + string ret = "NoEngine"; if (m_ScriptEngine.World.PhysicsScene != null) { - ret = m_ScriptEngine.World.PhysicsScene.EngineType; + ret = m_ScriptEngine.World.PhysicsScene.EngineName; // An old physics engine might have an uninitialized engine type if (ret == null) - ret = "unknown"; - } - + ret = "UnknownEngine"; + } return ret; } public string osGetSimulatorVersion() { - m_host.AddScriptLPS(1); + // High because it can be used to target attacks to known weaknesses + // This would allow a new class of griefer scripts that don't even + // require their user to know what they are doing (see script + // kiddie) + // + CheckThreatLevel(ThreatLevel.High,"osGetSimulatorVersion"); return m_ScriptEngine.World.GetSimulatorVersion(); } @@ -1639,7 +1972,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public Object osParseJSONNew(string JSON) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osParseJSONNew"); try { @@ -1648,14 +1981,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } catch(Exception e) { - OSSLError("osParseJSONNew: Problems decoding JSON string " + JSON + " : " + e.Message); + OSSLError("osParseJSONNew: Problems decoding JSON string " + JSON + " : " + e.Message) ; return null; } } public Hashtable osParseJSON(string JSON) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osParseJSON"); Object decoded = osParseJSONNew(JSON); @@ -1686,7 +2019,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osMessageObject(LSL_Key objectUUID, string message) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osMessageObject"); UUID objUUID; if (!UUID.TryParse(objectUUID, out objUUID)) // prior to patching, a thrown exception regarding invalid GUID format would be shouted instead. @@ -1715,6 +2048,54 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api "dataserver", resobj, new DetectParams[0])); } + + /// + /// Similar to llDie but given an object UUID + /// + /// + + public void osDie(LSL_Key objectUUID) + { +// CheckThreatLevel(ThreatLevel.VeryHigh, "osDie"); + // if this is restricted to objects rezzed by this host level can be reduced + + CheckThreatLevel(ThreatLevel.Low, "osDie"); + + UUID objUUID; + if (!UUID.TryParse(objectUUID, out objUUID)) + { + OSSLShoutError("osDie() cannot delete objects with invalid UUIDs"); + return; + } + + // harakiri check + if(objUUID == UUID.Zero) + { + if (!m_host.ParentGroup.IsAttachment) + throw new SelfDeleteException(); + return; + } + + SceneObjectGroup sceneOG = World.GetSceneObjectGroup(objUUID); + + if (sceneOG == null || sceneOG.IsDeleted) + return; + + if(sceneOG.IsAttachment) + return; + + if (sceneOG.OwnerID != m_host.OwnerID) + return; + + // harakiri check + if(sceneOG.UUID == m_host.ParentGroup.UUID) + throw new SelfDeleteException(); + + // restrict to objects rezzed by host + if(sceneOG.RezzerID == m_host.ParentGroup.UUID) + World.DeleteSceneObject(sceneOG, false); + } + /// /// Write a notecard directly to the prim's inventory. /// @@ -1727,7 +2108,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The contents of the notecard. public void osMakeNotecard(string notecardName, LSL_Types.list contents) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osMakeNotecard"); StringBuilder notecardData = new StringBuilder(); @@ -1778,8 +2159,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api taskItem.ResetIDs(m_host.UUID); taskItem.ParentID = m_host.UUID; taskItem.CreationDate = (uint)Util.UnixTimeSinceEpoch(); - taskItem.Name = asset.Name; - taskItem.Description = asset.Description; + taskItem.Name = name; + taskItem.Description = description; taskItem.Type = (int)AssetType.Notecard; taskItem.InvType = (int)InventoryType.Notecard; taskItem.OwnerID = m_host.OwnerID; @@ -1799,6 +2180,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.Inventory.AddInventoryItemExclusive(taskItem, false); else m_host.Inventory.AddInventoryItem(taskItem, false); + m_host.ParentGroup.InvalidateDeepEffectivePerms(); return taskItem; } @@ -1843,15 +2225,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID assetID = UUID.Zero; - if (!UUID.TryParse(notecardNameOrUuid, out assetID)) + bool notecardNameIsUUID = UUID.TryParse(notecardNameOrUuid, out assetID); + + if (!notecardNameIsUUID) { - foreach (TaskInventoryItem item in m_host.TaskInventory.Values) - { - if (item.Type == 7 && item.Name == notecardNameOrUuid) - { - assetID = item.AssetID; - } - } + assetID = SearchTaskInventoryForAssetId(notecardNameOrUuid); } if (assetID == UUID.Zero) @@ -1862,13 +2240,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AssetBase a = World.AssetService.Get(assetID.ToString()); if (a == null) - return UUID.Zero; + { + // Whoops, it's still possible here that the notecard name was properly + // formatted like a UUID but isn't an asset UUID so lets look it up by name after all + assetID = SearchTaskInventoryForAssetId(notecardNameOrUuid); + if (assetID == UUID.Zero) + return UUID.Zero; + + if (!NotecardCache.IsCached(assetID)) + { + a = World.AssetService.Get(assetID.ToString()); + + if (a == null) + { + return UUID.Zero; + } + } + } NotecardCache.Cache(assetID, a.Data); }; return assetID; } + protected UUID SearchTaskInventoryForAssetId(string name) + { + UUID assetId = UUID.Zero; + m_host.TaskInventory.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_host.TaskInventory.Values) + { + if (item.Type == 7 && item.Name == name) + { + assetId = item.AssetID; + } + } + m_host.TaskInventory.LockItemsForRead(false); + return assetId; + } /// /// Directly get an entire notecard at once. @@ -1885,7 +2293,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Notecard line public string osGetNotecardLine(string name, int line) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNotecardLine"); UUID assetID = CacheNotecard(name); @@ -1912,7 +2320,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Notecard text public string osGetNotecard(string name) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNotecard"); string text = LoadNotecard(name); @@ -1941,7 +2349,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public int osGetNumberOfNotecardLines(string name) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osGetNumberOfNotecardLines"); UUID assetID = CacheNotecard(name); @@ -1956,8 +2364,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osAvatarName2Key(string firstname, string lastname) { - if (!CheckThreatLevel(ThreatLevel.Low, "osAvatarName2Key")) return string.Empty; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osAvatarName2Key"); IUserManagement userManager = World.RequestModuleInterface(); if (userManager == null) @@ -2008,7 +2415,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osKey2Name(string id) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osKey2Name"); UUID key = new UUID(); @@ -2117,8 +2524,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public string osGetGridNick() { -//// if (!CheckThreatLevel(ThreatLevel.None, "osGetGridNick")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridNick"); string nick = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; @@ -2134,8 +2540,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridName() { -//// if (!CheckThreatLevel(ThreatLevel.None, "osGetGridName")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridName"); string name = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; @@ -2151,8 +2556,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridLoginURI() { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetGridLoginURI")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridLoginURI"); string loginURI = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; @@ -2168,11 +2572,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridHomeURI() { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridHomeURI"); IConfigSource config = m_ScriptEngine.ConfigSource; - string HomeURI = Util.GetConfigVarFromSections(config, "HomeURI", + string HomeURI = Util.GetConfigVarFromSections(config, "HomeURI", new string[] { "Startup", "Hypergrid" }, String.Empty); if (!string.IsNullOrEmpty(HomeURI)) @@ -2190,8 +2593,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridGatekeeperURI() { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridGatekeeperURI"); IConfigSource config = m_ScriptEngine.ConfigSource; string gatekeeperURI = Util.GetConfigVarFromSections(config, "GatekeeperURI", @@ -2209,8 +2611,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetGridCustom(string key) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetGridCustom")) return String.Empty; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetGridCustom"); string retval = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; @@ -2226,8 +2627,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osGetAvatarHomeURI(string uuid) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetAvatarHomeURI")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osGetAvatarHomeURI"); IUserManagement userManager = m_ScriptEngine.World.RequestModuleInterface(); string returnValue = ""; @@ -2259,14 +2659,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String osFormatString(string str, LSL_List strings) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osFormatString"); return String.Format(str, strings.Data); } public LSL_List osMatchString(string src, string pattern, int start) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osMatchString"); LSL_List result = new LSL_List(); @@ -2307,7 +2707,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String osReplaceString(string src, string pattern, string replace, int count, int start) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osReplaceString"); // Normalize indices (if negative). // After normlaization they may still be @@ -2331,24 +2731,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string osLoadedCreationDate() { - if (!CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationDate")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationDate"); return World.RegionInfo.RegionSettings.LoadedCreationDate; } public string osLoadedCreationTime() { - if (!CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationTime")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationTime"); return World.RegionInfo.RegionSettings.LoadedCreationTime; } public string osLoadedCreationID() { - if (!CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationID")) return ""; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osLoadedCreationID"); return World.RegionInfo.RegionSettings.LoadedCreationID; } @@ -2368,8 +2765,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_List osGetLinkPrimitiveParams(int linknumber, LSL_List rules) { - if (!CheckThreatLevel(ThreatLevel.High, "osGetLinkPrimitiveParams")) return new LSL_List(); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osGetLinkPrimitiveParams"); + InitLSL(); // One needs to cast m_LSL_Api because we're using functions not // on the ILSL_Api interface. @@ -2396,9 +2793,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceCreateLink(string target, int parent) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osForceCreateLink")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osForceCreateLink"); InitLSL(); ((LSL_Api)m_LSL_Api).CreateLink(target, parent); @@ -2406,9 +2801,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceBreakLink(int linknum) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakLink")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakLink"); InitLSL(); ((LSL_Api)m_LSL_Api).BreakLink(linknum); @@ -2416,9 +2809,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceBreakAllLinks() { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakAllLinks")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osForceBreakAllLinks"); InitLSL(); ((LSL_Api)m_LSL_Api).BreakAllLinks(); @@ -2426,7 +2817,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer osIsNpc(LSL_Key npc) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2442,31 +2833,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcCreate")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); + + // have to get the npc module also here to set the default Not Owned + INPCModule module = World.RequestModuleInterface(); + if(module == null) + return new LSL_Key(UUID.Zero.ToString()); + + bool owned = (module.NPCOptionFlags & NPCOptionsFlags.AllowNotOwned) == 0; - return NpcCreate(firstname, lastname, position, notecard, false, false); + return NpcCreate(firstname, lastname, position, notecard, owned, false, false); } public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard, int options) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcCreate")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); return NpcCreate( firstname, lastname, position, notecard, (options & ScriptBaseClass.OS_NPC_NOT_OWNED) == 0, - (options & ScriptBaseClass.OS_NPC_SENSE_AS_AGENT) != 0); + (options & ScriptBaseClass.OS_NPC_SENSE_AS_AGENT) != 0, + (options & ScriptBaseClass.OS_NPC_OBJECT_GROUP) != 0); } private LSL_Key NpcCreate( - string firstname, string lastname, LSL_Vector position, string notecard, bool owned, bool senseAsAgent) + string firstname, string lastname, LSL_Vector position, string notecard, bool owned, bool senseAsAgent, bool hostGroupID) { + if (!World.Permissions.CanRezObject(1, m_host.OwnerID, new Vector3((float)position.x, (float)position.y, (float)position.z))) + { + OSSLError("no permission to rez NPC at requested location"); + return new LSL_Key(UUID.Zero.ToString()); + } + INPCModule module = World.RequestModuleInterface(); - if (module != null) + if(module == null) + { + OSSLError("NPC module not enabled"); + return new LSL_Key(UUID.Zero.ToString()); + } + + string groupTitle = String.Empty; + UUID groupID = UUID.Zero; + + AvatarAppearance appearance = null; + + // check creation options + NPCOptionsFlags createFlags = module.NPCOptionFlags; + + if((createFlags & NPCOptionsFlags.AllowNotOwned) == 0 && !owned) + { + OSSLError("Not owned NPCs disabled"); + owned = true; // we should get here... + } + + if((createFlags & NPCOptionsFlags.AllowSenseAsAvatar) == 0 && senseAsAgent) { - AvatarAppearance appearance = null; + OSSLError("NPC allow sense as Avatar disabled"); + senseAsAgent = false; + } + + if(hostGroupID && m_host.GroupID != UUID.Zero) + { + IGroupsModule groupsModule = m_ScriptEngine.World.RequestModuleInterface(); + if (groupsModule != null) + { + GroupMembershipData member = groupsModule.GetMembershipData(m_host.GroupID, m_host.OwnerID); + if (member == null) + { + OSSLError(string.Format("osNpcCreate: the object owner is not member of the object group")); + return new LSL_Key(UUID.Zero.ToString()); + } + + groupID = m_host.GroupID; + + if((createFlags & NPCOptionsFlags.NoNPCGroup) != 0) + { + GroupRecord grprec = groupsModule.GetGroupRecord(m_host.GroupID); + if(grprec != null && grprec.GroupName != "") + groupTitle = grprec.GroupName; + } + } + } + + if((createFlags & NPCOptionsFlags.NoNPCGroup) == 0) + { + if (firstname != String.Empty || lastname != String.Empty) + { + if (firstname != "Shown outfit:") + groupTitle = "- NPC -"; + } + } + if((createFlags & NPCOptionsFlags.AllowCloneOtherAvatars) != 0) + { UUID id; if (UUID.TryParse(notecard, out id)) { @@ -2474,38 +2933,52 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (clonePresence != null) appearance = clonePresence.Appearance; } + } - if (appearance == null) - { - string appearanceSerialized = LoadNotecard(notecard); + if (appearance == null) + { + string appearanceSerialized = LoadNotecard(notecard); - if (appearanceSerialized != null) + if (appearanceSerialized != null) + { + try { OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized); appearance = new AvatarAppearance(); appearance.Unpack(appearanceOsd); } - else + catch { - OSSLError(string.Format("osNpcCreate: Notecard reference '{0}' not found.", notecard)); + OSSLError(string.Format("osNpcCreate: Error processing notcard '{0}'", notecard)); + return new LSL_Key(UUID.Zero.ToString()); } } + else + { + OSSLError(string.Format("osNpcCreate: Notecard reference '{0}' not found.", notecard)); + } + } - UUID ownerID = UUID.Zero; - if (owned) - ownerID = m_host.OwnerID; - UUID x = module.CreateNPC(firstname, - lastname, - position, - ownerID, - senseAsAgent, - World, - appearance); + UUID ownerID = UUID.Zero; + if (owned) + ownerID = m_host.OwnerID; + UUID x = module.CreateNPC(firstname, + lastname, + position, + UUID.Random(), + ownerID, + groupTitle, + groupID, + senseAsAgent, + World, + appearance); - return new LSL_Key(x.ToString()); + ScenePresence sp; + if (World.TryGetScenePresence(x, out sp)) + { + sp.SendAvatarDataToAllAgents(); } - - return new LSL_Key(UUID.Zero.ToString()); + return new LSL_Key(x.ToString()); } /// @@ -2516,8 +2989,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The asset ID of the notecard saved. public LSL_Key osNpcSaveAppearance(LSL_Key npc, string notecard) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcSaveAppearance")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcSaveAppearance"); INPCModule npcModule = World.RequestModuleInterface(); @@ -2538,8 +3010,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcLoadAppearance(LSL_Key npc, string notecard) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcLoadAppearance")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcLoadAppearance"); INPCModule npcModule = World.RequestModuleInterface(); @@ -2570,7 +3041,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Key osNpcGetOwner(LSL_Key npc) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osNpcGetOwner"); INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null) @@ -2591,7 +3062,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector osNpcGetPos(LSL_Key npc) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcGetPos"); INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null) @@ -2614,8 +3085,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2633,8 +3103,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcMoveToTarget(LSL_Key npc, LSL_Vector target, int options) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcMoveToTarget")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcMoveToTarget"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2658,7 +3127,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Rotation osNpcGetRot(LSL_Key npc) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcGetRot"); INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null) @@ -2681,8 +3150,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcSetRot")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcSetRot"); INPCModule npcModule = World.RequestModuleInterface(); if (npcModule != null) @@ -2703,8 +3171,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcStopMoveToTarget(LSL_Key npc) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcStopMoveToTarget")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcStopMoveToTarget"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2718,15 +3185,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - public void osNpcSay(LSL_Key npc, string message) - { - osNpcSay(npc, 0, message); - } - - public void osNpcSay(LSL_Key npc, int channel, string message) + public void osNpcSetProfileAbout(LSL_Key npc, string about) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcSay")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osNpcSetProfileAbout"); + + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + ScenePresence sp = World.GetScenePresence(npcId); + if (sp != null) + ((INPC)(sp.ControllingClient)).profileAbout = about; + } + } + + public void osNpcSetProfileImage(LSL_Key npc, string image) + { + CheckThreatLevel(ThreatLevel.Low, "osNpcSetProfileImage"); + + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + UUID ImageID = new UUID(); + + ImageID = ScriptUtils.GetAssetIdFromItemName(m_host, image, (int)AssetType.Texture); + + if (ImageID == null || ImageID == UUID.Zero) + { + if (!UUID.TryParse(image, out ImageID)) + return; + } + + ScenePresence sp = World.GetScenePresence(npcId); + if (sp != null) + ((INPC)(sp.ControllingClient)).profileImage = ImageID; + } + } + + public void osNpcSay(LSL_Key npc, string message) + { + osNpcSay(npc, 0, message); + } + + public void osNpcSay(LSL_Key npc, int channel, string message) + { + CheckThreatLevel(ThreatLevel.High, "osNpcSay"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2742,8 +3254,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcShout(LSL_Key npc, int channel, string message) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcShout")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcShout"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2759,8 +3270,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcSit(LSL_Key npc, LSL_Key target, int options) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcSit")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcSit"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2776,8 +3286,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcStand(LSL_Key npc) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcStand")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcStand"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2793,25 +3302,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcRemove(LSL_Key npc) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcRemove")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcRemove"); - INPCModule module = World.RequestModuleInterface(); - if (module != null) + try { - UUID npcId = new UUID(npc.m_string); + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); - if (!module.CheckPermissions(npcId, m_host.OwnerID)) - return; + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; - module.DeleteNPC(npcId, World); + module.DeleteNPC(npcId, World); + } } + catch { } } public void osNpcPlayAnimation(LSL_Key npc, string animation) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcPlayAnimation")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcPlayAnimation"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2825,8 +3336,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcStopAnimation(LSL_Key npc, string animation) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcStopAnimation")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcStopAnimation"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2840,8 +3350,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcWhisper(LSL_Key npc, int channel, string message) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcWhisper")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcWhisper"); INPCModule module = World.RequestModuleInterface(); if (module != null) @@ -2857,8 +3366,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num) { - if (!CheckThreatLevel(ThreatLevel.High, "osNpcTouch")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osNpcTouch"); INPCModule module = World.RequestModuleInterface(); int linkNum = link_num.value; @@ -2902,16 +3410,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The asset ID of the notecard saved. public LSL_Key osOwnerSaveAppearance(string notecard) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osOwnerSaveAppearance")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osOwnerSaveAppearance"); return SaveAppearanceToNotecard(m_host.OwnerID, notecard); } public LSL_Key osAgentSaveAppearance(LSL_Key avatarId, string notecard) { - if (!CheckThreatLevel(ThreatLevel.High, "osAgentSaveAppearance")) return new LSL_Key(ScriptBaseClass.NULL_KEY); - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osAgentSaveAppearance"); return SaveAppearanceToNotecard(avatarId, notecard); } @@ -2923,7 +3429,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (appearanceModule != null) { appearanceModule.SaveBakedTextures(sp.UUID); - OSDMap appearancePacked = sp.Appearance.Pack(); + EntityTransferContext ctx = new EntityTransferContext(); + OSDMap appearancePacked = sp.Appearance.Pack(ctx); TaskInventoryItem item = SaveNotecard(notecard, "Avatar Appearance", Util.GetFormattedXml(appearancePacked as OSD), true); @@ -2962,7 +3469,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// "male" or "female" or "unknown" public LSL_String osGetGender(LSL_Key rawAvatarId) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osGetGender"); UUID avatarId; if (!UUID.TryParse(rawAvatarId, out avatarId)) @@ -3005,7 +3512,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Key osGetMapTexture() { - m_host.AddScriptLPS(1); + CheckThreatLevel(); return m_ScriptEngine.World.RegionInfo.RegionSettings.TerrainImageID.ToString(); } @@ -3017,7 +3524,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Key osGetRegionMapTexture(string regionName) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osGetRegionMapTexture"); Scene scene = m_ScriptEngine.World; UUID key = UUID.Zero; @@ -3033,6 +3540,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (region != null) key = region.TerrainImage; + ScriptSleep(1000); + return key.ToString(); } @@ -3045,7 +3554,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// List of floats public LSL_List osGetRegionStats() { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetRegionStats"); + LSL_List ret = new LSL_List(); float[] stats = World.StatsReporter.LastReportedSimStats; @@ -3058,32 +3568,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector osGetRegionSize() { - m_host.AddScriptLPS(1); - - bool isMegaregion; - IRegionCombinerModule rcMod = World.RequestModuleInterface(); - if (rcMod != null) - isMegaregion = rcMod.IsRootForMegaregion(World.RegionInfo.RegionID); - else - isMegaregion = false; + CheckThreatLevel(); - if (isMegaregion) - { - Vector2 size = rcMod.GetSizeOfMegaregion(World.RegionInfo.RegionID); - return new LSL_Vector(size.X, size.Y, Constants.RegionHeight); - } - else - { - Scene scene = m_ScriptEngine.World; - GridRegion region = scene.GridService.GetRegionByUUID(UUID.Zero, World.RegionInfo.RegionID); - return new LSL_Vector((float)region.RegionSizeX, (float)region.RegionSizeX, Constants.RegionHeight); - } + Scene scene = m_ScriptEngine.World; + RegionInfo reg = World.RegionInfo; +// GridRegion region = scene.GridService.GetRegionByUUID(UUID.Zero, World.RegionInfo.RegionID); +// return new LSL_Vector((float)region.RegionSizeX, (float)region.RegionSizeY, (float)Constants.RegionHeight); + return new LSL_Vector((float)reg.RegionSizeX, (float)reg.RegionSizeY, 0.0f); } public int osGetSimulatorMemory() { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetSimulatorMemory")) return 0; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetSimulatorMemory"); + long pws = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; if (pws > Int32.MaxValue) @@ -3094,10 +3591,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return (int)pws; } + public int osGetSimulatorMemoryKB() + { + CheckThreatLevel(ThreatLevel.Moderate, "osGetSimulatorMemoryKB"); + + long pws = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; + + if((pws & 0x3FFL) != 0) + pws += 0x400L; + pws >>= 10; + + if (pws > Int32.MaxValue) + return Int32.MaxValue; + + return (int)pws; + } + public void osSetSpeed(string UUID, LSL_Float SpeedModifier) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osSetSpeed")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osSetSpeed"); + ScenePresence avatar = World.GetScenePresence(new UUID(UUID)); if (avatar != null) @@ -3106,8 +3619,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osKickAvatar(string FirstName, string SurName, string alert) { - if (!CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar"); World.ForEachRootScenePresence(delegate(ScenePresence sp) { @@ -3125,23 +3637,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float osGetHealth(string avatar) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osGetHealth"); LSL_Float health = new LSL_Float(-1); ScenePresence presence = World.GetScenePresence(new UUID(avatar)); - if (presence != null) health = presence.Health; + if (presence != null) + health = presence.Health; return health; } public void osCauseDamage(string avatar, double damage) { - if (!CheckThreatLevel(ThreatLevel.High, "osCauseDamage")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osCauseDamage"); UUID avatarId = new UUID(avatar); Vector3 pos = m_host.GetWorldPosition(); - ScenePresence presence = World.GetScenePresence(avatarId); + ScenePresence presence = World.GetScenePresence(avatarId); if (presence != null) { LandData land = World.GetLandData(pos); @@ -3163,13 +3675,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osCauseHealing(string avatar, double healing) { - if (!CheckThreatLevel(ThreatLevel.High, "osCauseHealing")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osCauseHealing"); UUID avatarId = new UUID(avatar); ScenePresence presence = World.GetScenePresence(avatarId); - if (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition())) + if (presence != null) { float health = presence.Health; health += (float)healing; @@ -3181,31 +3692,67 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public void osSetHealth(string avatar, double health) + { + CheckThreatLevel(ThreatLevel.High, "osSetHealth"); + + UUID avatarId = new UUID(avatar); + ScenePresence presence = World.GetScenePresence(avatarId); + + if (presence != null) + { + if (health > 100.0) + health = 100.0; + else if (health < 1.0) + health = 1.0; + + presence.setHealthWithUpdate((float)health); + } + } + + public void osSetHealRate(string avatar, double healrate) + { + CheckThreatLevel(ThreatLevel.High, "osSetHealRate"); + + UUID avatarId = new UUID(avatar); + ScenePresence presence = World.GetScenePresence(avatarId); + + if (presence != null) + presence.HealRate = (float)healrate; + } + + public LSL_Float osGetHealRate(string avatar) + { + CheckThreatLevel(ThreatLevel.None, "osGetHealRate"); + + LSL_Float rate = new LSL_Float(0); + ScenePresence presence = World.GetScenePresence(new UUID(avatar)); + if (presence != null) + rate = presence.HealRate; + return rate; + } + public LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules) { - if (!CheckThreatLevel(ThreatLevel.High, "osGetPrimitiveParams")) return new LSL_List(); - m_host.AddScriptLPS(1); - InitLSL(); + CheckThreatLevel(ThreatLevel.High, "osGetPrimitiveParams"); + InitLSL(); return m_LSL_Api.GetPrimitiveParamsEx(prim, rules); } public void osSetPrimitiveParams(LSL_Key prim, LSL_List rules) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetPrimitiveParams")) return; - m_host.AddScriptLPS(1); - InitLSL(); + CheckThreatLevel(ThreatLevel.High, "osSetPrimitiveParams"); + InitLSL(); m_LSL_Api.SetPrimitiveParamsEx(prim, rules, "osSetPrimitiveParams"); } /// - /// Set parameters for light projection in host prim + /// Set parameters for light projection in host prim /// public void osSetProjectionParams(bool projection, LSL_Key texture, double fov, double focus, double amb) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetProjectionParams")) return; - osSetProjectionParams(UUID.Zero.ToString(), projection, texture, fov, focus, amb); } @@ -3214,8 +3761,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osSetProjectionParams(LSL_Key prim, bool projection, LSL_Key texture, double fov, double focus, double amb) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetProjectionParams")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osSetProjectionParams"); SceneObjectPart obj = null; if (prim == UUID.Zero.ToString()) @@ -3245,12 +3791,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Strided list of the UUID, position and name of each avatar in the region public LSL_List osGetAvatarList() { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osGetAvatarList"); LSL_List result = new LSL_List(); World.ForEachRootScenePresence(delegate (ScenePresence avatar) { - if (avatar != null && avatar.UUID != m_host.OwnerID) + if (avatar != null && !avatar.IsDeleted && avatar.UUID != m_host.OwnerID ) + { + result.Add(new LSL_String(avatar.UUID.ToString())); + result.Add(new LSL_Vector(avatar.AbsolutePosition)); + result.Add(new LSL_String(avatar.Name)); + } + }); + + return result; + } + + public LSL_List osGetNPCList() + { + CheckThreatLevel(ThreatLevel.None, "osGetNPCList"); + + LSL_List result = new LSL_List(); + World.ForEachRootScenePresence(delegate (ScenePresence avatar) + { + // npcs are not childagents but that is now. + if (avatar != null && avatar.IsNPC && !avatar.IsDeleted && !avatar.IsChildAgent && !avatar.IsInTransit) { result.Add(new LSL_String(avatar.UUID.ToString())); result.Add(new LSL_Vector(avatar.AbsolutePosition)); @@ -3268,7 +3833,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_String osUnixTimeToTimestamp(long time) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osUnixTimeToTimestamp"); long baseTicks = 621355968000000000; long tickResolution = 10000000; @@ -3282,10 +3847,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// Get the description from an inventory item /// /// - /// Item description + /// Item description public LSL_String osGetInventoryDesc(string item) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); lock (m_host.TaskInventory) { @@ -3308,8 +3873,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Integer osInviteToGroup(LSL_Key agentId) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osInviteToGroup")) return ScriptBaseClass.FALSE; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osInviteToGroup"); UUID agent = new UUID(agentId); @@ -3343,8 +3907,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Integer osEjectFromGroup(LSL_Key agentId) { - if (!CheckThreatLevel(ThreatLevel.VeryLow, "osEjectFromGroup")) return ScriptBaseClass.FALSE; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryLow, "osEjectFromGroup"); UUID agent = new UUID(agentId); @@ -3378,9 +3941,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osSetTerrainTexture(int level, LSL_Key texture) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetTerrainTexture")) return; + CheckThreatLevel(ThreatLevel.High, "osSetTerrainTexture"); - m_host.AddScriptLPS(1); //Check to make sure that the script's owner is the estate manager/master //World.Permissions.GenericEstatePermission( if (World.Permissions.IsGod(m_host.OwnerID)) @@ -3408,9 +3970,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osSetTerrainTextureHeight(int corner, double low, double high) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetTerrainTextureHeight")) return; + CheckThreatLevel(ThreatLevel.High, "osSetTerrainTextureHeight"); - m_host.AddScriptLPS(1); //Check to make sure that the script's owner is the estate manager/master //World.Permissions.GenericEstatePermission( if (World.Permissions.IsGod(m_host.OwnerID)) @@ -3429,9 +3990,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceAttachToAvatar(int attachmentPoint) { - if (!CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatar")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatar"); InitLSL(); ((LSL_Api)m_LSL_Api).AttachToAvatar(attachmentPoint); @@ -3439,18 +3998,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceAttachToAvatarFromInventory(string itemName, int attachmentPoint) { - if (!CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatarFromInventory")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatarFromInventory"); ForceAttachToAvatarFromInventory(m_host.OwnerID, itemName, attachmentPoint); } public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint) { - if (!CheckThreatLevel(ThreatLevel.Severe, "osForceAttachToOtherAvatarFromInventory")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.VeryHigh, "osForceAttachToOtherAvatarFromInventory"); UUID avatarId; @@ -3480,7 +4035,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (item.InvType != (int)InventoryType.Object) { // FIXME: Temporary null check for regression tests since they dont' have the infrastructure to set - // up the api reference. + // up the api reference. if (m_LSL_Api != null) ((LSL_Api)m_LSL_Api).llSay(0, string.Format("Unable to attach, item '{0}' is not an object.", itemName)); @@ -3509,9 +4064,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osForceDetachFromAvatar() { - if (!CheckThreatLevel(ThreatLevel.High, "osForceDetachFromAvatar")) return; - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceDetachFromAvatar"); InitLSL(); ((LSL_Api)m_LSL_Api).DetachFromAvatar(); @@ -3519,9 +4072,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List osGetNumberOfAttachments(LSL_Key avatar, LSL_List attachmentPoints) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osGetNumberOfAttachments")) return new LSL_List(); - - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osGetNumberOfAttachments"); UUID targetUUID; ScenePresence target; @@ -3555,15 +4106,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osMessageAttachments(LSL_Key avatar, string message, LSL_List attachmentPoints, int options) { - if (!CheckThreatLevel(ThreatLevel.Moderate, "osMessageAttachments")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osMessageAttachments"); UUID targetUUID; + if(!UUID.TryParse(avatar.ToString(), out targetUUID)) + return; + + if(targetUUID == UUID.Zero) + return; + ScenePresence target; + if(!World.TryGetScenePresence(targetUUID, out target)) + return; - if (attachmentPoints.Length >= 1 && UUID.TryParse(avatar.ToString(), out targetUUID) && World.TryGetScenePresence(targetUUID, out target)) + if(target.IsDeleted || target.IsInTransit) + return; + + List aps = new List(); + if(attachmentPoints.Length != 0) { - List aps = new List(); foreach (object point in attachmentPoints.Data) { int ipoint; @@ -3572,115 +4133,76 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api aps.Add(ipoint); } } + // parsing failed + if(aps.Count != attachmentPoints.Length) + return; + } - List attachments = new List(); - - bool msgAll = aps.Contains(ScriptBaseClass.OS_ATTACH_MSG_ALL); - bool invertPoints = (options & ScriptBaseClass.OS_ATTACH_MSG_INVERT_POINTS) != 0; + List attachments = new List(); - if (msgAll && invertPoints) - { - return; - } - else if (msgAll || invertPoints) - { - attachments = target.GetAttachments(); - } - else - { - foreach (int point in aps) - { - if (point > 0) - { - attachments.AddRange(target.GetAttachments((uint)point)); - } - } - } + bool msgAll; + bool invertPoints = (options & ScriptBaseClass.OS_ATTACH_MSG_INVERT_POINTS) != 0; - // if we have no attachments at this point, exit now - if (attachments.Count == 0) - { + if(aps.Count == 0) + { + if(!invertPoints) return; - } + msgAll = true; + invertPoints = false; + } + else + msgAll = aps.Contains(ScriptBaseClass.OS_ATTACH_MSG_ALL); - List ignoreThese = new List(); + if (msgAll && invertPoints) + return; - if (invertPoints) + if (msgAll || invertPoints) + { + attachments = target.GetAttachments(); + } + else + { + foreach (int point in aps) { - foreach (SceneObjectGroup attachment in attachments) + if (point > 0) { - if (aps.Contains((int)attachment.AttachmentPoint)) - { - ignoreThese.Add(attachment); - } + attachments.AddRange(target.GetAttachments((uint)point)); } } + } - foreach (SceneObjectGroup attachment in ignoreThese) - { - attachments.Remove(attachment); - } - ignoreThese.Clear(); - - // if inverting removed all attachments to check, exit now - if (attachments.Count < 1) - { - return; - } + // if we have no attachments at this point, exit now + if (attachments.Count == 0) + { + return; + } - if ((options & ScriptBaseClass.OS_ATTACH_MSG_OBJECT_CREATOR) != 0) - { - foreach (SceneObjectGroup attachment in attachments) - { - if (attachment.RootPart.CreatorID != m_host.CreatorID) - { - ignoreThese.Add(attachment); - } - } + bool optionObjCreator = (options & + ScriptBaseClass.OS_ATTACH_MSG_OBJECT_CREATOR) != 0; + bool optionScriptCreator = (options & + ScriptBaseClass.OS_ATTACH_MSG_SCRIPT_CREATOR) != 0; - foreach (SceneObjectGroup attachment in ignoreThese) - { - attachments.Remove(attachment); - } - ignoreThese.Clear(); + UUID hostCreatorID = m_host.CreatorID; + UUID itemCreatorID = m_item.CreatorID; - // if filtering by same object creator removed all - // attachments to check, exit now - if (attachments.Count == 0) - { - return; - } - } + foreach (SceneObjectGroup sog in attachments) + { + if(sog.IsDeleted || sog.inTransit) + continue; - if ((options & ScriptBaseClass.OS_ATTACH_MSG_SCRIPT_CREATOR) != 0) - { - foreach (SceneObjectGroup attachment in attachments) - { - if (attachment.RootPart.CreatorID != m_item.CreatorID) - { - ignoreThese.Add(attachment); - } - } + if (invertPoints && aps.Contains((int)sog.AttachmentPoint)) + continue; - foreach (SceneObjectGroup attachment in ignoreThese) - { - attachments.Remove(attachment); - } - ignoreThese.Clear(); + UUID CreatorID = sog.RootPart.CreatorID; + if (optionObjCreator && CreatorID != hostCreatorID) + continue; - // if filtering by object creator must match originating - // script creator removed all attachments to check, - // exit now - if (attachments.Count == 0) - { - return; - } - } + if (optionScriptCreator && CreatorID != itemCreatorID) + continue; - foreach (SceneObjectGroup attachment in attachments) - { - MessageObject(attachment.RootPart.UUID, message); - } + SceneObjectPart[] parts = sog.Parts; + foreach(SceneObjectPart p in parts) + MessageObject(p.UUID, message); } } @@ -3693,7 +4215,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// 1 if thing is a valid UUID, 0 otherwise public LSL_Integer osIsUUID(string thing) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); UUID test; return UUID.TryParse(thing, out test) ? 1 : 0; @@ -3707,7 +4229,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Float osMin(double a, double b) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); return Math.Min(a, b); } @@ -3720,16 +4242,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public LSL_Float osMax(double a, double b) { - m_host.AddScriptLPS(1); + CheckThreatLevel(); return Math.Max(a, b); } public LSL_Key osGetRezzingObject() { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.None, "osGetRezzingObject"); - return new LSL_Key(m_host.ParentGroup.FromPartID.ToString()); + UUID rezID = m_host.ParentGroup.RezzerID; + if(rezID == UUID.Zero || m_host.ParentGroup.Scene.GetScenePresence(rezID) != null) + return new LSL_Key(UUID.Zero.ToString()); + return new LSL_Key(rezID.ToString()); } /// @@ -3738,7 +4263,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public void osSetContentType(LSL_Key id, string type) { - if (!CheckThreatLevel(ThreatLevel.High, "osSetContentType")) return; + CheckThreatLevel(ThreatLevel.High, "osSetContentType"); if (m_UrlModule != null) m_UrlModule.HttpContentType(new UUID(id),type); @@ -3750,7 +4275,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// boolean indicating whether an error was shouted. protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix) { - m_host.AddScriptLPS(1); bool fail = false; if (m_item.PermsGranter != m_host.OwnerID) { @@ -3800,39 +4324,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osDropAttachment() { - if (!CheckThreatLevel(ThreatLevel.Low, "osDropAttachment")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachment"); DropAttachment(true); } public void osForceDropAttachment() { - if (!CheckThreatLevel(ThreatLevel.High, "osForceDropAttachment")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceDropAttachment"); DropAttachment(false); } public void osDropAttachmentAt(LSL_Vector pos, LSL_Rotation rot) { - if (!CheckThreatLevel(ThreatLevel.Low, "osDropAttachmentAt")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachmentAt"); DropAttachmentAt(true, pos, rot); } public void osForceDropAttachmentAt(LSL_Vector pos, LSL_Rotation rot) { - if (!CheckThreatLevel(ThreatLevel.High, "osForceDropAttachmentAt")) return; - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.High, "osForceDropAttachmentAt"); DropAttachmentAt(false, pos, rot); } public LSL_Integer osListenRegex(int channelID, string name, string ID, string msg, int regexBitfield) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osListenRegex"); + UUID keyID; UUID.TryParse(ID, out keyID); @@ -3879,7 +4400,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer osRegexIsMatch(string input, string pattern) { - m_host.AddScriptLPS(1); + CheckThreatLevel(ThreatLevel.Low, "osRegexIsMatch"); + try { return Regex.IsMatch(input, pattern) ? 1 : 0; @@ -3890,5 +4412,392 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 0; } } + + public LSL_String osRequestURL(LSL_List options) + { + CheckThreatLevel(ThreatLevel.Moderate, "osRequestSecureURL"); + + Hashtable opts = new Hashtable(); + for (int i = 0 ; i < options.Length ; i++) + { + object opt = options.Data[i]; + if (opt.ToString() == "allowXss") + opts["allowXss"] = true; + } + + if (m_UrlModule != null) + return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID, opts).ToString(); + return UUID.Zero.ToString(); + } + + public LSL_String osRequestSecureURL(LSL_List options) + { + CheckThreatLevel(ThreatLevel.Moderate, "osRequestSecureURL"); + + Hashtable opts = new Hashtable(); + for (int i = 0 ; i < options.Length ; i++) + { + object opt = options.Data[i]; + if (opt.ToString() == "allowXss") + opts["allowXss"] = true; + } + + if (m_UrlModule != null) + return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID, opts).ToString(); + return UUID.Zero.ToString(); + } + + public void osCollisionSound(string impact_sound, double impact_volume) + { + CheckThreatLevel(); + + if(impact_sound == "") + { + m_host.CollisionSoundVolume = (float)impact_volume; + m_host.CollisionSound = m_host.invalidCollisionSoundUUID; + if(impact_volume == 0.0) + m_host.CollisionSoundType = -1; // disable all sounds + else if(impact_volume == 1.0f) + m_host.CollisionSoundType = 0; // full return to default sounds + else + m_host.CollisionSoundType = 2; // default sounds with volume + m_host.aggregateScriptEvents(); + return; + } + // TODO: Parameter check logic required. + UUID soundId = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound); + if(soundId != UUID.Zero) + { + m_host.CollisionSound = soundId; + m_host.CollisionSoundVolume = (float)impact_volume; + m_host.CollisionSoundType = 1; + } + else + m_host.CollisionSoundType = -1; + + m_host.aggregateScriptEvents(); + } + + // still not very usefull, detector is lost on rez, restarts, etc + public void osVolumeDetect(int detect) + { + CheckThreatLevel(); + + if (m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted || m_host.ParentGroup.IsAttachment) + return; + + m_host.ScriptSetVolumeDetect(detect != 0); + } + + /// + /// Get inertial data + /// + /// + /// + /// + /// a LSL list with contents: + /// LSL_Float mass, the total mass of a linkset + /// LSL_Vector CenterOfMass, center mass relative to root prim + /// LSL_Vector Inertia, elements of diagonal of inertia Ixx,Iyy,Izz divided by total mass + /// LSL_Vector aux, elements of upper triagle of inertia Ixy (= Iyx), Ixz (= Izx), Iyz(= Izy) divided by total mass + /// + public LSL_List osGetInertiaData() + { + CheckThreatLevel(); + + LSL_List result = new LSL_List(); + float TotalMass; + Vector3 CenterOfMass; + Vector3 Inertia; + Vector4 aux; + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return result; + + sog.GetInertiaData(out TotalMass, out CenterOfMass, out Inertia, out aux ); + if(TotalMass > 0) + { + float t = 1.0f/TotalMass; + Inertia.X *= t; + Inertia.Y *= t; + Inertia.Z *= t; + + aux.X *= t; + aux.Y *= t; + aux.Z *= t; + } + + result.Add(new LSL_Float(TotalMass)); + result.Add(new LSL_Vector(CenterOfMass.X, CenterOfMass.Y, CenterOfMass.Z)); + result.Add(new LSL_Vector(Inertia.X, Inertia.Y, Inertia.Z)); + result.Add(new LSL_Vector(aux.X, aux.Y, aux.Z)); + return result; + } + + /// + /// set inertial data + /// replaces the automatic calculation of mass, center of mass and inertia + /// + /// + /// total mass of linkset + /// location of center of mass relative to root prim in local coords + /// moment of inertia relative to principal axis and center of mass,Ixx, Iyy, Izz divided by mass + /// rotation of the inertia, relative to local axis + /// + /// the inertia argument is is inertia divided by mass, so corresponds only to the geometric distribution of mass and both can be changed independently. + /// + + public void osSetInertia(LSL_Float mass, LSL_Vector centerOfMass, LSL_Vector principalInertiaScaled, LSL_Rotation lslrot) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + if(mass < 0 || principalInertiaScaled.x < 0 || principalInertiaScaled.y < 0 || principalInertiaScaled.z < 0) + return; + + // need more checks + + Vector3 CenterOfMass = new Vector3((float)centerOfMass.x,(float)centerOfMass.y,(float)centerOfMass.z); + Vector3 Inertia; + float m = (float)mass; + + Inertia.X = m * (float)principalInertiaScaled.x; + Inertia.Y = m * (float)principalInertiaScaled.y; + Inertia.Z = m * (float)principalInertiaScaled.z; + + Vector4 rot = new Vector4((float)lslrot.x, (float)lslrot.y, (float)lslrot.y, (float)lslrot.s); + rot.Normalize(); + + sog.SetInertiaData(m, CenterOfMass, Inertia, rot ); + } + + /// + /// set inertial data as a sphere + /// replaces the automatic calculation of mass, center of mass and inertia + /// + /// + /// total mass of linkset + /// size of the Box + /// location of center of mass relative to root prim in local coords + /// rotation of the box, and so inertia, relative to local axis + /// + /// + public void osSetInertiaAsBox(LSL_Float mass, LSL_Vector boxSize, LSL_Vector centerOfMass, LSL_Rotation lslrot) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + if(mass < 0) + return; + + // need more checks + + Vector3 CenterOfMass = new Vector3((float)centerOfMass.x,(float)centerOfMass.y,(float)centerOfMass.z); + Vector3 Inertia; + float lx = (float)boxSize.x; + float ly = (float)boxSize.y; + float lz = (float)boxSize.z; + float m = (float)mass; + float t = m / 12.0f; + + Inertia.X = t * (ly*ly + lz*lz); + Inertia.Y = t * (lx*lx + lz*lz); + Inertia.Z = t * (lx*lx + ly*ly); + + Vector4 rot = new Vector4((float)lslrot.x, (float)lslrot.y, (float)lslrot.z, (float)lslrot.s); + rot.Normalize(); + + sog.SetInertiaData(m, CenterOfMass, Inertia, rot ); + } + + /// + /// set inertial data as a sphere + /// replaces the automatic calculation of mass, center of mass and inertia + /// + /// + /// total mass of linkset + /// radius of the sphere + /// location of center of mass relative to root prim in local coords + /// + /// + public void osSetInertiaAsSphere(LSL_Float mass, LSL_Float radius, LSL_Vector centerOfMass) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + if(mass < 0) + return; + + // need more checks + + Vector3 CenterOfMass = new Vector3((float)centerOfMass.x,(float)centerOfMass.y,(float)centerOfMass.z); + Vector3 Inertia; + float r = (float)radius; + float m = (float)mass; + float t = 0.4f * m * r * r; + + Inertia.X = t; + Inertia.Y = t; + Inertia.Z = t; + + sog.SetInertiaData(m, CenterOfMass, Inertia, new Vector4(0f, 0f, 0f,1.0f)); + } + + /// + /// set inertial data as a cylinder + /// replaces the automatic calculation of mass, center of mass and inertia + /// + /// + /// total mass of linkset + /// radius of the cylinder + /// lenght of the cylinder + /// location of center of mass relative to root prim in local coords + /// rotation of the cylinder, and so inertia, relative to local axis + /// + /// cylinder axis aligned with Z axis. For other orientations provide the rotation. + /// + public void osSetInertiaAsCylinder(LSL_Float mass, LSL_Float radius, LSL_Float lenght, LSL_Vector centerOfMass, LSL_Rotation lslrot) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + if(mass < 0) + return; + + // need more checks + + Vector3 CenterOfMass = new Vector3((float)centerOfMass.x,(float)centerOfMass.y,(float)centerOfMass.z); + Vector3 Inertia; + float m = (float)mass; + float r = (float)radius; + r *= r; + Inertia.Z = 0.5f * m * r; + float t = (float)lenght; + t *= t; + t += 3.0f * r; + t *= 8.333333e-2f * m; + + Inertia.X = t; + Inertia.Y = t; + + Vector4 rot = new Vector4((float)lslrot.x, (float)lslrot.y, (float)lslrot.z, (float)lslrot.s); + rot.Normalize(); + + sog.SetInertiaData(m, CenterOfMass, Inertia, rot); + } + + /// + /// removes inertial data manual override + /// default automatic calculation is used again + /// + /// + public void osClearInertia() + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return; + + sog.SetInertiaData(-1, Vector3.Zero, Vector3.Zero, Vector4.Zero ); + } + + private bool checkAllowObjectTPbyLandOwner(Vector3 pos) + { + ILandObject land = World.LandChannel.GetLandObject(pos); + if(land == null) + return true; + + LandData landdata = land.LandData; + if(landdata == null) + return true; + + UUID hostOwner = m_host.OwnerID; + if(landdata.OwnerID == hostOwner) + return true; + + EstateSettings es = World.RegionInfo.EstateSettings; + if(es != null && es.IsEstateManagerOrOwner(hostOwner)) + return true; + + if(!landdata.IsGroupOwned) + return false; + + UUID landGroup = landdata.GroupID; + if(landGroup == UUID.Zero) + return false; + + if(landGroup == m_host.GroupID) + return true; + + return false; + } + + /// + /// teleports a object (full linkset) + /// + /// the id of the linkset to teleport + /// target position + /// a rotation to apply + /// several flags/param> + /// + /// only does teleport local to region + /// if object has scripts, owner must have rights to run scripts on target location + /// object owner must have rights to enter ojects on target location + /// target location parcel must have enought free prims capacity for the linkset prims + /// all avatars siting on the object must have access to target location + /// has a cool down time. retries before expire reset it + /// fail conditions are silent ignored + /// + public LSL_Integer osTeleportObject(LSL_Key objectUUID, LSL_Vector targetPos, LSL_Rotation rotation, LSL_Integer flags) + { + CheckThreatLevel(ThreatLevel.Severe, "osTeleportObject"); + + UUID objUUID; + if (!UUID.TryParse(objectUUID, out objUUID)) + { + OSSLShoutError("osTeleportObject() invalid object Key"); + return -1; + } + + SceneObjectGroup sog = World.GetSceneObjectGroup(objUUID); + if(sog== null || sog.IsDeleted || sog.inTransit) + return -1; + + if(sog.OwnerID != m_host.OwnerID) + { + Vector3 pos = sog.AbsolutePosition; + if(!checkAllowObjectTPbyLandOwner(pos)) + return -1; + } + + UUID myid = m_host.ParentGroup.UUID; + + return sog.TeleportObject(myid, targetPos, rotation, flags); + // a delay here may break vehicles + } + + public LSL_Integer osGetLinkNumber(LSL_String name) + { + CheckThreatLevel(); + + SceneObjectGroup sog = m_host.ParentGroup; + if(sog== null || sog.IsDeleted) + return -1; + return sog.GetLinkNumber(name); + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index 64dc2e2..cc98bbb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -93,7 +93,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins private const int AGENT = 1; private const int AGENT_BY_USERNAME = 0x10; private const int NPC = 0x20; - private const int OS_NPC = 0x01000000; private const int ACTIVE = 2; private const int PASSIVE = 4; private const int SCRIPTED = 8; @@ -161,7 +160,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins ts.arc = arc; ts.host = host; - ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); + ts.next = DateTime.UtcNow.AddSeconds(ts.interval); AddSenseRepeater(ts); } @@ -197,14 +196,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins public void CheckSenseRepeaterEvents() { // Go through all timers - foreach (SensorInfo ts in SenseRepeaters) + + List curSensors; + lock(SenseRepeatListLock) + curSensors = SenseRepeaters; + + DateTime now = DateTime.UtcNow; + foreach (SensorInfo ts in curSensors) { // Time has passed? - if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime()) + if (ts.next < now) { SensorSweep(ts); // set next interval - ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); + ts.next = now.AddSeconds(ts.interval); } } } @@ -240,7 +245,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins List sensedEntities = new List(); // Is the sensor type is AGENT and not SCRIPTED then include agents - if ((ts.type & (AGENT | AGENT_BY_USERNAME | NPC | OS_NPC)) != 0 && (ts.type & SCRIPTED) == 0) + if ((ts.type & (AGENT | AGENT_BY_USERNAME | NPC)) != 0 && (ts.type & SCRIPTED) == 0) { sensedEntities.AddRange(doAgentSensor(ts)); } @@ -339,7 +344,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins float dy; float dz; - Quaternion q = SensePoint.GetWorldRotation(); +// Quaternion q = SensePoint.RotationOffset; + Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation! if (SensePoint.ParentGroup.IsAttachment) { // In attachments, rotate the sensor cone with the @@ -351,14 +357,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // your head but the sensor will stay with your (global) // avatar rotation and position. // Position of a sensor in a child prim attached to an avatar - // will be still wrong. + // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); // Don't proceed if the avatar for this attachment has since been removed from the scene. if (avatar == null) return sensedEntities; - q = avatar.GetWorldRotation() * q; + fromRegionPos = avatar.AbsolutePosition; + q = avatar.Rotation; } LSL_Types.Quaternion r = new LSL_Types.Quaternion(q); @@ -402,7 +409,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins objtype = 0; part = ((SceneObjectGroup)ent).RootPart; - if (part.ParentGroup.AttachmentPoint != 0) // Attached so ignore + if (part.ParentGroup.RootPart.Shape.PCode != (byte)PCode.Tree && + part.ParentGroup.RootPart.Shape.PCode != (byte)PCode.NewTree && + part.ParentGroup.AttachmentPoint != 0) // Attached so ignore continue; if (part.Inventory.ContainsScripts()) @@ -470,7 +479,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins SceneObjectPart SensePoint = ts.host; Vector3 fromRegionPos = SensePoint.GetWorldPosition(); - + Quaternion q = SensePoint.GetWorldRotation(); if (SensePoint.ParentGroup.IsAttachment) { @@ -483,14 +492,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // your head but the sensor will stay with your (global) // avatar rotation and position. // Position of a sensor in a child prim attached to an avatar - // will be still wrong. + // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); // Don't proceed if the avatar for this attachment has since been removed from the scene. if (avatar == null) return sensedEntities; - - q = avatar.GetWorldRotation() * q; + fromRegionPos = avatar.AbsolutePosition; + q = avatar.Rotation; } LSL_Types.Quaternion r = new LSL_Types.Quaternion(q); @@ -499,14 +508,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins bool attached = (SensePoint.ParentGroup.AttachmentPoint != 0); Vector3 toRegionPos; double dis; - + Action senseEntity = new Action(presence => { // m_log.DebugFormat( // "[SENSOR REPEAT]: Inspecting scene presence {0}, type {1} on sensor sweep for {2}, type {3}", // presence.Name, presence.PresenceType, ts.name, ts.type); - if ((ts.type & NPC) == 0 && (ts.type & OS_NPC) == 0 && presence.PresenceType == PresenceType.Npc) + if ((ts.type & NPC) == 0 && presence.PresenceType == PresenceType.Npc) { INPC npcData = m_npcModule.GetNPC(presence.UUID, presence.Scene); if (npcData == null || !npcData.SenseAsAgent) @@ -537,16 +546,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins } } - if (presence.IsDeleted || presence.IsChildAgent || presence.GodLevel > 0.0) + if (presence.IsDeleted || presence.IsChildAgent || presence.IsViewerUIGod) return; - + // if the object the script is in is attached and the avatar is the owner // then this one is not wanted if (attached && presence.UUID == SensePoint.OwnerID) return; toRegionPos = presence.AbsolutePosition; - dis = Math.Abs(Util.GetDistanceTo(toRegionPos, fromRegionPos)); + dis = Util.GetDistanceTo(toRegionPos, fromRegionPos); + if (presence.IsSatOnObject && presence.ParentPart != null && + presence.ParentPart.ParentGroup != null && + presence.ParentPart.ParentGroup.RootPart != null) + { + Vector3 rpos = presence.ParentPart.ParentGroup.RootPart.AbsolutePosition; + double dis2 = Util.GetDistanceTo(rpos, fromRegionPos); + if (dis > dis2) + dis = dis2; + } // Disabled for now since all osNpc* methods check for appropriate ownership permission. // Perhaps could be re-enabled as an NPC setting at some point since being able to make NPCs not @@ -688,7 +706,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); AddSenseRepeater(ts); - + idx += 6; } } @@ -704,6 +722,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins } return retList; - } + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs index 0b14565..cae1c14 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs @@ -123,25 +123,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins if (Timers.Count == 0) return; + Dictionary tvals; lock (TimerListLock) { // Go through all timers - Dictionary.ValueCollection tvals = Timers.Values; - foreach (TimerInfo ts in tvals) + tvals = new Dictionary(Timers); + } + + foreach (TimerInfo ts in tvals.Values) + { + // Time has passed? + if (ts.next < DateTime.Now.Ticks) { - // Time has passed? - if (ts.next < DateTime.Now.Ticks) - { - //m_log.Debug("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next); - // Add it to queue - m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, - new EventParams("timer", new Object[0], - new DetectParams[0])); - // set next interval - - //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); - ts.next = DateTime.Now.Ticks + ts.interval; - } + //m_log.Debug("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next); + // Add it to queue + m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, + new EventParams("timer", new Object[0], + new DetectParams[0])); + // set next interval + + //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); + ts.next = DateTime.Now.Ticks + ts.interval; } } } @@ -198,6 +200,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins } return retList; - } + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs index 215c087..e6676b4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Region.ScriptEngine.Shared.Api")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,9 +25,9 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -[assembly: AssemblyVersion("0.8.3.*")] +[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs new file mode 100644 index 0000000..ab215f3 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs @@ -0,0 +1,46 @@ +/* + * 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.Collections; +using OpenSim.Region.ScriptEngine.Interfaces; + +using key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; +using rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; +using vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; +using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; + +namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces +{ + public interface ICM_Api + { + string cmDetectedCountry(int num); + string cmGetAgentCountry(key key); + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index 3d58573..17c977f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -116,6 +116,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llGetAnimation(string id); LSL_List llGetAnimationList(string id); LSL_Integer llGetAttached(); + LSL_List llGetAttachedList(string id); LSL_List llGetBoundingBox(string obj); LSL_Vector llGetCameraPos(); LSL_Rotation llGetCameraRot(); @@ -127,6 +128,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llGetEnv(LSL_String name); LSL_Vector llGetForce(); LSL_Integer llGetFreeMemory(); + LSL_Integer llGetUsedMemory(); LSL_Integer llGetFreeURLs(); LSL_Vector llGetGeometricCenter(); LSL_Float llGetGMTclock(); @@ -204,12 +206,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llGetTimestamp(); LSL_Vector llGetTorque(); LSL_Integer llGetUnixTime(); - LSL_Integer llGetUsedMemory(); LSL_Vector llGetVel(); LSL_Float llGetWallclock(); void llGiveInventory(string destination, string inventory); void llGiveInventoryList(string destination, string category, LSL_List inventory); - void llGiveMoney(string destination, int amount); + LSL_Integer llGiveMoney(string destination, int amount); LSL_String llTransferLindenDollars(string destination, int amount); void llGodLikeRezObject(string inventory, LSL_Vector pos); LSL_Float llGround(LSL_Vector offset); @@ -325,6 +326,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Integer llRound(double f); LSL_Integer llSameGroup(string agent); void llSay(int channelID, string text); + LSL_Integer llScaleByFactor(double scaling_factor); + LSL_Float llGetMaxScaleFactor(); + LSL_Float llGetMinScaleFactor(); void llScaleTexture(double u, double v, int face); LSL_Integer llScriptDanger(LSL_Vector pos); void llScriptProfiler(LSL_Integer flag); @@ -344,7 +348,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void llSetDamage(double damage); void llSetForce(LSL_Vector force, int local); void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local); - void llSetVelocity(LSL_Vector velocity, int local); + void llSetVelocity(LSL_Vector vel, int local); void llSetAngularVelocity(LSL_Vector angularVelocity, int local); void llSetHoverHeight(double height, int water, double tau); void llSetInventoryPermMask(string item, int mask, int value); @@ -362,11 +366,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void llSetParcelMusicURL(string url); void llSetPayPrice(int price, LSL_List quick_pay_buttons); void llSetPos(LSL_Vector pos); + LSL_Integer llSetRegionPos(LSL_Vector pos); LSL_Integer llSetPrimMediaParams(LSL_Integer face, LSL_List rules); void llSetPrimitiveParams(LSL_List rules); void llSetLinkPrimitiveParamsFast(int linknum, LSL_List rules); void llSetPrimURL(string url); - LSL_Integer llSetRegionPos(LSL_Vector pos); void llSetRemoteScriptAccessPin(int pin); void llSetRot(LSL_Rotation rot); void llSetScale(LSL_Vector scale); @@ -429,10 +433,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Vector llWind(LSL_Vector offset); LSL_String llXorBase64Strings(string str1, string str2); LSL_String llXorBase64StringsCorrect(string str1, string str2); - void print(string str); + LSL_Integer llGetLinkNumberOfSides(LSL_Integer link); + void llSetPhysicsMaterial(int material_bits, LSL_Float material_gravity_modifier, LSL_Float material_restitution, LSL_Float material_friction, LSL_Float material_density); void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc); void llSetKeyframedMotion(LSL_List frames, LSL_List options); LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); + LSL_List llGetPhysicsMaterial(); + void llSetAnimationOverride(LSL_String animState, LSL_String anim); + void llResetAnimationOverride(LSL_String anim_state); + LSL_String llGetAnimationOverride(LSL_String anim_state); + LSL_String llJsonGetValue(LSL_String json, LSL_List specifiers); + LSL_List llJson2List(LSL_String json); + LSL_String llList2Json(LSL_String type, LSL_List values); + LSL_String llJsonSetValue(LSL_String json, LSL_List specifiers, LSL_String value); + LSL_String llJsonValueType(LSL_String json, LSL_List specifiers); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IMOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IMOD_Api.cs index aa78aaa..7c518f3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IMOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IMOD_Api.cs @@ -49,7 +49,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Vector modInvokeV(string fname, params object[] parms); LSL_Rotation modInvokeR(string fname, params object[] parms); LSL_List modInvokeL(string fname, params object[] parms); - + //Module functions string modSendCommand(string modules, string command, string k); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 82fdc53..ffb7ded 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -38,6 +38,7 @@ using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; + namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces { /// @@ -50,11 +51,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces /// public enum ThreatLevel { - // Not documented, presumably means permanently disabled ? NoAccess = -1, /// - /// Function is no threat at all. It doesn't constitute a threat to + /// Function is no threat at all. It doesn't constitute a threat to /// either users or the system and has no known side effects. /// None = 0, @@ -66,7 +66,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces Nuisance = 1, /// - /// Extreme levels of abuse of this function can cause impaired + /// Extreme levels of abuse of this function can cause impaired /// functioning of the region, or very gullible users can be tricked /// into experiencing harmless effects. /// @@ -81,7 +81,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces /// /// Intentional abuse can cause denial of service and crashes with - /// potential of data or state loss; or trusting users can be tricked + /// potential of data or state loss; or trusting users can be tricked /// into embarrassing or uncomfortable situations. /// Moderate = 4, @@ -114,7 +114,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces public interface IOSSL_Api { - bool CheckThreatLevel(ThreatLevel level, string function); + void CheckThreatLevel(ThreatLevel level, string function); //OpenSim functions string osSetDynamicTextureURL(string dynamicID, string contentType, string url, string extraParams, int timer); @@ -123,6 +123,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces string osSetDynamicTextureURLBlendFace(string dynamicID, string contentType, string url, string extraParams, bool blend, int disp, int timer, int alpha, int face); string osSetDynamicTextureData(string dynamicID, string contentType, string data, string extraParams, int timer); + string osSetDynamicTextureDataFace(string dynamicID, string contentType, string data, string extraParams, int timer, int face); string osSetDynamicTextureDataBlend(string dynamicID, string contentType, string data, string extraParams, int timer, int alpha); string osSetDynamicTextureDataBlendFace(string dynamicID, string contentType, string data, string extraParams, @@ -135,6 +136,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void osTerrainFlush(); int osRegionRestart(double seconds); + int osRegionRestart(double seconds, string msg); void osRegionNotice(string msg); bool osConsoleCommand(string Command); void osSetParcelMediaURL(string url); @@ -142,8 +144,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void osSetParcelSIPAddress(string SIPAddress); // Avatar Info Commands - string osGetAgentIP(string agent); LSL_List osGetAgents(); + string osGetAgentIP(string agent); // Teleport commands void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); @@ -221,10 +223,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces string osDrawLine(string drawList, int endX, int endY); string osDrawText(string drawList, string text); string osDrawEllipse(string drawList, int width, int height); + string osDrawFilledEllipse(string drawList, int width, int height); string osDrawRectangle(string drawList, int width, int height); string osDrawFilledRectangle(string drawList, int width, int height); string osDrawPolygon(string drawList, LSL_List x, LSL_List y); string osDrawFilledPolygon(string drawList, LSL_List x, LSL_List y); + string osDrawResetTransform(string drawList); + string osDrawRotationTransform(string drawList, LSL_Float x); + string osDrawScaleTransform(string drawList, LSL_Float x, LSL_Float y); + string osDrawTranslationTransform(string drawList, LSL_Float x, LSL_Float y); string osSetFontName(string drawList, string fontName); string osSetFontSize(string drawList, int fontSize); string osSetPenSize(string drawList, int penSize); @@ -261,6 +268,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces string osGetSimulatorVersion(); LSL_Integer osCheckODE(); string osGetPhysicsEngineType(); + string osGetPhysicsEngineName(); Object osParseJSONNew(string JSON); Hashtable osParseJSON(string JSON); @@ -315,6 +323,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void osForceBreakAllLinks(); /// + /// Similar to llDie but given an object UUID + /// + /// + + void osDie(LSL_Key objectUUID); + + /// /// Check if the given key is an npc /// /// @@ -341,6 +356,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces rotation osNpcGetRot(key npc); void osNpcSetRot(LSL_Key npc, rotation rot); void osNpcStopMoveToTarget(LSL_Key npc); + void osNpcSetProfileAbout(LSL_Key npc, string about); + void osNpcSetProfileImage(LSL_Key npc, string image); void osNpcSay(key npc, string message); void osNpcSay(key npc, int channel, string message); void osNpcShout(key npc, int channel, string message); @@ -362,10 +379,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces vector osGetRegionSize(); int osGetSimulatorMemory(); + int osGetSimulatorMemoryKB(); void osKickAvatar(string FirstName,string SurName,string alert); void osSetSpeed(string UUID, LSL_Float SpeedModifier); LSL_Float osGetHealth(string avatar); void osCauseHealing(string avatar, double healing); + void osSetHealth(string avatar, double health); + void osSetHealRate(string avatar, double health); + LSL_Float osGetHealRate(string avatar); void osCauseDamage(string avatar, double damage); void osForceOtherSit(string avatar); void osForceOtherSit(string avatar, string target); @@ -375,6 +396,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void osSetProjectionParams(LSL_Key prim, bool projection, LSL_Key texture, double fov, double focus, double amb); LSL_List osGetAvatarList(); + LSL_List osGetNPCList(); LSL_String osUnixTimeToTimestamp(long time); @@ -468,5 +490,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces /// string to use as pattern /// boolean LSL_Integer osRegexIsMatch(string input, string pattern); + + LSL_String osRequestURL(LSL_List options); + LSL_String osRequestSecureURL(LSL_List options); + void osCollisionSound(string impact_sound, double impact_volume); + + void osVolumeDetect(int detect); + + LSL_List osGetInertiaData(); + void osClearInertia(); + void osSetInertia(LSL_Float mass, vector centerOfMass, vector principalInertiaScaled, rotation rot); + void osSetInertiaAsBox(LSL_Float mass, vector boxSize, vector centerOfMass, rotation rot); + void osSetInertiaAsSphere(LSL_Float mass, LSL_Float radius, vector centerOfMass); + void osSetInertiaAsCylinder(LSL_Float mass, LSL_Float radius, LSL_Float lenght, vector centerOfMass,rotation lslrot); + + LSL_Integer osTeleportObject(LSL_Key objectUUID, vector targetPos, rotation targetrotation, LSL_Integer flags); + LSL_Integer osGetLinkNumber(LSL_String name); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs new file mode 100644 index 0000000..4132dfa --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs @@ -0,0 +1,71 @@ +/* + * 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.Runtime.Remoting.Lifetime; +using System.Threading; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.Interfaces; +using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces; +using integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; +using rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; +using key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; +using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; +using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; + +namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase +{ + public partial class ScriptBaseClass : MarshalByRefObject + { + public ICM_Api m_CM_Functions; + + public void ApiTypeCM(IScriptApi api) + { + if (!(api is ICM_Api)) + return; + + m_CM_Functions = (ICM_Api)api; + } + + public string cmDetectedCountry(int num) + { + return m_CM_Functions.cmDetectedCountry(num); + } + + public string cmGetAgentCountry(key key) + { + return m_CM_Functions.cmGetAgentCountry(key); + } + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs index ce17ed0..1cc2cfb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; //for [DebuggerNonUserCode] using System.Reflection; using System.Runtime.Remoting.Lifetime; using OpenSim.Region.ScriptEngine.Shared; @@ -133,6 +134,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return (eventFlags); } + [DebuggerNonUserCode] public void ExecuteEvent(string state, string FunctionName, object[] args) { // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 9aecea2..2f249a7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -29,6 +29,7 @@ using System; using vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; using LSLInteger = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSLString = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { @@ -57,7 +58,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int ACTIVE = 2; public const int PASSIVE = 4; public const int SCRIPTED = 8; - public const int OS_NPC = 0x01000000; public const int CONTROL_FWD = 1; public const int CONTROL_BACK = 2; @@ -82,6 +82,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PERMISSION_CHANGE_PERMISSIONS = 512; public const int PERMISSION_TRACK_CAMERA = 1024; public const int PERMISSION_CONTROL_CAMERA = 2048; + public const int PERMISSION_TELEPORT = 4096; + public const int PERMISSION_OVERRIDE_ANIMATIONS = 0x8000; public const int AGENT_FLYING = 1; public const int AGENT_ATTACHMENTS = 2; @@ -96,6 +98,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int AGENT_CROUCHING = 1024; public const int AGENT_BUSY = 2048; public const int AGENT_ALWAYS_RUN = 4096; + public const int AGENT_MALE = 8192; //Particle Systems public const int PSYS_PART_INTERP_COLOR_MASK = 1; @@ -252,6 +255,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int ATTACH_HUD_BOTTOM_RIGHT = 38; public const int ATTACH_NECK = 39; public const int ATTACH_AVATAR_CENTER = 40; + public const int ATTACH_LHAND_RING1 = 41; + public const int ATTACH_RHAND_RING1 = 42; + public const int ATTACH_TAIL_BASE = 43; + public const int ATTACH_TAIL_TIP = 44; + public const int ATTACH_LWING = 45; + public const int ATTACH_RWING = 46; + public const int ATTACH_FACE_JAW = 47; + public const int ATTACH_FACE_LEAR = 48; + public const int ATTACH_FACE_REAR = 49; + public const int ATTACH_FACE_LEYE = 50; + public const int ATTACH_FACE_REYE = 51; + public const int ATTACH_FACE_TONGUE = 52; + public const int ATTACH_GROIN = 53; + public const int ATTACH_HIND_LFOOT = 54; + public const int ATTACH_HIND_RFOOT = 55; #region osMessageAttachments constants @@ -334,11 +352,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int ROTATE = 32; public const int SCALE = 64; public const int ALL_SIDES = -1; + + // LINK flags public const int LINK_SET = -1; public const int LINK_ROOT = 1; public const int LINK_ALL_OTHERS = -2; public const int LINK_ALL_CHILDREN = -3; public const int LINK_THIS = -4; + public const int CHANGED_INVENTORY = 1; public const int CHANGED_COLOR = 2; public const int CHANGED_SHAPE = 4; @@ -353,6 +374,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART public const int CHANGED_MEDIA = 2048; public const int CHANGED_ANIMATION = 16384; + public const int CHANGED_POSITION = 32768; + public const int TYPE_INVALID = 0; public const int TYPE_INTEGER = 1; public const int TYPE_FLOAT = 2; @@ -386,6 +409,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int CONTENT_TYPE_FORM = 7; //application/x-www-form-urlencoded public const int CONTENT_TYPE_RSS = 8; //application/rss+xml + //parameters comand flags public const int PRIM_MATERIAL = 2; public const int PRIM_PHYSICS = 3; public const int PRIM_TEMP_ON_REZ = 4; @@ -394,19 +418,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_SIZE = 7; public const int PRIM_ROTATION = 8; public const int PRIM_TYPE = 9; + // gap 10-16 public const int PRIM_TEXTURE = 17; public const int PRIM_COLOR = 18; public const int PRIM_BUMP_SHINY = 19; public const int PRIM_FULLBRIGHT = 20; public const int PRIM_FLEXIBLE = 21; public const int PRIM_TEXGEN = 22; - public const int PRIM_CAST_SHADOWS = 24; // Not implemented, here for completeness sake public const int PRIM_POINT_LIGHT = 23; // Huh? + public const int PRIM_CAST_SHADOWS = 24; // Not implemented, here for completeness sake public const int PRIM_GLOW = 25; public const int PRIM_TEXT = 26; public const int PRIM_NAME = 27; public const int PRIM_DESC = 28; public const int PRIM_ROT_LOCAL = 29; + public const int PRIM_PHYSICS_SHAPE_TYPE = 30; + public const int PRIM_PHYSICS_MATERIAL = 31; // apparently not on SL wiki public const int PRIM_OMEGA = 32; public const int PRIM_POS_LOCAL = 33; public const int PRIM_LINK_TARGET = 34; @@ -414,6 +441,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_SPECULAR = 36; public const int PRIM_NORMAL = 37; public const int PRIM_ALPHA_MODE = 38; + public const int PRIM_ALLOW_UNSIT = 39; // experiences related. unsupported + public const int PRIM_SCRIPTED_SIT_ONLY = 40; // experiences related. unsupported + public const int PRIM_SIT_TARGET = 41; + + + // parameters public const int PRIM_TEXGEN_DEFAULT = 0; public const int PRIM_TEXGEN_PLANAR = 1; @@ -470,6 +503,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_SCULPT_FLAG_INVERT = 64; public const int PRIM_SCULPT_FLAG_MIRROR = 128; + public const int PRIM_PHYSICS_SHAPE_PRIM = 0; + public const int PRIM_PHYSICS_SHAPE_NONE = 1; + public const int PRIM_PHYSICS_SHAPE_CONVEX = 2; + public const int PROFILE_NONE = 0; public const int PROFILE_SCRIPT_MEMORY = 1; @@ -600,6 +637,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_HOVER_HEIGHT = 25; public const int OBJECT_BODY_SHAPE_TYPE = 26; public const int OBJECT_LAST_OWNER_ID = 27; + public const int OBJECT_CLICK_ACTION = 28; + public const int OBJECT_OMEGA = 29; + public const int OBJECT_PRIM_COUNT = 30; + public const int OBJECT_TOTAL_INVENTORY_COUNT = 31; + public const int OBJECT_REZZER_KEY = 32; + public const int OBJECT_GROUP_TAG = 33; + public const int OBJECT_TEMP_ATTACHED = 34; + public const int OBJECT_ATTACHED_SLOTS_AVAILABLE = 35; // Pathfinding types public const int OPT_OTHER = -1; @@ -615,6 +660,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int AGENT_LIST_PARCEL = 1; public const int AGENT_LIST_PARCEL_OWNER = 2; public const int AGENT_LIST_REGION = 4; + public const int AGENT_LIST_EXCLUDENPC = 0x4000000; // our flag, not SL and it is a bit mask // Can not be public const? public static readonly vector ZERO_VECTOR = new vector(0.0, 0.0, 0.0); @@ -652,7 +698,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PARCEL_DETAILS_GROUP = 3; public const int PARCEL_DETAILS_AREA = 4; public const int PARCEL_DETAILS_ID = 5; - public const int PARCEL_DETAILS_SEE_AVATARS = 6; // not implemented + public const int PARCEL_DETAILS_SEE_AVATARS = 6; + public const int PARCEL_DETAILS_ANY_AVATAR_SOUNDS = 7; + public const int PARCEL_DETAILS_GROUP_SOUNDS = 8; //osSetParcelDetails public const int PARCEL_DETAILS_CLAIMDATE = 10; @@ -698,12 +746,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_MEDIA_PERM_GROUP = 2; public const int PRIM_MEDIA_PERM_ANYONE = 4; - public const int PRIM_PHYSICS_SHAPE_TYPE = 30; - public const int PRIM_PHYSICS_SHAPE_PRIM = 0; - public const int PRIM_PHYSICS_SHAPE_CONVEX = 2; - public const int PRIM_PHYSICS_SHAPE_NONE = 1; - - public const int PRIM_PHYSICS_MATERIAL = 31; public const int DENSITY = 1; public const int FRICTION = 2; public const int RESTITUTION = 4; @@ -760,6 +802,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OS_NPC_CREATOR_OWNED = 0x1; public const int OS_NPC_NOT_OWNED = 0x2; public const int OS_NPC_SENSE_AS_AGENT = 0x4; + public const int OS_NPC_OBJECT_GROUP = 0x08; public const string URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED"; public const string URL_REQUEST_DENIED = "URL_REQUEST_DENIED"; @@ -795,6 +838,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int KFM_CMD_STOP = 1; public const int KFM_CMD_PAUSE = 2; + public const string JSON_INVALID = "\uFDD0"; + public const string JSON_OBJECT = "\uFDD1"; + public const string JSON_ARRAY = "\uFDD2"; + public const string JSON_NUMBER = "\uFDD3"; + public const string JSON_STRING = "\uFDD4"; + public const string JSON_NULL = "\uFDD5"; + public const string JSON_TRUE = "\uFDD6"; + public const string JSON_FALSE = "\uFDD7"; + public const string JSON_DELETE = "\uFDD8"; + public const string JSON_APPEND = "-1"; + /// /// process name parameter as regex /// @@ -804,5 +858,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase /// process message parameter as regex /// public const int OS_LISTEN_REGEX_MESSAGE = 0x2; + + // for osTeleportObject + public const int OSTPOBJ_NONE = 0x0; + public const int OSTPOBJ_STOPATTARGET = 0x1; // stops at destination + public const int OSTPOBJ_STOPONFAIL = 0x2; // stops at jump point if tp fails + public const int OSTPOBJ_SETROT = 0x4; // the rotation is the final rotation, otherwise is a added rotation + } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 35aaf01..c39248b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -26,6 +26,7 @@ */ using System; +using System.Diagnostics; //for [DebuggerNonUserCode] using System.Runtime.Remoting.Lifetime; using System.Threading; using System.Reflection; @@ -314,6 +315,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llDialog(avatar, message, buttons, chat_channel); } + [DebuggerNonUserCode] public void llDie() { m_LSL_Functions.llDie(); @@ -424,6 +426,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetAttached(); } + public LSL_List llGetAttachedList(string id) + { + return m_LSL_Functions.llGetAttachedList(id); + } + public LSL_List llGetBoundingBox(string obj) { return m_LSL_Functions.llGetBoundingBox(obj); @@ -479,6 +486,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetFreeMemory(); } + public LSL_Integer llGetUsedMemory() + { + return m_LSL_Functions.llGetUsedMemory(); + } + public LSL_Integer llGetFreeURLs() { return m_LSL_Functions.llGetFreeURLs(); @@ -559,11 +571,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetLinkNumberOfSides(link); } - public void llSetKeyframedMotion(LSL_List frames, LSL_List options) - { - m_LSL_Functions.llSetKeyframedMotion(frames, options); - } - public LSL_Integer llGetListEntryType(LSL_List src, int index) { return m_LSL_Functions.llGetListEntryType(src, index); @@ -859,11 +866,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetUnixTime(); } - public LSL_Integer llGetUsedMemory() - { - return m_LSL_Functions.llGetUsedMemory(); - } - public LSL_Vector llGetVel() { return m_LSL_Functions.llGetVel(); @@ -884,9 +886,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llGiveInventoryList(destination, category, inventory); } - public void llGiveMoney(string destination, int amount) + public LSL_Integer llGiveMoney(string destination, int amount) { - m_LSL_Functions.llGiveMoney(destination, amount); + return m_LSL_Functions.llGiveMoney(destination, amount); } public LSL_String llTransferLindenDollars(string destination, int amount) @@ -1463,6 +1465,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSay(channelID, text); } + public LSL_Integer llScaleByFactor(double scaling_factor) + { + return m_LSL_Functions.llScaleByFactor(scaling_factor); + } + + public LSL_Float llGetMaxScaleFactor() + { + return m_LSL_Functions.llGetMaxScaleFactor(); + } + + public LSL_Float llGetMinScaleFactor() + { + return m_LSL_Functions.llGetMinScaleFactor(); + } + public void llScaleTexture(double u, double v, int face) { m_LSL_Functions.llScaleTexture(u, v, face); @@ -1563,6 +1580,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSetVelocity(force, local); } + public void llSetAngularVelocity(LSL_Vector force, int local) { m_LSL_Functions.llSetAngularVelocity(force, local); @@ -1643,6 +1661,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSetPos(pos); } + public LSL_Integer llSetRegionPos(LSL_Vector pos) + { + return m_LSL_Functions.llSetRegionPos(pos); + } + public void llSetPrimitiveParams(LSL_List rules) { m_LSL_Functions.llSetPrimitiveParams(rules); @@ -1658,11 +1681,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSetPrimURL(url); } - public LSL_Integer llSetRegionPos(LSL_Vector pos) - { - return m_LSL_Functions.llSetRegionPos(pos); - } - public void llSetRemoteScriptAccessPin(int pin) { m_LSL_Functions.llSetRemoteScriptAccessPin(pin); @@ -1977,7 +1995,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_LSL_Functions.llXorBase64StringsCorrect(str1, str2); } - + public LSL_List llGetPrimMediaParams(int face, LSL_List rules) { return m_LSL_Functions.llGetPrimMediaParams(face, rules); @@ -2008,9 +2026,64 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llClearLinkMedia(link, face); } - public void print(string str) + public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link) + { + return m_LSL_Functions.llGetLinkNumberOfSides(link); + } + + public void llSetKeyframedMotion(LSL_List frames, LSL_List options) + { + m_LSL_Functions.llSetKeyframedMotion(frames, options); + } + + public void llSetPhysicsMaterial(int material_bits, LSL_Float material_gravity_modifier, LSL_Float material_restitution, LSL_Float material_friction, LSL_Float material_density) + { + m_LSL_Functions.llSetPhysicsMaterial(material_bits, material_gravity_modifier, material_restitution, material_friction, material_density); + } + + public LSL_List llGetPhysicsMaterial() + { + return m_LSL_Functions.llGetPhysicsMaterial(); + } + + public void llSetAnimationOverride(LSL_String animState, LSL_String anim) + { + m_LSL_Functions.llSetAnimationOverride(animState, anim); + } + + public void llResetAnimationOverride(LSL_String anim_state) + { + m_LSL_Functions.llResetAnimationOverride(anim_state); + } + + public LSL_String llGetAnimationOverride(LSL_String anim_state) + { + return m_LSL_Functions.llGetAnimationOverride(anim_state); + } + + public LSL_String llJsonGetValue(LSL_String json, LSL_List specifiers) + { + return m_LSL_Functions.llJsonGetValue(json, specifiers); + } + + public LSL_List llJson2List(LSL_String json) + { + return m_LSL_Functions.llJson2List(json); + } + + public LSL_String llList2Json(LSL_String type, LSL_List values) + { + return m_LSL_Functions.llList2Json(type, values); + } + + public LSL_String llJsonSetValue(LSL_String json, LSL_List specifiers, LSL_String value) + { + return m_LSL_Functions.llJsonSetValue(json, specifiers, value); + } + + public LSL_String llJsonValueType(LSL_String json, LSL_List specifiers) { - m_LSL_Functions.print(str); + return m_LSL_Functions.llJsonValueType(json, specifiers); } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs index 143b497..2e27f16 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs @@ -72,9 +72,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_LS_Functions.lsSetWindlightSceneTargeted(rules, target); } + public void lsClearWindlightScene() { m_LS_Functions.lsClearWindlightScene(); } + + public LSL_List cmGetWindlightScene(LSL_List rules) + { + return m_LS_Functions.lsGetWindlightScene(rules); + } + + public int cmSetWindlightScene(LSL_List rules) + { + return m_LS_Functions.lsSetWindlightScene(rules); + } + + public int cmSetWindlightSceneTargeted(LSL_List rules, key target) + { + return m_LS_Functions.lsSetWindlightSceneTargeted(rules, target); + } + + public void cmClearWindlightScene() + { + m_LS_Functions.lsClearWindlightScene(); + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index a60f381..30ff764 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -153,6 +153,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osSetDynamicTextureData(dynamicID, contentType, data, extraParams, timer); } + public string osSetDynamicTextureDataFace(string dynamicID, string contentType, string data, string extraParams, + int timer, int face) + { + return m_OSSL_Functions.osSetDynamicTextureDataFace(dynamicID, contentType, data, extraParams, timer, face); + } + public string osSetDynamicTextureURLBlend(string dynamicID, string contentType, string url, string extraParams, int timer, int alpha) { @@ -209,6 +215,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osRegionRestart(seconds); } + public int osRegionRestart(double seconds, string msg) + { + return m_OSSL_Functions.osRegionRestart(seconds, msg); + } + public void osRegionNotice(string msg) { m_OSSL_Functions.osRegionNotice(msg); @@ -266,15 +277,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osTeleportOwner(position, lookat); } - // Avatar info functions - public string osGetAgentIP(string agent) + public LSL_List osGetAgents() { - return m_OSSL_Functions.osGetAgentIP(agent); + return m_OSSL_Functions.osGetAgents(); } - public LSL_List osGetAgents() + public string osGetAgentIP(string agent) { - return m_OSSL_Functions.osGetAgents(); + return m_OSSL_Functions.osGetAgentIP(agent); } // Animation Functions @@ -350,6 +360,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osDrawEllipse(drawList, width, height); } + public string osDrawFilledEllipse(string drawList, int width, int height) + { + return m_OSSL_Functions.osDrawFilledEllipse(drawList, width, height); + } + public string osDrawRectangle(string drawList, int width, int height) { return m_OSSL_Functions.osDrawRectangle(drawList, width, height); @@ -370,6 +385,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osDrawFilledPolygon(drawList, x, y); } + public string osDrawResetTransform(string drawList) + { + return m_OSSL_Functions.osDrawResetTransform(drawList); + } + + public string osDrawRotationTransform(string drawList, LSL_Float x) + { + return m_OSSL_Functions.osDrawRotationTransform(drawList, x); + } + + public string osDrawScaleTransform(string drawList, LSL_Float x, LSL_Float y) + { + return m_OSSL_Functions.osDrawScaleTransform(drawList, x, y); + } + + public string osDrawTranslationTransform(string drawList, LSL_Float x, LSL_Float y) + { + return m_OSSL_Functions.osDrawTranslationTransform(drawList, x, y); + } + public string osSetFontSize(string drawList, int fontSize) { return m_OSSL_Functions.osSetFontSize(drawList, fontSize); @@ -394,6 +429,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osSetPenColor(drawList, color); } + // Deprecated public string osSetPenColour(string drawList, string colour) { @@ -430,6 +466,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osGetPhysicsEngineType(); } + public string osGetPhysicsEngineName() + { + return m_OSSL_Functions.osGetPhysicsEngineName(); + } + public string osGetSimulatorVersion() { return m_OSSL_Functions.osGetSimulatorVersion(); @@ -439,7 +480,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osParseJSON(JSON); } - + public Object osParseJSONNew(string JSON) { return m_OSSL_Functions.osParseJSONNew(JSON); @@ -529,7 +570,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osReplaceString(src,pattern,replace,count,start); } - + // Information about data loaded into the region public string osLoadedCreationDate() @@ -567,6 +608,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osForceBreakAllLinks(); } + public void osDie(LSL_Key objectUUID) + { + m_OSSL_Functions.osDie(objectUUID); + } + public LSL_Integer osIsNpc(LSL_Key npc) { return m_OSSL_Functions.osIsNpc(npc); @@ -627,6 +673,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osNpcStopMoveToTarget(npc); } + public void osNpcSetProfileAbout(LSL_Key npc, string about) + { + m_OSSL_Functions.osNpcSetProfileAbout(npc, about); + } + + public void osNpcSetProfileImage(LSL_Key npc, string image) + { + m_OSSL_Functions.osNpcSetProfileImage(npc, image); + } + public void osNpcSay(key npc, string message) { m_OSSL_Functions.osNpcSay(npc, message); @@ -744,14 +800,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase if (Position.y > ((int)Constants.RegionSize - 1)) Position.y = ((int)Constants.RegionSize - 1); */ - if (Position.z > Constants.RegionHeight) - Position.z = Constants.RegionHeight; if (Position.x < 0) Position.x = 0; if (Position.y < 0) Position.y = 0; if (Position.z < 0) Position.z = 0; + if (Position.z > Constants.RegionHeight) + Position.z = Constants.RegionHeight; prim.OSSL.llSetPos(Position); } @@ -889,7 +945,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osGetRegionMapTexture(regionName); } - + public LSL_List osGetRegionStats() { return m_OSSL_Functions.osGetRegionStats(); @@ -902,19 +958,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase /// /// Returns the amount of memory in use by the Simulator Daemon. - /// Amount in bytes - if >= 4GB, returns 4GB. (LSL is not 64-bit aware) + /// Amount in bytes - if >= 2GB, returns 2GB. (LSL is not 64-bit aware) /// /// public LSL_Integer osGetSimulatorMemory() { return m_OSSL_Functions.osGetSimulatorMemory(); } - + + public LSL_Integer osGetSimulatorMemoryKB() + { + return m_OSSL_Functions.osGetSimulatorMemoryKB(); + } + public void osKickAvatar(string FirstName,string SurName,string alert) { m_OSSL_Functions.osKickAvatar(FirstName, SurName, alert); } - + public void osSetSpeed(string UUID, LSL_Float SpeedModifier) { m_OSSL_Functions.osSetSpeed(UUID, SpeedModifier); @@ -929,12 +990,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { m_OSSL_Functions.osCauseDamage(avatar, damage); } - + public void osCauseHealing(string avatar, double healing) { m_OSSL_Functions.osCauseHealing(avatar, healing); } + public void osSetHealth(string avatar, double health) + { + m_OSSL_Functions.osSetHealth(avatar, health); + } + + public void osSetHealRate(string avatar, double health) + { + m_OSSL_Functions.osSetHealRate(avatar, health); + } + + public LSL_Float osGetHealRate(string avatar) + { + return m_OSSL_Functions.osGetHealRate(avatar); + } + public void osForceOtherSit(string avatar) { m_OSSL_Functions.osForceOtherSit(avatar); @@ -944,12 +1020,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { m_OSSL_Functions.osForceOtherSit(avatar, target); } - + public LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules) { return m_OSSL_Functions.osGetPrimitiveParams(prim, rules); } - + public void osSetPrimitiveParams(LSL_Key prim, LSL_List rules) { m_OSSL_Functions.osSetPrimitiveParams(prim, rules); @@ -970,6 +1046,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osGetAvatarList(); } + public LSL_List osGetNPCList() + { + return m_OSSL_Functions.osGetNPCList(); + } + public LSL_String osUnixTimeToTimestamp(long time) { return m_OSSL_Functions.osUnixTimeToTimestamp(time); @@ -1054,5 +1135,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osRegexIsMatch(input, pattern); } + + public LSL_String osRequestURL(LSL_List options) + { + return m_OSSL_Functions.osRequestURL(options); + } + + public LSL_String osRequestSecureURL(LSL_List options) + { + return m_OSSL_Functions.osRequestSecureURL(options); + } + + public void osCollisionSound(string impact_sound, double impact_volume) + { + m_OSSL_Functions.osCollisionSound(impact_sound, impact_volume); + } + + public void osVolumeDetect(int detect) + { + m_OSSL_Functions.osVolumeDetect(detect); + } + + public LSL_List osGetInertiaData() + { + return m_OSSL_Functions.osGetInertiaData(); + } + + public void osSetInertia(LSL_Float mass, vector centerOfMass, vector principalInertiaScaled, rotation rot) + { + m_OSSL_Functions.osSetInertia(mass, centerOfMass, principalInertiaScaled, rot); + } + + public void osSetInertiaAsBox(LSL_Float mass, vector boxSize, vector centerOfMass, rotation rot) + { + m_OSSL_Functions.osSetInertiaAsBox(mass, boxSize, centerOfMass, rot); + } + + public void osSetInertiaAsSphere(LSL_Float mass, LSL_Float radius, vector centerOfMass) + { + m_OSSL_Functions.osSetInertiaAsSphere(mass, radius, centerOfMass); + } + + public void osSetInertiaAsCylinder(LSL_Float mass, LSL_Float radius, LSL_Float lenght, vector centerOfMass,rotation lslrot) + { + m_OSSL_Functions.osSetInertiaAsCylinder( mass, radius, lenght, centerOfMass, lslrot); + } + + public void osClearInertia() + { + m_OSSL_Functions.osClearInertia(); + } + + public LSL_Integer osTeleportObject(LSL_Key objectUUID, vector targetPos, rotation targetrotation, LSL_Integer flags) + { + return m_OSSL_Functions.osTeleportObject(objectUUID, targetPos, targetrotation, flags); + } + + public LSL_Integer osGetLinkNumber(LSL_String name) + { + return m_OSSL_Functions.osGetLinkNumber(name); + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OpenSim.Region.ScriptEngine.Shared.Api.Runtime.mdp b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OpenSim.Region.ScriptEngine.Shared.Api.Runtime.mdp deleted file mode 100644 index f02d2d9..0000000 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OpenSim.Region.ScriptEngine.Shared.Api.Runtime.mdp +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs index b1825ac..81020f1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Region.ScriptEngine.Shared.Api.Runtime")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs index edbbc2a..b138da3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs @@ -33,6 +33,7 @@ using System.Threading; using System.Reflection; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; //for [DebuggerNonUserCode] using OpenSim.Region.ScriptEngine.Interfaces; using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api.Runtime; @@ -90,6 +91,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return (int)m_Executor.GetStateEventFlags(state); } + [DebuggerNonUserCode] public void ExecuteEvent(string state, string FunctionName, object[] args) { m_Executor.ExecuteEvent(state, FunctionName, args); -- cgit v1.1