From dba37a8722a375c77a31efa03c12c146126898d3 Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Mon, 17 Mar 2008 15:11:36 +0000 Subject: From: Alan M Webb Here's a diff of the changes I have made in support of the following LSL script functions. llSetScriptState llGetScriptState llCSV2List llListRandomize llList2ListStrided llListFindList llResetOtherScript llGetScriptName It was necessary to modify ExecutorBase in support of the ScriptState implementations. I also modified SceneObjectPart and SceneObjectPart.Inventory to corrects a quoting mismatch in the commentary that through off live parsing of the files. I also simplified the State definition at the start of BuiltinCommands. --- .../Common/BuiltIn_Commands_BaseClass.cs | 9 +- OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs | 21 + .../ScriptEngine/Common/LSL_BuiltIn_Commands.cs | 430 ++++++++++++++++----- 3 files changed, 370 insertions(+), 90 deletions(-) (limited to 'OpenSim/Region/ScriptEngine') diff --git a/OpenSim/Region/ScriptEngine/Common/BuiltIn_Commands_BaseClass.cs b/OpenSim/Region/ScriptEngine/Common/BuiltIn_Commands_BaseClass.cs index 957f55c..9e30958 100644 --- a/OpenSim/Region/ScriptEngine/Common/BuiltIn_Commands_BaseClass.cs +++ b/OpenSim/Region/ScriptEngine/Common/BuiltIn_Commands_BaseClass.cs @@ -2310,9 +2310,9 @@ namespace OpenSim.Region.ScriptEngine.Common public const double DEG_TO_RAD = 0.01745329238f; public const double RAD_TO_DEG = 57.29578f; public const double SQRT2 = 1.414213538f; - public const int STRING_TRIM_HEAD = 1; - public const int STRING_TRIM_TAIL = 2; - public const int STRING_TRIM = 3; + public const int STRING_TRIM_HEAD = 1; + public const int STRING_TRIM_TAIL = 2; + public const int STRING_TRIM = 3; public const int LIST_STAT_RANGE = 0; public const int LIST_STAT_MIN = 1; public const int LIST_STAT_MAX = 2; @@ -2333,6 +2333,9 @@ namespace OpenSim.Region.ScriptEngine.Common public const int PARCEL_COUNT_SELECTED = 4; public const int PARCEL_COUNT_TEMP = 5; + public const int DEBUG_CHANNEL = 0x7FFFFFFF; + public const int PUBLIC_CHANNEL = 0x00000000; + // Can not be public const? public vector ZERO_VECTOR = new vector(0.0, 0.0, 0.0); public rotation ZERO_ROTATION = new rotation(0.0, 0, 0.0, 1.0); diff --git a/OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs b/OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs index 30c40f4..c272400 100644 --- a/OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs +++ b/OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs @@ -42,6 +42,25 @@ namespace OpenSim.Region.ScriptEngine.Common /// If set to False events will not be executed. /// protected bool m_Running = true; + /// + /// True indicates that the ScriptManager has stopped + /// this script. This prevents a script that has been + /// stopped as part of deactivation from being + /// resumed by a pending llSetScriptState request. + /// + protected bool m_Disable = false; + + /// + /// Indicate the scripts current running status. + /// + public bool Running + { + get { return m_Running; } + set { + if(!m_Disable) + m_Running = value; + } + } /// /// Create a new instance of ExecutorBase @@ -102,6 +121,8 @@ namespace OpenSim.Region.ScriptEngine.Common public void StopScript() { m_Running = false; + m_Disable = true; } + } } diff --git a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs index daf5e21..58b22d9 100644 --- a/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs +++ b/OpenSim/Region/ScriptEngine/Common/LSL_BuiltIn_Commands.cs @@ -50,9 +50,9 @@ namespace OpenSim.Region.ScriptEngine.Common /// public class LSL_BuiltIn_Commands : MarshalByRefObject, LSL_BuiltIn_Commands_Interface { - //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + // private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - private ASCIIEncoding enc = new ASCIIEncoding(); + // private ASCIIEncoding enc = new ASCIIEncoding(); private ScriptEngineBase.ScriptEngine m_ScriptEngine; private SceneObjectPart m_host; private uint m_localID; @@ -76,14 +76,10 @@ namespace OpenSim.Region.ScriptEngine.Common { get { return m_state; } set { - bool changed = false; + // Set it if it changed if (m_state != value) - changed = true; - // Set it - m_state = value; - - if (changed) { + m_state = value; m_ScriptEngine.m_EventManager.state_entry(m_localID); } } @@ -1793,8 +1789,33 @@ namespace OpenSim.Region.ScriptEngine.Common public void llSetScriptState(string name, int run) { + + LLUUID item; + ScriptManager sm; + IScript script = null; + m_host.AddScriptLPS(1); - NotImplemented("llSetScriptState"); + + // These functions are supposed to be robust, + // so get the state one step at a time. + + if((item = ScriptByName(name)) != LLUUID.Zero) + if((sm = m_ScriptEngine.m_ScriptManager) != null) + if(sm.Scripts.ContainsKey(m_localID)) + if((script = sm.GetScript(m_localID, item)) != null) + script.Exec.Running = (run==0) ? false : true; + + + // Required by SL + + if(script == null) + ShoutError("llSetScriptState: script "+name+" not found"); + + // If we didn;t find it, then it's safe to + // assume it is not running. + + return; + } public double llGetEnergy() @@ -1911,9 +1932,22 @@ namespace OpenSim.Region.ScriptEngine.Common public string llGetScriptName() { + + string result = null; + m_host.AddScriptLPS(1); - return String.Empty; + foreach (TaskInventoryItem item in m_host.TaskInventory.Values) + { + if(item.Type == 10 && item.ItemID == m_itemID) + { + result = item.Name; + break; + } + } + + return result; + } public int llGetNumberOfSides() @@ -2269,81 +2303,216 @@ namespace OpenSim.Region.ScriptEngine.Common return ret; } + /// + /// The supplied string is scanned for commas + /// and converted into a list. Commas are only + /// effective if they are encountered outside + /// of '<' '>' delimiters. Any whitespace + /// before or after an element is trimmed. + /// + public LSL_Types.list llCSV2List(string src) { + + LSL_Types.list result = new LSL_Types.list(); + int parens = 0; + int start = 0; + int length = 0; + m_host.AddScriptLPS(1); - return new LSL_Types.list(src.Split(",".ToCharArray())); + + for(int i=0; i' : + if(parens > 0) + parens--; + length++; + break; + case ',' : + if(parens == 0) + { + result.Add(src.Substring(start,length).Trim()); + start += length+1; + length = 0; + } else + length++; + break; + default : + length++; + break; + } + } + + result.Add(src.Substring(start,length).Trim()); + + return result; + } + /// + /// Randomizes the list, be arbitrarily reordering + /// sublists of stride elements. As the stride approaches + /// the size of the list, the options become very + /// limited. + /// + /// + /// This could take a while for very large list + /// sizes. + /// + public LSL_Types.list llListRandomize(LSL_Types.list src, int stride) { + + LSL_Types.list result; + Random rand = new Random(); + + int chunkk; + int[] chunks; + int index1; + int index2; + int tmp; + m_host.AddScriptLPS(1); - //int s = stride; - //if (s < 1) - // s = 1; - // This is a cowardly way of doing it ;) - // TODO: Instead, randomize and check if random is mod stride or if it can not be, then array.removerange - //List tmp = new List(); + if(stride == 0) + stride = 1; - // Add chunks to an array - //int c = 0; - //LSL_Types.list chunk = new LSL_Types.list(); - //foreach (string element in src) - //{ - // c++; - // if (c > s) - // { - // tmp.Add(chunk); - // chunk = new LSL_Types.list(); - // c = 0; - // } - // chunk.Add(element); - //} - //if (chunk.Count > 0) - // tmp.Add(chunk); + // Stride MUST be a factor of the list length + // If not, then return the src list. This also + // traps those cases where stride > length. + + if(src.Length != stride && src.Length%stride == 0) + { - // Decreate (<- what kind of word is that? :D ) array back into a list - //int rnd; - //LSL_Types.list ret = new LSL_Types.list(); - //while (tmp.Count > 0) - //{ - // rnd = Util.RandomClass.Next(tmp.Count); - // foreach (string str in tmp[rnd]) - // { - // ret.Add(str); - // } - // tmp.RemoveAt(rnd); - //} + chunkk = src.Length/stride; + + chunks = new int[chunkk]; + + for(int i=0;i + /// Elements in the source list starting with 0 and then + /// every i+stride. If the stride is negative then the scan + /// is backwards producing an inverted result. + /// Only those elements that are also in the specified + /// range are included in the result. + /// + public LSL_Types.list llList2ListStrided(LSL_Types.list src, int start, int end, int stride) { + + LSL_Types.list result = new LSL_Types.list(); + int[] si = new int[2]; + int[] ei = new int[2]; + bool twopass = false; + m_host.AddScriptLPS(1); - LSL_Types.list ret = new LSL_Types.list(); - //int s = stride; - //if (s < 1) - // s = 1; - //int sc = s; - //for (int i = start; i < src.Count; i++) - //{ - // sc--; - // if (sc == 0) - // { - // sc = s; - // // Addthis - // ret.Add(src[i]); - // } - // if (i == end) - // break; - //} - NotImplemented("llList2ListStrided"); - return ret; + // First step is always to deal with negative indices + + if(start < 0) + start = src.Length+start; + if(end < 0) + end = src.Length+end; + + // Out of bounds indices are OK, just trim them + // accordingly + + if(start > src.Length) + start = src.Length; + + if(end > src.Length) + end = src.Length; + + // There may be one or two ranges to be considered + + if(start != end) + { + + if(start <= end) + { + si[0] = start; + ei[0] = end; + } + else + { + si[1] = start; + ei[1] = src.Length; + si[0] = 0; + ei[0] = end; + twopass = true; + } + + // The scan always starts from the beginning of the + // source list, but members are only selected if they + // fall within the specified sub-range. The specified + // range values are inclusive. + // A negative stride reverses the direction of the + // scan producing an inverted list as a result. + + if(stride == 0) + stride = 1; + + if(stride > 0) + for(int i=0;i=si[0]) + result.Add(src.Data[i]); + if(twopass && i>=si[1] && i<=ei[1]) + result.Add(src.Data[i]); + } + else if(stride < 0) + for(int i=src.Length-1;i>=0;i+=stride) + { + if(i<=ei[0] && i>=si[0]) + result.Add(src.Data[i]); + if(twopass && i>=si[1] && i<=ei[1]) + result.Add(src.Data[i]); + } + } + + return result; + } public LSL_Types.Vector3 llGetRegionCorner() @@ -2358,19 +2527,42 @@ namespace OpenSim.Region.ScriptEngine.Common return dest.GetSublist(0, start - 1) + src + dest.GetSublist(start, -1); } + /// + /// Returns the index of the first occurrence of test + /// in src. + /// + public int llListFindList(LSL_Types.list src, LSL_Types.list test) { + + int index = -1; + int length = src.Length - test.Length + 1; + m_host.AddScriptLPS(1); - //foreach (string s in test) - //{ - // for (int ci = 0; ci < src.Count; ci++) - // { - // if (s == src[ci]) - // return ci; - // } - //} - NotImplemented("llListFindList"); - return -1; + + // If either list is empty, do not match + + if(src.Length != 0 && test.Length != 0) + { + for(int i=0; i< length; i++) + { + if(src.Data[i].Equals(test.Data[0])) + { + int j; + for(j=1;j + /// Reset the named script. The script must be present + /// in the same prim. + /// + public void llResetOtherScript(string name) { + + LLUUID item; + ScriptManager sm; + IScript script = null; + m_host.AddScriptLPS(1); - NotImplemented("llResetOtherScript"); + + // These functions are supposed to be robust, + // so get the state one step at a time. + + if((item = ScriptByName(name)) != LLUUID.Zero) + if((sm = m_ScriptEngine.m_ScriptManager) != null) + sm.ResetScript(m_localID, item); + + // Required by SL + + if(script == null) + ShoutError("llResetOtherScript: script "+name+" not found"); + + // If we didn;t find it, then it's safe to + // assume it is not running. + + return; + } public int llGetScriptState(string name) { + + LLUUID item; + ScriptManager sm; + IScript script = null; + m_host.AddScriptLPS(1); - //NotImplemented("llGetScriptState"); + // These functions are supposed to be robust, + // so get the state one step at a time. + + if((item = ScriptByName(name)) != LLUUID.Zero) + if((sm = m_ScriptEngine.m_ScriptManager) != null) + if((script = sm.GetScript(m_localID, item)) != null) + return script.Exec.Running?1:0; + + // Required by SL + + if(script == null) + ShoutError("llGetScriptState: script "+name+" not found"); + + // If we didn;t find it, then it's safe to + // assume it is not running. + return 0; + } public void llRemoteLoadScript() { m_host.AddScriptLPS(1); - NotImplemented("llRemoteLoadScript"); + ShoutError("llRemoteLoadScript: deprecated"); } public void llSetRemoteScriptAccessPin(int pin) @@ -3880,7 +4120,7 @@ namespace OpenSim.Region.ScriptEngine.Common { m_host.AddScriptLPS(1); Int64 tmp = 0; - Int64 val = Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp); + Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp); return Convert.ToInt32(tmp); } @@ -4237,18 +4477,19 @@ namespace OpenSim.Region.ScriptEngine.Common return ret; } - public string llStringTrim(string src, int type) + public string llStringTrim(string src, int type) { m_host.AddScriptLPS(1); - if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); } - if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); } - if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM) { return src.Trim(); } - return src; - } + if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); } + if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); } + if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM) { return src.Trim(); } + return src; + } // // OpenSim functions // + public int osTerrainSetHeight(int x, int y, double val) { m_host.AddScriptLPS(1); @@ -4413,6 +4654,21 @@ namespace OpenSim.Region.ScriptEngine.Common return false; } + private LLUUID ScriptByName(string name) + { + foreach (TaskInventoryItem item in m_host.TaskInventory.Values) + { + if(item.Type == 10 && item.Name == name) + return item.ItemID; + } + return LLUUID.Zero; + } + + private void ShoutError(string msg) + { + llShout(BuiltIn_Commands_BaseClass.DEBUG_CHANNEL,msg); + } + public void osSetPrimFloatOnWater(int floatYN) { m_host.AddScriptLPS(1); -- cgit v1.1