diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 0e6e1432327..c2655193fb5 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -181,7 +181,8 @@ public virtual void StoreObject(SceneObjectGroup obj, UUID regionUUID) "AttachedPosY, AttachedPosZ, " + "PhysicsShapeType, Density, GravityModifier, " + "Friction, Restitution, Vehicle, PhysInertia, DynAttrs, " + - "RotationAxisLocks, sopanims, sitactrange, pseudocrc" + + "RotationAxisLocks, sopanims, sitactrange, pseudocrc, " + + "linksetdata" + ") values (" + "?UUID, " + "?CreationDate, ?Name, ?Text, " + "?Description, ?SitName, ?TouchName, " + @@ -216,7 +217,8 @@ public virtual void StoreObject(SceneObjectGroup obj, UUID regionUUID) "?AttachedPosY, ?AttachedPosZ, " + "?PhysicsShapeType, ?Density, ?GravityModifier, " + "?Friction, ?Restitution, ?Vehicle, ?PhysInertia, ?DynAttrs," + - "?RotationAxisLocks, ?sopanims, ?sitactrange, ?pseudocrc)"; + "?RotationAxisLocks, ?sopanims, ?sitactrange, ?pseudocrc, " + + "?linksetdata)"; FillPrimCommand(cmd, prim, obj.UUID, regionUUID); @@ -1202,6 +1204,11 @@ private SceneObjectPart BuildPrim(IDataReader row) if(pseudocrc != 0) prim.PseudoCRC = pseudocrc; + if (!(row["linksetdata"] is DBNull)) + { + prim.DeserializeLinksetData((string)row["linksetdata"]); + } + return prim; } @@ -1613,13 +1620,22 @@ private void FillPrimCommand(MySqlCommand cmd, SceneObjectPart prim, UUID sceneG cmd.Parameters.AddWithValue("Restitution", prim.Restitution); cmd.Parameters.AddWithValue("RotationAxisLocks", prim.RotationAxisLocks); - if (prim.Animations!= null) + if (prim.Animations != null) cmd.Parameters.AddWithValue("sopanims", prim.SerializeAnimations()); else cmd.Parameters.AddWithValue("sopanims", null); cmd.Parameters.AddWithValue("sitactrange", prim.SitActiveRange); cmd.Parameters.AddWithValue("pseudocrc", prim.PseudoCRC); + + if (prim.LinksetData != null) + { + cmd.Parameters.AddWithValue("linksetdata", prim.SerializeLinksetData()); + } + else + { + cmd.Parameters.AddWithValue("linksetdata", null); + } } /// diff --git a/OpenSim/Data/MySQL/OpenSim.Data.MySQL.csproj b/OpenSim/Data/MySQL/OpenSim.Data.MySQL.csproj index 6c298076d00..7ddb21b2248 100644 --- a/OpenSim/Data/MySQL/OpenSim.Data.MySQL.csproj +++ b/OpenSim/Data/MySQL/OpenSim.Data.MySQL.csproj @@ -44,7 +44,7 @@ - + diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations index d1f62dcdb4b..da5fc0c6314 100644 --- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations @@ -550,3 +550,11 @@ BEGIN; ALTER TABLE `land` ADD COLUMN `environment` MEDIUMTEXT default NULL; COMMIT; + :VERSION 64 #----- material overrides + ALTER TABLE `primshapes` ADD COLUMN `MatOvrd` blob default NULL; + COMMIT; + +:VERSION 65 #----- add linkset data storage column +BEGIN; +ALTER TABLE `prims` ADD COLUMN `linksetdata` MEDIUMTEXT default NULL; +COMMIT; \ No newline at end of file diff --git a/OpenSim/Data/OpenSim.Data.csproj b/OpenSim/Data/OpenSim.Data.csproj index 9bc07d0f0c9..f21ab12753f 100644 --- a/OpenSim/Data/OpenSim.Data.csproj +++ b/OpenSim/Data/OpenSim.Data.csproj @@ -51,7 +51,7 @@ - + diff --git a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs index d78d1a87362..9d715ac712f 100755 --- a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs +++ b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs @@ -355,9 +355,9 @@ UPDATE prims SET ""ClickAction"" = :ClickAction, ""Material"" = :Material, ""CollisionSound"" = :CollisionSound, ""CollisionSoundVolume"" = :CollisionSoundVolume, ""PassTouches"" = :PassTouches, ""LinkNumber"" = :LinkNumber, ""MediaURL"" = :MediaURL, ""DynAttrs"" = :DynAttrs, ""Vehicle"" = :Vehicle, ""PhysInertia"" = :PhysInertia, ""standtargetx"" =:standtargetx, ""standtargety"" =:standtargety, ""standtargetz"" =:standtargetz, - ""sitactrange"" =:sitactrange, ""pseudocrc"" = :pseudocrc, ""sopanims"" = :sopanims - - WHERE ""UUID"" = :UUID ; + ""sitactrange"" =:sitactrange, ""pseudocrc"" = :pseudocrc, ""sopanims"" = :sopanims, + ""linksetdata"" =:linksetdata + WHERE ""UUID"" = :UUID ; INSERT INTO prims ( @@ -371,7 +371,7 @@ INSERT INTO ""ForceMouselook"", ""ScriptAccessPin"", ""AllowedDrop"", ""DieAtEdge"", ""SalePrice"", ""SaleType"", ""ColorR"", ""ColorG"", ""ColorB"", ""ColorA"", ""ParticleSystem"", ""ClickAction"", ""Material"", ""CollisionSound"", ""CollisionSoundVolume"", ""PassTouches"", ""LinkNumber"", ""MediaURL"", ""DynAttrs"", ""PhysicsShapeType"", ""Density"", ""GravityModifier"", ""Friction"", ""Restitution"", ""PassCollisions"", ""RotationAxisLocks"", ""RezzerID"" , ""Vehicle"", ""PhysInertia"", - ""standtargetx"", ""standtargety"", ""standtargetz"", ""sitactrange"", ""pseudocrc"", ""sopanims"" + ""standtargetx"", ""standtargety"", ""standtargetz"", ""sitactrange"", ""pseudocrc"", ""sopanims"", ""linksetdata"" ) Select :UUID, :CreationDate, :Name, :Text, :Description, :SitName, :TouchName, :ObjectFlags, :OwnerMask, :NextOwnerMask, :GroupMask, :EveryoneMask, :BaseMask, :PositionX, :PositionY, :PositionZ, :GroupPositionX, :GroupPositionY, :GroupPositionZ, :VelocityX, @@ -383,7 +383,7 @@ INSERT INTO :ForceMouselook, :ScriptAccessPin, :AllowedDrop, :DieAtEdge, :SalePrice, :SaleType, :ColorR, :ColorG, :ColorB, :ColorA, :ParticleSystem, :ClickAction, :Material, :CollisionSound, :CollisionSoundVolume, :PassTouches, :LinkNumber, :MediaURL, :DynAttrs, :PhysicsShapeType, :Density, :GravityModifier, :Friction, :Restitution, :PassCollisions, :RotationAxisLocks, :RezzerID, :Vehicle, :PhysInertia, - :standtargetx, :standtargety, :standtargetz,:sitactrange, :pseudocrc, :sopanims + :standtargetx, :standtargety, :standtargetz,:sitactrange, :pseudocrc, :sopanims, :LinksetData where not EXISTS (SELECT ""UUID"" FROM prims WHERE ""UUID"" = :UUID); "; @@ -1406,6 +1406,11 @@ private static SceneObjectPart BuildPrim(IDataRecord primRow) prim.Animations = null; } + if ((primRow["LinksetData"] is DBNull) == false) + { + prim.DeserializeLinksetData(((string)primRow["linksetdata"])); + } + return prim; } @@ -1870,6 +1875,8 @@ private NpgsqlParameter[] CreatePrimParameters(SceneObjectPart prim, UUID sceneG else parameters.Add(_Database.CreateParameter("sopanims", null)); + parameters.Add(_Database.CreateParameter("linksetdata", prim.SerializeLinksetData())); + return parameters.ToArray(); } diff --git a/OpenSim/Data/PGSQL/Resources/RegionStore.migrations b/OpenSim/Data/PGSQL/Resources/RegionStore.migrations index 1def32ef1f4..ea172f13783 100644 --- a/OpenSim/Data/PGSQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/PGSQL/Resources/RegionStore.migrations @@ -1261,3 +1261,8 @@ BEGIN; ALTER TABLE `prims` ADD COLUMN `sopanims` bytea NULL; ALTER TABLE `primshapes` ADD COLUMN `MatOvrd` bytea NULL; COMMIT; + +:VERSION 53 #----- add linkset data storage column +BEGIN; +ALTER TABLE `prims` ADD COLUMN `linksetdata` varchar default NULL; +COMMIT; diff --git a/OpenSim/Data/SQLite/Resources/RegionStore.migrations b/OpenSim/Data/SQLite/Resources/RegionStore.migrations index 448fc962714..84e35c7e548 100644 --- a/OpenSim/Data/SQLite/Resources/RegionStore.migrations +++ b/OpenSim/Data/SQLite/Resources/RegionStore.migrations @@ -406,3 +406,8 @@ BEGIN; ALTER TABLE `prims` ADD COLUMN `sopanims` blob default NULL; ALTER TABLE `primshapes` ADD COLUMN `MatOvrd` blob default NULL; COMMIT; + +:VERSION 41 #----- add linkset data storage column +BEGIN; +ALTER TABLE `prims` ADD COLUMN `linksetdata` TEXT default NULL; +COMMIT; \ No newline at end of file diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index 786532bef97..30b4c4d3c3b 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -1251,6 +1251,8 @@ private static DataTable createPrimTable() createCol(prims, "pseudocrc", typeof(int)); createCol(prims, "sopanims", typeof(byte[])); + createCol(prims, "linksetdata", typeof(string)); + // Add in contraints prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] }; @@ -1810,6 +1812,11 @@ private SceneObjectPart buildPrim(DataRow row) prim.Animations = null; } + if (!(row["linksetdata"] is DBNull)) + { + prim.DeserializeLinksetData((string)row["LinksetData"]); + } + return prim; } @@ -2199,6 +2206,8 @@ private static void fillPrimRow(DataRow row, SceneObjectPart prim, UUID sceneGro row["pseudocrc"] = prim.PseudoCRC; row["sopanims"] = prim.SerializeAnimations(); + + row["linksetdata"] = prim.SerializeLinksetData(); } /// diff --git a/OpenSim/Framework/VersionInfo.cs b/OpenSim/Framework/VersionInfo.cs index e5b85474cb2..4391af35837 100644 --- a/OpenSim/Framework/VersionInfo.cs +++ b/OpenSim/Framework/VersionInfo.cs @@ -39,30 +39,16 @@ public class VersionInfo { public const string VersionNumber = "0.9.2.2"; public const string AssemblyVersionNumber = "0.9.2.2"; - public const string Release = "8619"; - - public const Flavour VERSION_FLAVOUR = Flavour.Dev; - - public enum Flavour - { - Unknown, - Dev, - RC1, - RC2, - RC3, - Release, - Post_Fixes, - Extended - } + public const string Release = "8738"; public static string Version { - get { return GetVersionString(VersionNumber, Release, VERSION_FLAVOUR); } + get { return GetVersionString(VersionNumber, Release); } } - public static string GetVersionString(string versionNumber, string release, Flavour flavour) + public static string GetVersionString(string versionNumber, string release) { - string versionString = "OpenSim-NGC " + versionNumber + "." + release + " Yeti " + flavour; + string versionString = "OpenSim-NGC Tranquillity " + versionNumber + "." + release; return versionString.PadRight(VERSIONINFO_VERSION_LENGTH); } diff --git a/OpenSim/Framework/VersionInfo.tt b/OpenSim/Framework/VersionInfo.tt index 52060856d05..b8a22e42b2c 100644 --- a/OpenSim/Framework/VersionInfo.tt +++ b/OpenSim/Framework/VersionInfo.tt @@ -41,28 +41,14 @@ namespace OpenSim public const string AssemblyVersionNumber = "0.9.2.2"; public const string Release = "<#= (int)DateTimeOffset.UtcNow.Subtract(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalDays #>"; - public const Flavour VERSION_FLAVOUR = Flavour.Dev; - - public enum Flavour - { - Unknown, - Dev, - RC1, - RC2, - RC3, - Release, - Post_Fixes, - Extended - } - public static string Version { - get { return GetVersionString(VersionNumber, Release, VERSION_FLAVOUR); } + get { return GetVersionString(VersionNumber, Release); } } - public static string GetVersionString(string versionNumber, string release, Flavour flavour) + public static string GetVersionString(string versionNumber, string release) { - string versionString = "OpenSim-NGC " + versionNumber + "." + release + " Yeti " + flavour; + string versionString = "OpenSim-NGC Tranquillity " + versionNumber + "." + release; return versionString.PadRight(VERSIONINFO_VERSION_LENGTH); } diff --git a/OpenSim/Region/Framework/OpenSim.Region.Framework.Tests.csproj b/OpenSim/Region/Framework/OpenSim.Region.Framework.Tests.csproj index 61fdd443b09..4e8660ce851 100644 --- a/OpenSim/Region/Framework/OpenSim.Region.Framework.Tests.csproj +++ b/OpenSim/Region/Framework/OpenSim.Region.Framework.Tests.csproj @@ -141,6 +141,8 @@ + + diff --git a/OpenSim/Region/Framework/OpenSim.Region.Framework.csproj b/OpenSim/Region/Framework/OpenSim.Region.Framework.csproj index e4aebe25752..e5db07bede5 100644 --- a/OpenSim/Region/Framework/OpenSim.Region.Framework.csproj +++ b/OpenSim/Region/Framework/OpenSim.Region.Framework.csproj @@ -82,5 +82,6 @@ + \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/LinksetData.cs b/OpenSim/Region/Framework/Scenes/LinksetData.cs new file mode 100644 index 00000000000..8f8278a7b29 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/LinksetData.cs @@ -0,0 +1,417 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; + +namespace OpenSim.Region.Framework.Scenes +{ + public class LinksetData + { + public const int LINKSETDATA_MAX = 131072; + + private static readonly object linksetDataLock = new object(); + + public LinksetData() + { + Data = new SortedList(); + + LinksetDataBytesFree = LINKSETDATA_MAX; + LinksetDataBytesUsed = 0; + } + + public SortedList Data { get; private set; } = null; + + public int LinksetDataBytesFree { get; private set; } = LINKSETDATA_MAX; + public int LinksetDataBytesUsed { get; private set; } = 0; + + // Deep Copy of Linkset Data + public LinksetData Copy() + { + lock (linksetDataLock) + { + var copy = new LinksetData(); + foreach (var entry in Data) + { + var key = String.Copy(entry.Key); + var val = entry.Value.Copy(); + copy.Data.Add(key, val); + copy.LinksetDataAccountingDelta(val.GetCost(key)); + } + + return copy; + } + } + + /// + /// Adds or updates a entry to linkset data + /// + /// + /// -1 if the password did not match + /// -1 is the data was protected + /// 0 if the data was successfully added or updated + /// 1 if the data could not be added or updated due to memory + /// 2 if the data is unchanged + /// + public int AddOrUpdateLinksetDataKey(string key, string value, string pass) + { + lock (linksetDataLock) + { + if (LinksetDataOverLimit()) + return 1; + + LinksetDataEntry entry = null; + if (Data.TryGetValue(key, out entry)) + { + if (!entry.CheckPassword(pass)) + return -1; + + if (entry.Value == value) + return 2; + + // Subtract out the old entry + LinksetDataAccountingDelta(-entry.GetCost(key)); + } + + // Add New or Update handled here. + LinksetDataEntry newEntry = new LinksetDataEntry(value, pass); + Data[key] = newEntry; + + // Add the cost for the newply created entry + LinksetDataAccountingDelta(newEntry.GetCost(key)); + + return 0; + } + } + + /// + /// Deletes a named key from the key value store + /// + /// The key value we're removing + /// The password for a protected field (or string.Empty if not protected) + /// + /// 0 if successful. + /// 1 if not due to the password. + /// -1 if no such key was found + /// + public int DeleteLinksetDataKey(string key, string pass) + { + lock (linksetDataLock) + { + if (Data.Count <= 0) + return -1; + + LinksetDataEntry entry; + if (!Data.TryGetValue(key, out entry)) + return -1; + + if (!entry.CheckPassword(pass)) + return 1; + + Data.Remove(key); + LinksetDataAccountingDelta(-entry.GetCost(key)); + + return 0; + } + } + + public void DeserializeLinksetData(string data) + { + if (data == null || data.Length == 0) + return; + + //? Need to adjust accounting + lock (linksetDataLock) + { + Data = JsonSerializer.Deserialize>(data); + } + } + + /// + /// FindLinksetDataKeys - Given a Regex pattern and start, count return the + /// list of matchingkeys in the LinksetData store. + /// + /// A Regex pattern to match + /// starting offset into the list of keys + /// how many to return, < 1 means all keys + /// + public string[] FindLinksetDataKeys(string pattern, int start, int count) + { + List all_keys = new List(GetLinksetDataSubList(0, 0)); + Regex rx = new Regex(pattern, RegexOptions.CultureInvariant); + + if (count < 1) + count = all_keys.Count; + + List matches = new List(); + foreach (var str in all_keys) + { + if (rx.IsMatch(str)) + matches.Add(str); + } + + return matches.Skip(start).Take(count).ToArray(); + } + + /// + /// GetLinksetDataSubList - Return a subset of key values from start for count + /// + /// Offset in the list for the first key + /// How many keys to return, < 1 means all keys + /// + public string[] GetLinksetDataSubList(int start, int count) + { + lock (linksetDataLock) + { + if (Data.Count <= 0) + return new string[0]; + + if (count < 1) + count = Data.Count; + + List ret = Data.Keys.Skip(start).Take(count).ToList(); + + return ret.ToArray(); + } + } + + public bool HasLinksetData() + { + return Data.Count > 0; + } + + /// + /// LinksetDataCountMatches - Return a count of the # of keys that match pattern. + /// + /// The Regex pattern to match + /// An integer count or zero if none + public int LinksetDataCountMatches(string pattern) + { + lock (linksetDataLock) + { + if (Data.Count <= 0) + return 0; + + Regex reg = new Regex(pattern, RegexOptions.CultureInvariant); + + int count = 0; + foreach (var kvp in Data) + { + if (reg.IsMatch(kvp.Key)) + count++; + } + + return count; + } + } + + public int LinksetDataKeys() + { + return Data.Count; + } + + public string[] LinksetDataMultiDelete(string pattern, string pass, out int deleted, out int not_deleted) + { + lock (linksetDataLock) + { + deleted = 0; + not_deleted = 0; + + if (Data.Count <= 0) + return new string[0]; + + Regex reg = new Regex(pattern, RegexOptions.CultureInvariant); + List matches = new List(); + + // Take a copy so we can delete as we iterate + foreach (var kvp in Data.ToArray()) + { + if (reg.IsMatch(kvp.Key)) + { + if (kvp.Value.CheckPassword(pass)) + { + Data.Remove(kvp.Key); + matches.Add(kvp.Key); + + LinksetDataAccountingDelta(-kvp.Value.GetCost(kvp.Key)); + deleted += 1; + } + else + { + not_deleted += 1; + } + } + } + + return matches.ToArray(); + } + } + + public bool LinksetDataOverLimit() + { + return (LinksetDataBytesFree <= 0); + } + + /// + /// Merge the linksetData present in another Linkset into this one. + /// The current root will have the new linkset for the merged sog. + /// If a key is present in our linksetData it wins, dont overide it. + /// + /// + public void MergeLinksetData(LinksetData otherLinksetData) + { + // Nothing to merge? + if (otherLinksetData == null) + return; + + lock (linksetDataLock) + { + foreach (var kvp in otherLinksetData.Data) + { + // If its already present skip it + if (Data.ContainsKey(kvp.Key)) + continue; + + // Do we have space for another entry? + if (LinksetDataOverLimit()) + break; + + var key = string.Copy(kvp.Key); + var value = kvp.Value.Copy(); + + Data.Add(key, value); + LinksetDataAccountingDelta(value.GetCost(key)); + } + + // Clear the LinksetData entries from the "other" SOG + otherLinksetData.Data.Clear(); + + otherLinksetData.LinksetDataBytesFree = LINKSETDATA_MAX; + otherLinksetData.LinksetDataBytesUsed = 0; + } + } + + /// + /// Reads a value from the key value pair + /// + /// The key value we're retrieving + /// The password for a protected field (or string.Empty if not protected) + /// Blank if no key or pass mismatch. Value if no password or pass matches + public string ReadLinksetData(string key, string pass) + { + lock (linksetDataLock) + { + if (Data.Count <= 0) + return string.Empty; + + LinksetDataEntry entry; + if (Data.TryGetValue(key, out entry)) + { + return entry.CheckPasswordAndGetValue(pass); + } + + return string.Empty; + } + } + + /// + /// ResetLinksetData - clear the list and update the accounting. + /// + public void ResetLinksetData() + { + lock (linksetDataLock) + { + if (Data.Count <= 0) + return; + + Data.Clear(); + + LinksetDataBytesFree = LINKSETDATA_MAX; + LinksetDataBytesUsed = 0; + } + } + + public string SerializeLinksetData() + { + lock (linksetDataLock) + { + return JsonSerializer.Serialize>(Data); + } + } + + /// + /// Add/Subtract an integer value from the current data allocated for the Linkset. + /// + /// An integer value, positive adds, negative subtracts delta bytes. + private void LinksetDataAccountingDelta(int delta) + { + LinksetDataBytesUsed += delta; + LinksetDataBytesFree = LINKSETDATA_MAX - LinksetDataBytesUsed; + + if (LinksetDataBytesFree < 0) + LinksetDataBytesFree = 0; + } + } + + public class LinksetDataEntry + { + public LinksetDataEntry(string value, string password) + { + Value = value; + Password = password; + } + + public string Password { get; private set; } = string.Empty; + + public string Value { get; private set; } + + public bool CheckPassword(string pass) + { + // A undocumented caveat for LinksetData appears to be that even for unprotected values, + // if a pass is provided, it is still treated as protected + return string.IsNullOrEmpty(Password) || (Password == pass); + } + + public string CheckPasswordAndGetValue(string pass) + { + return CheckPassword(pass) ? Value : string.Empty; + } + + // Deep Copy of Current Entry + public LinksetDataEntry Copy() + { + string value = String.IsNullOrEmpty(Value) ? null : string.Copy(Value); + string password = String.IsNullOrEmpty(Password) ? null : string.Copy(Password); + + return new LinksetDataEntry(value, password); + } + + /// + /// Calculate the cost in bytes for this entry. Adds in the passed in key and + /// if a password is supplied uses 32 bytes minimum unless the password is longer. + /// + /// The string key value associated with this entry. + /// int - cost of this entry in bytes + public int GetCost(string key) + { + int cost = 0; + + cost += Encoding.UTF8.GetBytes(key).Length; + cost += Encoding.UTF8.GetBytes(this.Value).Length; + + if (!string.IsNullOrEmpty(this.Password)) + { + // For parity, the pass adds 32 bytes regardless of the length. See LL caveats + cost += Math.Max(Encoding.UTF8.GetBytes(this.Password).Length, 32); + } + + return cost; + } + + public bool IsProtected() + { + return !string.IsNullOrEmpty(Password); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index e7d6346c121..c46dead5f5f 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -88,9 +88,10 @@ public enum ScriptEventCode : int http_request = 38, path_update = 40, + linkset_data = 41, // marks highest numbered event - Size = 41 + Size = 42 } // this is not the right place for this @@ -145,7 +146,9 @@ public enum scriptEvents : ulong anytouch = touch | touch_end | touch_start, anyTarget = at_target | not_at_target | at_rot_target | not_at_rot_target, anyobjcollision = collision | collision_end | collision_start, - anylandcollision = land_collision | land_collision_end | land_collision_start + anylandcollision = land_collision | land_collision_end | land_collision_start, + + linkset_data = 1UL << 41 } public struct scriptPosTarget @@ -2661,10 +2664,17 @@ public SceneObjectGroup Copy(bool userExposed) public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) { SceneObjectPart newpart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed); -// SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed); -// newpart.LocalId = m_scene.AllocateLocalId(); + // SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed); + // newpart.LocalId = m_scene.AllocateLocalId(); + + // If the rootpart we're copying has LinksetData do a deep copy of that to the new rootpart. + if (part.LinksetData != null) + { + newpart.LinksetData = part.LinksetData.Copy(); + } SetRootPart(newpart); + if (userExposed) RootPart.Velocity = Vector3.Zero; // In case source is moving } @@ -3249,6 +3259,15 @@ public void LinkToGroup(SceneObjectGroup objectGroup, bool insert) // 'linkPart' == the root of the group being linked into this group SceneObjectPart linkPart = objectGroup.m_rootPart; + // Merge linksetData if there is any + if (linkPart.LinksetData != null) + { + if (m_rootPart.LinksetData == null) + m_rootPart.LinksetData = new LinksetData(); + + m_rootPart.LinksetData.MergeLinksetData(linkPart.LinksetData); + } + if (m_rootPart.PhysActor != null) m_rootPart.PhysActor.Building = true; if (linkPart.PhysActor != null) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4fdca98b675..d55028b53d9 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -29,9 +29,12 @@ using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Linq; using System.Reflection; using System.Threading; using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; using System.Xml; using System.Xml.Serialization; using log4net; @@ -42,6 +45,11 @@ using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Region.PhysicsModules.SharedBase; using PermissionMask = OpenSim.Framework.PermissionMask; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Data.Entity.ModelConfiguration.Configuration; +using System.Runtime.Serialization.Json; +using OpenMetaverse.Rendering; +using System.Web.Configuration; namespace OpenSim.Region.Framework.Scenes { @@ -196,6 +204,9 @@ public bool IsSitTargetSet /// public PhysicsActor PhysActor { get; set; } + [XmlIgnore] + public LinksetData LinksetData { get; set; } = null; + //Xantor 20080528 Sound stuff: // Note: This isn't persisted in the database right now, as the fields for that aren't just there yet. // Not a big problem as long as the script that sets it remains in the prim on startup. @@ -2231,6 +2242,7 @@ public SceneObjectPart Copy(uint plocalID, UUID AgentID, UUID GroupID, int linkN dupe.PhysActor.LocalID = plocalID; dupe.PseudoCRC = (int)(DateTime.UtcNow.Ticks); + dupe.DeserializeLinksetData(SerializeLinksetData()); ParentGroup.Scene.EventManager.TriggerOnSceneObjectPartCopy(dupe, this, userExposed); @@ -5765,7 +5777,7 @@ public Byte[] SerializeAnimations() public void DeSerializeAnimations(Byte[] data) { - if(data == null) + if (data == null) { Animations = null; AnimationsNames = null; @@ -5810,10 +5822,35 @@ public void DeSerializeAnimations(Byte[] data) AnimationsNames = null; } + public string SerializeLinksetData() + { + if (IsRoot && (LinksetData != null)) + { + if (LinksetData.HasLinksetData()) + return LinksetData.SerializeLinksetData(); + } + + return string.Empty; + } + + public void DeserializeLinksetData(string data) + { + if (string.IsNullOrEmpty(data) || data.Length == 0) + return; + + if (LinksetData == null) + { + LinksetData = new LinksetData(); + } + + LinksetData.DeserializeLinksetData(data); + } + public bool GetOwnerName(out string FirstName, out string LastName) { - if(ParentGroup != null) + if (ParentGroup != null) return ParentGroup.GetOwnerName(out FirstName, out LastName); + FirstName = string.Empty; LastName = string.Empty; return false; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index f238777334f..dbe51a891a8 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -533,6 +533,7 @@ static SceneObjectSerializer() m_SOPXmlProcessors.Add("SOPAnims", ProcessSOPAnims); m_SOPXmlProcessors.Add("SitActRange", ProcessSitActRange); + m_SOPXmlProcessors.Add("LinksetData", ProcessLinksetData); #endregion @@ -832,6 +833,24 @@ private static void ProcessSitActRange(SceneObjectPart obj, XmlReader reader) obj.SitActiveRange = reader.ReadElementContentAsFloat("SitActRange", String.Empty); } + private static void ProcessLinksetData(SceneObjectPart obj, XmlReader reader) + { + try + { + string data = reader.ReadElementContentAsString(); + if (string.IsNullOrEmpty(data)) + return; + + obj.DeserializeLinksetData(data); + } + catch + { + m_log.DebugFormat( + "[SceneObjectSerializer]: Exception while processing linksetdata for object part {0} {1}.", + obj.Name, obj.UUID); + } + } + private static void ProcessVehicle(SceneObjectPart obj, XmlReader reader) { SOPVehicle vehicle = SOPVehicle.FromXml2(reader); @@ -1669,6 +1688,9 @@ public static void SOPToXml2(XmlTextWriter writer, SceneObjectPart sop, Dictiona } if(Math.Abs(sop.SitActiveRange) > 1e-5) writer.WriteElementString("SitActRange", sop.SitActiveRange.ToString(Culture.FormatProvider)); + + writer.WriteElementString("LinksetData", sop.SerializeLinksetData()); + writer.WriteEndElement(); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 61c02ff7116..2593a01d77e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -114,6 +114,7 @@ public int LlRequestAgentDataCacheTimeoutMs protected float m_recoilScaleFactor = 0.0f; protected bool m_AllowGodFunctions; + protected string m_GetWallclockTimeZone = String.Empty; // Defaults to UTC protected double m_timer = Util.GetTimeStampMS(); protected bool m_waitingForScriptAnswer = false; protected bool m_automaticLinkPermission = false; @@ -431,6 +432,8 @@ private void LoadConfig() m_automaticLinkPermission = seConfig.GetBoolean("AutomaticLinkPermission", m_automaticLinkPermission); m_notecardLineReadCharsMax = seConfig.GetInt("NotecardLineReadCharsMax", m_notecardLineReadCharsMax); + m_GetWallclockTimeZone = seConfig.GetString("GetWallclockTimeZone", m_GetWallclockTimeZone); + // Rezzing an object with a velocity can create recoil. This feature seems to have been // removed from recent versions of SL. The code computes recoil (vel*mass) and scales // it by this factor. May be zero to turn off recoil all together. @@ -3113,7 +3116,16 @@ public LSL_Float llGetTimeOfDay() public LSL_Float llGetWallclock() { - return DateTime.Now.TimeOfDay.TotalSeconds; + DateTimeOffset dateTimeOffset = DateTimeOffset.Now; + + if (string.IsNullOrEmpty(m_GetWallclockTimeZone) == false) + { + dateTimeOffset = + TimeZoneInfo.ConvertTimeBySystemTimeZoneId( + DateTimeOffset.UtcNow, m_GetWallclockTimeZone); + } + + return Math.Truncate(dateTimeOffset.DateTime.TimeOfDay.TotalSeconds); } public LSL_Float llGetTime() @@ -18767,7 +18779,6 @@ public LSL_String llReplaceSubString(LSL_String src, LSL_String pattern, LSL_Str count = -1; } - try { if (string.IsNullOrEmpty(src.m_string)) @@ -18787,7 +18798,245 @@ public LSL_String llReplaceSubString(LSL_String src, LSL_String pattern, LSL_Str return src; } } - } + + public LSL_Integer llLinksetDataWrite(LSL_String name, LSL_String value) + { + return llLinksetDataWriteProtected(name, value, new LSL_String(string.Empty)); + } + + public LSL_Integer llLinksetDataWriteProtected(LSL_String name, LSL_String value, LSL_String pass) + { + if (string.IsNullOrEmpty(name)) + return ScriptBaseClass.LINKSETDATA_ENOKEY; + + // If value is empty this becomes a key delete operation + if (string.IsNullOrEmpty(value)) + { + return llLinksetDataDeleteProtected(name, pass); + } + + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + int ret = rootPrim.LinksetData.AddOrUpdateLinksetDataKey(name, value, pass); + + object[] parameters = new object[] + { + new LSL_Integer(ScriptBaseClass.LINKSETDATA_UPDATE), name, value + }; + + if (ret == 0) + { + m_ScriptEngine.PostObjectEvent( + rootPrim.LocalId, + new EventParams("linkset_data", parameters, Array.Empty())); + + rootPrim.ParentGroup.HasGroupChanged = true; + + return ScriptBaseClass.LINKSETDATA_OK; + } + else + { + if (ret == 1) + { + return ScriptBaseClass.LINKSETDATA_EMEMORY; + } + else if (ret == 2) + { + return ScriptBaseClass.LINKSETDATA_NOUPDATE; + } + else + { + return ScriptBaseClass.LINKSETDATA_EPROTECTED; + } + } + } + + public void llLinksetDataReset() + { + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + rootPrim.LinksetData.ResetLinksetData(); + + object[] parameters = new object[] + { + new LSL_Integer(ScriptBaseClass.LINKSETDATA_RESET), new LSL_String(string.Empty), new LSL_String(string.Empty) + }; + + m_ScriptEngine.PostObjectEvent( + rootPrim.LocalId, + new EventParams("linkset_data", parameters, Array.Empty())); + + rootPrim.ParentGroup.HasGroupChanged = true; + } + + public LSL_Integer llLinksetDataAvailable() + { + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + return new LSL_Integer(rootPrim.LinksetData.LinksetDataBytesFree); + } + + public LSL_Integer llLinksetDataCountKeys() + { + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + return new LSL_Integer(rootPrim.LinksetData.LinksetDataKeys()); + } + + public LSL_Integer llLinksetDataDelete(LSL_String name) + { + return llLinksetDataDeleteProtected(name, new LSL_String(string.Empty)); + } + + public LSL_Integer llLinksetDataDeleteProtected(LSL_String name, LSL_String pass) + { + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + int ret = rootPrim.LinksetData.DeleteLinksetDataKey(name, pass); + + object[] parameters; + + if (ret == 0) + { + parameters = new object[] + { + new LSL_Integer(ScriptBaseClass.LINKSETDATA_DELETE), name, new LSL_String(string.Empty) + }; + + m_ScriptEngine.PostObjectEvent( + rootPrim.LocalId, + new EventParams("linkset_data", parameters, Array.Empty())); + + rootPrim.ParentGroup.HasGroupChanged = true; + + return new LSL_Integer(ScriptBaseClass.LINKSETDATA_OK); + } + else if (ret == 1) + { + return new LSL_Integer(ScriptBaseClass.LINKSETDATA_EPROTECTED); + } + else + { + return new LSL_Integer(ScriptBaseClass.LINKSETDATA_NOTFOUND); + } + } + + public LSL_List llLinksetDataDeleteFound(LSL_String pattern, LSL_String pass) + { + int deleted = 0; + int not_deleted = 0; + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + var matches = rootPrim.LinksetData.LinksetDataMultiDelete(pattern, pass, out deleted, out not_deleted); + + string removed_keys = String.Join(",", matches); + + object[] parameters = new object[] + { + new LSL_Integer(ScriptBaseClass.LINKSETDATA_MULTIDELETE), + new LSL_String(removed_keys), + new LSL_String(string.Empty) + }; + + if (deleted > 0) + { + m_ScriptEngine.PostObjectEvent( + m_host.LocalId, + new EventParams("linkset_data", parameters, Array.Empty())); + + rootPrim.ParentGroup.HasGroupChanged = true; + + } + + return new LSL_List(new object[] + { + new LSL_Integer(deleted), new LSL_Integer(not_deleted) + }); + } + + public LSL_Integer llLinksetDataCountFound(LSL_String pattern) + { + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + return rootPrim.LinksetData.LinksetDataCountMatches(pattern); + } + + public LSL_List llLinksetDataFindKeys(LSL_String pattern, LSL_Integer start, LSL_Integer count) + { + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + return new LSL_List(rootPrim.LinksetData.FindLinksetDataKeys(pattern, start, count)); + } + + public LSL_List llLinksetDataListKeys(LSL_Integer start, LSL_Integer count) + { + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + return new LSL_List(rootPrim.LinksetData.GetLinksetDataSubList(start, count)); + } + + public LSL_String llLinksetDataRead(LSL_String name) + { + return llLinksetDataReadProtected(name, string.Empty); + } + + public LSL_String llLinksetDataReadProtected(LSL_String name, LSL_String pass) + { + var rootPrim = m_host.ParentGroup.RootPart; + + if (rootPrim.LinksetData == null) + { + rootPrim.LinksetData = new LinksetData(); + } + + return new LSL_String(rootPrim.LinksetData.ReadLinksetData(name, pass)); + } + } public class NotecardCache { diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index c24903c8ac5..cd92adebfed 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -4021,7 +4021,7 @@ private void SetProjectionParams(SceneObjectPart obj, LSL_Integer llprojection, obj.Shape.ProjectionEntry = true; obj.Shape.ProjectionTextureUUID = texID; obj.Shape.ProjectionFOV = Util.Clamp((float)fov, 0, 3.0f); - obj.Shape.ProjectionFocus = Util.Clamp((float)focus, 0, 20.0f); + obj.Shape.ProjectionFocus = Util.Clamp((float)focus, -20.0f, 20.0f); obj.Shape.ProjectionAmbiance = Util.Clamp((float)amb, 0, 1.0f); obj.ParentGroup.HasGroupChanged = true; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index 6ea61f2321c..55a8865e769 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -489,10 +489,24 @@ public interface ILSL_Api LSL_String llReplaceSubString(LSL_String src, LSL_String pattern, LSL_String replacement, int count); - void llLinkAdjustSoundVolume(LSL_Integer linknumber, LSL_Float volume); - void llLinkStopSound(LSL_Integer linknumber); - void llLinkPlaySound(LSL_Integer linknumber, string sound, double volume); - void llLinkSetSoundQueueing(int linknumber, int queue); - void llLinkSetSoundRadius(int linknumber, double radius); + void llLinkAdjustSoundVolume(LSL_Integer linknumber, LSL_Float volume); + void llLinkStopSound(LSL_Integer linknumber); + void llLinkPlaySound(LSL_Integer linknumber, string sound, double volume); + void llLinkSetSoundQueueing(int linknumber, int queue); + void llLinkSetSoundRadius(int linknumber, double radius); + + LSL_Integer llLinksetDataWrite(LSL_String name, LSL_String value); + LSL_Integer llLinksetDataWriteProtected(LSL_String name, LSL_String value, LSL_String pass); + void llLinksetDataReset(); + LSL_Integer llLinksetDataAvailable(); + LSL_Integer llLinksetDataCountKeys(); + LSL_Integer llLinksetDataDelete(LSL_String name); + LSL_Integer llLinksetDataDeleteProtected(LSL_String name, LSL_String pass); + LSL_List llLinksetDataDeleteFound(LSL_String pattern, LSL_String pass); + LSL_Integer llLinksetDataCountFound(LSL_String pattern); + LSL_List llLinksetDataFindKeys(LSL_String pattern, LSL_Integer start, LSL_Integer count); + LSL_List llLinksetDataListKeys(LSL_Integer start, LSL_Integer count); + LSL_String llLinksetDataRead(LSL_String name); + LSL_String llLinksetDataReadProtected(LSL_String name, LSL_String pass); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index d44c58126a1..0babf18bfb3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -1001,5 +1001,17 @@ public partial class ScriptBaseClass public const int NPCLOOKAT_FOCUS = 8; public const int NPCLOOKAT_MOUSELOOK = 9; public const int NPCLOOKAT_CLEAR = 10; + + public const int LINKSETDATA_RESET = 0; + public const int LINKSETDATA_UPDATE = 1; + public const int LINKSETDATA_DELETE = 2; + public const int LINKSETDATA_MULTIDELETE = 3; + + public const int LINKSETDATA_OK = 0; + public const int LINKSETDATA_EMEMORY = 1; + public const int LINKSETDATA_ENOKEY = 2; + public const int LINKSETDATA_EPROTECTED = 3; + public const int LINKSETDATA_NOTFOUND = 4; + public const int LINKSETDATA_NOUPDATE = 5; } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 4edf92bb5df..88b712bc456 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -2242,5 +2242,82 @@ public void llLinkSetSoundRadius(int linknumber, double radius) { m_LSL_Functions.llLinkSetSoundRadius(linknumber, radius); } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_Integer llLinksetDataWrite(LSL_String name, LSL_String value) + { + return m_LSL_Functions.llLinksetDataWrite(name, value); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_Integer llLinksetDataWriteProtected(LSL_String name, LSL_String value, LSL_String pass) + { + return m_LSL_Functions.llLinksetDataWriteProtected(name, value, pass); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_Integer llLinksetDataAvailable() + { + return m_LSL_Functions.llLinksetDataAvailable(); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public void llLinksetDataReset() + { + m_LSL_Functions.llLinksetDataReset(); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_Integer llLinksetDataCountKeys() + { + return m_LSL_Functions.llLinksetDataCountKeys(); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_Integer llLinksetDataDelete(LSL_String name) + { + return m_LSL_Functions.llLinksetDataDelete(name); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_Integer llLinksetDataDeleteProtected(LSL_String name, LSL_String pass) + { + return m_LSL_Functions.llLinksetDataDeleteProtected(name, pass); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_List llLinksetDataFindKeys(LSL_String pattern, LSL_Integer start, LSL_Integer count) + { + return m_LSL_Functions.llLinksetDataFindKeys(pattern, start,count); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_List llLinksetDataListKeys(LSL_Integer start, LSL_Integer count) + { + return m_LSL_Functions.llLinksetDataListKeys(start,count); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_String llLinksetDataRead(LSL_String name) + { + return m_LSL_Functions.llLinksetDataRead(name); + } + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + public LSL_String llLinksetDataReadProtected(LSL_String name, LSL_String pass) + { + return m_LSL_Functions.llLinksetDataReadProtected(name, pass); + } + + public LSL_Integer llLinksetDataCountFound(LSL_String pattern) + { + return m_LSL_Functions.llLinksetDataCountFound(pattern); + } + + public LSL_List llLinksetDataDeleteFound(LSL_String pattern, LSL_String pass) + { + return m_LSL_Functions.llLinksetDataDeleteFound(pattern, pass); + } + } } diff --git a/OpenSim/Region/ScriptEngine/YEngine/MMRIEventHandlers.cs b/OpenSim/Region/ScriptEngine/YEngine/MMRIEventHandlers.cs index 905a23072fd..82d859676d8 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/MMRIEventHandlers.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/MMRIEventHandlers.cs @@ -74,5 +74,6 @@ public interface IEventHandlers void transaction_result(string id, int success, string data); void path_update(int type, LSL_List data); void region_cross(LSL_Vector newpos, LSL_Vector oldpos); + void linkset_data(LSL_Integer action, string name, string value); } } diff --git a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs index 775e0a6a629..b854437df1b 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs @@ -83,8 +83,9 @@ public enum ScriptEventCode: int http_request = 38, // path_update = 40, + linkset_data = 41, // marks highest numbered event - Size = 41 + Size = 42 } } diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs b/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs index fdbe207850f..59b40d52261 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs @@ -935,11 +935,11 @@ public bool PostObjectEvent(uint localID, EventParams parms) TraceCalls("[YEngine]: YEngine.PostObjectEvent({0},{1})", localID.ToString(), parms.EventName); - // In SecondLife, attach events go to all scripts of all prims + // In SecondLife, attach and linkset_data events go to all scripts of all prims // in a linked object. So here we duplicate that functionality, // as all we ever get is a single attach event for the whole // object. - if(parms.EventName == "attach") + if ((parms.EventName == "attach") || (parms.EventName == "linkset_data")) { bool posted = false; foreach(SceneObjectPart primpart in part.ParentGroup.Parts) diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs index ffb15b6d2e5..36d62e315ac 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs @@ -241,7 +241,8 @@ public partial class XMRInstance: XMRInstAbstract, IDisposable {"on_rez", ScriptEventCode.on_rez}, {"sensor", ScriptEventCode.sensor}, {"http_request", ScriptEventCode.http_request}, - {"path_update", ScriptEventCode.path_update} + {"path_update", ScriptEventCode.path_update}, + {"linkset_data", ScriptEventCode.linkset_data} }; } } diff --git a/addon-modules/Gloebit/GloebitMoneyModule/GloebitMoneyModule.cs b/addon-modules/Gloebit/GloebitMoneyModule/GloebitMoneyModule.cs index 8abd4c19b60..9c181966a92 100644 --- a/addon-modules/Gloebit/GloebitMoneyModule/GloebitMoneyModule.cs +++ b/addon-modules/Gloebit/GloebitMoneyModule/GloebitMoneyModule.cs @@ -725,17 +725,6 @@ public void PostInitialise() // 0.9.0.1, 0.9.0.2, etc. detectedOSVersion = "=>0.9.0.1"; m_newLandPassFlow = true; - } else { - // Need to pull version flavour and check it. - // TODO: may need to split on spaces or hyphens and then pull last field because flavour is not friggin public - char[] dChars = { '-', ' ' }; - string[] versionParts = m_opensimVersion.Split(dChars, System.StringSplitOptions.RemoveEmptyEntries); - string flavour = versionParts[versionParts.Length - 1]; // TODO: do we every have to worry about this being length 0? - if (flavour == OpenSim.VersionInfo.Flavour.Release.ToString()) { - // 0.9.0 release - detectedOSVersion = "=0.9.0"; - m_newLandPassFlow = true; - } } // TODO: Unclear if post-fixes is a necessary flavour check yet. } else { diff --git a/addon-modules/OpenSim.Data.MySQL.MoneyData/OpenSim.Data.MySQL.MoneyData/OpenSim.Data.MySQL.MoneyData.csproj b/addon-modules/OpenSim.Data.MySQL.MoneyData/OpenSim.Data.MySQL.MoneyData/OpenSim.Data.MySQL.MoneyData.csproj index 2285e1edf4f..1cd26b1d009 100644 --- a/addon-modules/OpenSim.Data.MySQL.MoneyData/OpenSim.Data.MySQL.MoneyData/OpenSim.Data.MySQL.MoneyData.csproj +++ b/addon-modules/OpenSim.Data.MySQL.MoneyData/OpenSim.Data.MySQL.MoneyData/OpenSim.Data.MySQL.MoneyData.csproj @@ -10,6 +10,7 @@ + diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index d3c31e447d1..e2114ca3ae7 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1017,6 +1017,12 @@ ;; Increasing this to large values potentially opens ;; up the system to malicious scripters ; NotecardLineReadCharsMax = 255 + + ; llGetWallclock returns a float that is the time in seconds since midnight Pacific time (PST/PDT), truncated to whole seconds. + ; How you specify that time zone varies based on system type (Linux, Windows or Mac). If this value is not set (the default) + ; we will return whatever the system time is. You can define the timezone id for PST if you prefer that behaviour. + ; Normal default for Linux is "America/Los_Angeles" from the ICU database and for Windows is: "Pacific Standard Time" + ; GetWallclockTimeZone = "America/Los_Angeles" ;# {SensorMaxRange} {} {Sensor range} {} 96.0 ;; Sensor settings @@ -1131,6 +1137,12 @@ ;# {SensorMaxResults} {} {Max sensor results returned?} {} ; SensorMaxResults = 16 + ; llGetWallclock returns a float that is the time in seconds since midnight Pacific time (PST/PDT), truncated to whole seconds. + ; How you specify that time zone varies based on system type (Linux, Windows or Mac). If this value is not set (the default) + ; we will return whatever the system time is. You can define the timezone id for PST if you prefer that behaviour. + ; Normal default for Linux is "America/Los_Angeles" from the ICU database and for Windows is: "Pacific Standard Time" + ; GetWallclockTimeZone = "America/Los_Angeles" + ;# {DisableUndergroundMovement} {} {Disable underground movement of prims} {true false} true ;; Disable underground movement of prims (default true); set to ;; false to allow script controlled underground positioning of @@ -1147,7 +1159,6 @@ ;; If this INI file is not included, the OSSL functions are disabled. Include-osslDefaultEnable = "config-include/osslDefaultEnable.ini" - [FreeSwitchVoice] ;; In order for this to work you need a functioning FreeSWITCH PBX set up. ;; Configuration details at http://opensimulator.org/wiki/Freeswitch_Module diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 3fc3c637f28..c03850a6548 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1783,6 +1783,11 @@ ; prims ; DisableUndergroundMovement = true + ; llGetWallclock returns a float that is the time in seconds since midnight Pacific time (PST/PDT), truncated to whole seconds. + ; How you specify that time zone varies based on system type (Linux, Windows or Mac). If this value is not set (the default) + ; we will return whatever the system time is. You can define the timezone id for PST if you prefer that behaviour. + ; Normal default for Linux is "America/Los_Angeles" from the ICU database and for Windows is: "Pacific Standard Time" + ; GetWallclockTimeZone = "America/Los_Angeles" ; scripts states and cache parent folder location ;ScriptEnginesPath="ScriptEngines" @@ -1830,7 +1835,6 @@ ; This does not delete cached scripts state. ; DeleteScriptsOnStartup = true - ; Controls whether scripts are stopped by aborting their threads externally (abort) ; or by co-operative checks inserted by OpenSimulator into compiled script (co-op). ; co-op will be more stable as aborting threads can cause instability. @@ -1849,7 +1853,6 @@ ; Compile debug info (line numbers) into the script assemblies CompileWithDebugInformation = true - ; Interval (s) between background save of script states SaveInterval = 120 @@ -1881,6 +1884,12 @@ ; rounded up to this minimum interval. ; MinTimerInterval = 0.5 + ; llGetWallclock returns a float that is the time in seconds since midnight Pacific time (PST/PDT), truncated to whole seconds. + ; How you specify that time zone varies based on system type (Linux, Windows or Mac). If this value is not set (the default) + ; we will return whatever the system time is. You can define the timezone id for PST if you prefer that behaviour. + ; Normal default for Linux is "America/Los_Angeles" from the ICU database and for Windows is: "Pacific Standard Time" + ; GetWallclockTimeZone = "America/Los_Angeles" + ; Sensor settings ;SensorMaxRange = 96.0 ;SensorMaxResults = 16 diff --git a/bin/ScriptSyntax.xml b/bin/ScriptSyntax.xml index d10146dd619..249495ab2fe 100644 --- a/bin/ScriptSyntax.xml +++ b/bin/ScriptSyntax.xml @@ -1,4 +1,4 @@ -face0493-6022-3cf1-bdbe-1ae375f7f2da +f0eb469c-b2f3-4d64-802a-1ac709cb91e6 llsd-lsl-syntax-version2 controls @@ -311,6 +311,31 @@ face0493-6022-3cf1-bdbe-1ae375f7f2da tooltipTriggered by llTransferMoney() function + linkset_data + arguments + + action + + type + integer + + + + name + + type + string + + + + value + + type + string + + + + constants @@ -3461,6 +3486,76 @@ face0493-6022-3cf1-bdbe-1ae375f7f2da typevector value>0.0,0.0,0.0< + LINKSETDATA_OK + + type + integer + value + 0 + + LINKSETDATA_EMEMORY + + type + integer + value + 1 + + LINKSETDATA_ENOKEY + + type + integer + value + 2 + + LINKSETDATA_EPROTECTED + + type + integer + value + 3 + + LINKSETDATA_NOTFOUND + + type + integer + value + 4 + + LINKSETDATA_NOUPDATE + + type + integer + value + 5 + + LINKSETDATA_RESET + + type + integer + value + 0 + + LINKSETDATA_UPDATE + + type + integer + value + 1 + + LINKSETDATA_DELETE + + type + integer + value + 2 + + LINKSETDATA_MULTIDELETE + + type + integer + value + 3 + functions @@ -4852,6 +4947,231 @@ face0493-6022-3cf1-bdbe-1ae375f7f2da volumetypefloat + llLinksetDataWrite + + return + integer + arguments + + + name + + type + string + + + + value + + type + string + + + + + llLinksetDataWriteProtected + + return + integer + arguments + + + name + + type + string + + + + value + + type + string + + + + pass + + type + string + + + + + llLinksetDataRead + + return + string + arguments + + + name + + type + string + + + + + llLinksetDataReadProtected + + return + string + arguments + + + name + + type + string + + + + pass + + type + string + + + + + llLinksetDataDelete + + arguments + + + name + + type + string + + + + + llLinksetDataDeleteProtected + + arguments + + + name + + type + string + + + + pass + + type + string + + + + + llLinksetDataDeleteFound + + return + integer + arguments + + + pattern + + type + string + + + + pass + + type + string + + + + + llLinksetDataReset + + arguments + + llLinksetDataAvailable + + return + integer + arguments + + llLinksetDataCountKeys + + return + integer + arguments + + llLinksetDataCountFound + + return + integer + arguments + + + pattern + + type + string + + + + + llLinksetDataListKeys + + return + list + arguments + + + first + + type + integer + + + + count + + type + integer + + + + + llLinksetDataFindKeys + + return + list + arguments + + + regex + + type + string + + + + first + + type + integer + + + + count + + type + integer + + + + llLinkSetSoundQueueing arguments