aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2013-02-05 00:35:15 +0000
committerJustin Clark-Casey (justincc)2013-02-05 00:35:15 +0000
commit1fc9f282fa7d3b8efa54a27a25b0916e82d62f61 (patch)
treef220060baa0f8eeedd4a7af23dbdd371e260b57b /OpenSim
parentBump version and assembly version numbers from 0.7.5 to 0.7.6 (diff)
parentRemove the accidental PrimShapes column that I added back to the SQLite regio... (diff)
downloadopensim-SC-1fc9f282fa7d3b8efa54a27a25b0916e82d62f61.zip
opensim-SC-1fc9f282fa7d3b8efa54a27a25b0916e82d62f61.tar.gz
opensim-SC-1fc9f282fa7d3b8efa54a27a25b0916e82d62f61.tar.bz2
opensim-SC-1fc9f282fa7d3b8efa54a27a25b0916e82d62f61.tar.xz
Merge branch 'dynamic-attributes2'
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Data/MSSQL/MSSQLSimulationData.cs18
-rw-r--r--OpenSim/Data/MSSQL/Resources/RegionStore.migrations8
-rw-r--r--OpenSim/Data/MySQL/MySQLSimulationData.cs19
-rw-r--r--OpenSim/Data/MySQL/Resources/RegionStore.migrations8
-rw-r--r--OpenSim/Data/SQLite/Resources/RegionStore.migrations5
-rw-r--r--OpenSim/Data/SQLite/SQLiteSimulationData.cs19
-rw-r--r--OpenSim/Framework/DAMap.cs260
-rw-r--r--OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs107
-rw-r--r--OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs37
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs14
11 files changed, 496 insertions, 10 deletions
diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
index 17f42e1..276a190 100644
--- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
@@ -351,7 +351,7 @@ IF EXISTS (SELECT UUID FROM prims WHERE UUID = @UUID)
351 ScriptAccessPin = @ScriptAccessPin, AllowedDrop = @AllowedDrop, DieAtEdge = @DieAtEdge, SalePrice = @SalePrice, 351 ScriptAccessPin = @ScriptAccessPin, AllowedDrop = @AllowedDrop, DieAtEdge = @DieAtEdge, SalePrice = @SalePrice,
352 SaleType = @SaleType, ColorR = @ColorR, ColorG = @ColorG, ColorB = @ColorB, ColorA = @ColorA, ParticleSystem = @ParticleSystem, 352 SaleType = @SaleType, ColorR = @ColorR, ColorG = @ColorG, ColorB = @ColorB, ColorA = @ColorA, ParticleSystem = @ParticleSystem,
353 ClickAction = @ClickAction, Material = @Material, CollisionSound = @CollisionSound, CollisionSoundVolume = @CollisionSoundVolume, PassTouches = @PassTouches, 353 ClickAction = @ClickAction, Material = @Material, CollisionSound = @CollisionSound, CollisionSoundVolume = @CollisionSoundVolume, PassTouches = @PassTouches,
354 LinkNumber = @LinkNumber, MediaURL = @MediaURL 354 LinkNumber = @LinkNumber, MediaURL = @MediaURL, DynAttrs = @DynAttrs
355 WHERE UUID = @UUID 355 WHERE UUID = @UUID
356 END 356 END
357ELSE 357ELSE
@@ -366,7 +366,7 @@ ELSE
366 PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, LoopedSound, LoopedSoundGain, TextureAnimation, OmegaX, 366 PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, LoopedSound, LoopedSoundGain, TextureAnimation, OmegaX,
367 OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ, 367 OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ,
368 ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA, 368 ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA,
369 ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL 369 ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL, DynAttrs
370 ) VALUES ( 370 ) VALUES (
371 @UUID, @CreationDate, @Name, @Text, @Description, @SitName, @TouchName, @ObjectFlags, @OwnerMask, @NextOwnerMask, @GroupMask, 371 @UUID, @CreationDate, @Name, @Text, @Description, @SitName, @TouchName, @ObjectFlags, @OwnerMask, @NextOwnerMask, @GroupMask,
372 @EveryoneMask, @BaseMask, @PositionX, @PositionY, @PositionZ, @GroupPositionX, @GroupPositionY, @GroupPositionZ, @VelocityX, 372 @EveryoneMask, @BaseMask, @PositionX, @PositionY, @PositionZ, @GroupPositionX, @GroupPositionY, @GroupPositionZ, @VelocityX,
@@ -376,7 +376,7 @@ ELSE
376 @PayPrice, @PayButton1, @PayButton2, @PayButton3, @PayButton4, @LoopedSound, @LoopedSoundGain, @TextureAnimation, @OmegaX, 376 @PayPrice, @PayButton1, @PayButton2, @PayButton3, @PayButton4, @LoopedSound, @LoopedSoundGain, @TextureAnimation, @OmegaX,
377 @OmegaY, @OmegaZ, @CameraEyeOffsetX, @CameraEyeOffsetY, @CameraEyeOffsetZ, @CameraAtOffsetX, @CameraAtOffsetY, @CameraAtOffsetZ, 377 @OmegaY, @OmegaZ, @CameraEyeOffsetX, @CameraEyeOffsetY, @CameraEyeOffsetZ, @CameraAtOffsetX, @CameraAtOffsetY, @CameraAtOffsetZ,
378 @ForceMouselook, @ScriptAccessPin, @AllowedDrop, @DieAtEdge, @SalePrice, @SaleType, @ColorR, @ColorG, @ColorB, @ColorA, 378 @ForceMouselook, @ScriptAccessPin, @AllowedDrop, @DieAtEdge, @SalePrice, @SaleType, @ColorR, @ColorG, @ColorB, @ColorA,
379 @ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL 379 @ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL, @DynAttrs
380 ) 380 )
381 END"; 381 END";
382 382
@@ -1691,6 +1691,11 @@ VALUES
1691 1691
1692 if (!(primRow["MediaURL"] is System.DBNull)) 1692 if (!(primRow["MediaURL"] is System.DBNull))
1693 prim.MediaUrl = (string)primRow["MediaURL"]; 1693 prim.MediaUrl = (string)primRow["MediaURL"];
1694
1695 if (!(primRow["DynAttrs"] is System.DBNull))
1696 prim.DynAttrs = DAMap.FromXml((string)primRow["DynAttrs"]);
1697 else
1698 prim.DynAttrs = new DAMap();
1694 1699
1695 return prim; 1700 return prim;
1696 } 1701 }
@@ -1749,7 +1754,6 @@ VALUES
1749 baseShape.Media = PrimitiveBaseShape.MediaList.FromXml((string)shapeRow["Media"]); 1754 baseShape.Media = PrimitiveBaseShape.MediaList.FromXml((string)shapeRow["Media"]);
1750 } 1755 }
1751 1756
1752
1753 return baseShape; 1757 return baseShape;
1754 } 1758 }
1755 1759
@@ -2086,6 +2090,11 @@ VALUES
2086 parameters.Add(_Database.CreateParameter("PassTouches", 0)); 2090 parameters.Add(_Database.CreateParameter("PassTouches", 0));
2087 parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum)); 2091 parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum));
2088 parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl)); 2092 parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl));
2093
2094 if (prim.DynAttrs.Count > 0)
2095 parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml()));
2096 else
2097 parameters.Add(_Database.CreateParameter("DynAttrs", null));
2089 2098
2090 return parameters.ToArray(); 2099 return parameters.ToArray();
2091 } 2100 }
@@ -2143,7 +2152,6 @@ VALUES
2143 parameters.Add(_Database.CreateParameter("Media", s.Media.ToXml())); 2152 parameters.Add(_Database.CreateParameter("Media", s.Media.ToXml()));
2144 } 2153 }
2145 2154
2146
2147 return parameters.ToArray(); 2155 return parameters.ToArray();
2148 } 2156 }
2149 2157
diff --git a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
index 350e548..92cc38a 100644
--- a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
+++ b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
@@ -1148,3 +1148,11 @@ CREATE TABLE [dbo].[regionenvironment](
1148) ON [PRIMARY] 1148) ON [PRIMARY]
1149 1149
1150COMMIT 1150COMMIT
1151
1152:VERSION 38 #---------------- Dynamic attributes
1153
1154BEGIN TRANSACTION
1155
1156ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
1157
1158COMMIT
diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs
index d562783..c95311e 100644
--- a/OpenSim/Data/MySQL/MySQLSimulationData.cs
+++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs
@@ -171,7 +171,8 @@ namespace OpenSim.Data.MySQL
171 "ParticleSystem, ClickAction, Material, " + 171 "ParticleSystem, ClickAction, Material, " +
172 "CollisionSound, CollisionSoundVolume, " + 172 "CollisionSound, CollisionSoundVolume, " +
173 "PassTouches, " + 173 "PassTouches, " +
174 "LinkNumber, MediaURL) values (" + "?UUID, " + 174 "LinkNumber, MediaURL, DynAttrs) " +
175 "values (?UUID, " +
175 "?CreationDate, ?Name, ?Text, " + 176 "?CreationDate, ?Name, ?Text, " +
176 "?Description, ?SitName, ?TouchName, " + 177 "?Description, ?SitName, ?TouchName, " +
177 "?ObjectFlags, ?OwnerMask, ?NextOwnerMask, " + 178 "?ObjectFlags, ?OwnerMask, ?NextOwnerMask, " +
@@ -202,7 +203,8 @@ namespace OpenSim.Data.MySQL
202 "?SaleType, ?ColorR, ?ColorG, " + 203 "?SaleType, ?ColorR, ?ColorG, " +
203 "?ColorB, ?ColorA, ?ParticleSystem, " + 204 "?ColorB, ?ColorA, ?ParticleSystem, " +
204 "?ClickAction, ?Material, ?CollisionSound, " + 205 "?ClickAction, ?Material, ?CollisionSound, " +
205 "?CollisionSoundVolume, ?PassTouches, ?LinkNumber, ?MediaURL)"; 206 "?CollisionSoundVolume, ?PassTouches, ?LinkNumber, " +
207 "?MediaURL, ?DynAttrs)";
206 208
207 FillPrimCommand(cmd, prim, obj.UUID, regionUUID); 209 FillPrimCommand(cmd, prim, obj.UUID, regionUUID);
208 210
@@ -219,7 +221,8 @@ namespace OpenSim.Data.MySQL
219 "PathTaperX, PathTaperY, PathTwist, " + 221 "PathTaperX, PathTaperY, PathTwist, " +
220 "PathTwistBegin, ProfileBegin, ProfileEnd, " + 222 "PathTwistBegin, ProfileBegin, ProfileEnd, " +
221 "ProfileCurve, ProfileHollow, Texture, " + 223 "ProfileCurve, ProfileHollow, Texture, " +
222 "ExtraParams, State, Media) values (?UUID, " + 224 "ExtraParams, State, Media) " +
225 "values (?UUID, " +
223 "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " + 226 "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " +
224 "?PCode, ?PathBegin, ?PathEnd, " + 227 "?PCode, ?PathBegin, ?PathEnd, " +
225 "?PathScaleX, ?PathScaleY, " + 228 "?PathScaleX, ?PathScaleY, " +
@@ -1291,6 +1294,11 @@ namespace OpenSim.Data.MySQL
1291 1294
1292 if (!(row["MediaURL"] is System.DBNull)) 1295 if (!(row["MediaURL"] is System.DBNull))
1293 prim.MediaUrl = (string)row["MediaURL"]; 1296 prim.MediaUrl = (string)row["MediaURL"];
1297
1298 if (!(row["DynAttrs"] is System.DBNull))
1299 prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]);
1300 else
1301 prim.DynAttrs = new DAMap();
1294 1302
1295 return prim; 1303 return prim;
1296 } 1304 }
@@ -1637,6 +1645,11 @@ namespace OpenSim.Data.MySQL
1637 1645
1638 cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum); 1646 cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum);
1639 cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl); 1647 cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl);
1648
1649 if (prim.DynAttrs.Count > 0)
1650 cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml());
1651 else
1652 cmd.Parameters.AddWithValue("DynAttrs", null);
1640 } 1653 }
1641 1654
1642 /// <summary> 1655 /// <summary>
diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations
index 5b59779..c48aec2 100644
--- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations
+++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations
@@ -902,3 +902,11 @@ BEGIN;
902CREATE TABLE `regionextra` (`RegionID` char(36) not null, `Name` varchar(32) not null, `value` text, primary key(`RegionID`, `Name`)); 902CREATE TABLE `regionextra` (`RegionID` char(36) not null, `Name` varchar(32) not null, `value` text, primary key(`RegionID`, `Name`));
903 903
904COMMIT; 904COMMIT;
905
906:VERSION 46 #---------------- Dynamic attributes
907
908BEGIN;
909
910ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
911
912COMMIT;
diff --git a/OpenSim/Data/SQLite/Resources/RegionStore.migrations b/OpenSim/Data/SQLite/Resources/RegionStore.migrations
index e872977..e583dc2 100644
--- a/OpenSim/Data/SQLite/Resources/RegionStore.migrations
+++ b/OpenSim/Data/SQLite/Resources/RegionStore.migrations
@@ -575,3 +575,8 @@ CREATE TABLE `regionenvironment` (
575); 575);
576 576
577COMMIT; 577COMMIT;
578
579:VERSION 27
580BEGIN;
581ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
582COMMIT;
diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
index 29cac3c..91fc704 100644
--- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs
+++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
@@ -1232,6 +1232,8 @@ namespace OpenSim.Data.SQLite
1232 createCol(prims, "VolumeDetect", typeof(Int16)); 1232 createCol(prims, "VolumeDetect", typeof(Int16));
1233 1233
1234 createCol(prims, "MediaURL", typeof(String)); 1234 createCol(prims, "MediaURL", typeof(String));
1235
1236 createCol(prims, "DynAttrs", typeof(String));
1235 1237
1236 // Add in contraints 1238 // Add in contraints
1237 prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] }; 1239 prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] };
@@ -1711,6 +1713,16 @@ namespace OpenSim.Data.SQLite
1711// m_log.DebugFormat("[SQLITE]: MediaUrl type [{0}]", row["MediaURL"].GetType()); 1713// m_log.DebugFormat("[SQLITE]: MediaUrl type [{0}]", row["MediaURL"].GetType());
1712 prim.MediaUrl = (string)row["MediaURL"]; 1714 prim.MediaUrl = (string)row["MediaURL"];
1713 } 1715 }
1716
1717 if (!(row["DynAttrs"] is System.DBNull))
1718 {
1719 //m_log.DebugFormat("[SQLITE]: DynAttrs type [{0}]", row["DynAttrs"].GetType());
1720 prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]);
1721 }
1722 else
1723 {
1724 prim.DynAttrs = new DAMap();
1725 }
1714 1726
1715 return prim; 1727 return prim;
1716 } 1728 }
@@ -2133,6 +2145,11 @@ namespace OpenSim.Data.SQLite
2133 row["VolumeDetect"] = 0; 2145 row["VolumeDetect"] = 0;
2134 2146
2135 row["MediaURL"] = prim.MediaUrl; 2147 row["MediaURL"] = prim.MediaUrl;
2148
2149 if (prim.DynAttrs.Count > 0)
2150 row["DynAttrs"] = prim.DynAttrs.ToXml();
2151 else
2152 row["DynAttrs"] = null;
2136 } 2153 }
2137 2154
2138 /// <summary> 2155 /// <summary>
@@ -2392,7 +2409,7 @@ namespace OpenSim.Data.SQLite
2392 2409
2393 if (!(row["Media"] is System.DBNull)) 2410 if (!(row["Media"] is System.DBNull))
2394 s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]); 2411 s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]);
2395 2412
2396 return s; 2413 return s;
2397 } 2414 }
2398 2415
diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs
new file mode 100644
index 0000000..291c8b8
--- /dev/null
+++ b/OpenSim/Framework/DAMap.cs
@@ -0,0 +1,260 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Text;
33using System.Xml;
34using System.Xml.Schema;
35using System.Xml.Serialization;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38
39namespace OpenSim.Framework
40{
41 /// <summary>
42 /// This class stores and retrieves dynamic attributes.
43 /// </summary>
44 /// <remarks>
45 /// Modules that want to use dynamic attributes need to do so in a private data store
46 /// which is accessed using a unique name. DAMap provides access to the data stores,
47 /// each of which is an OSDMap. Modules are free to store any type of data they want
48 /// within their data store. However, avoid storing large amounts of data because that
49 /// would slow down database access.
50 /// </remarks>
51 public class DAMap : IDictionary<string, OSDMap>, IXmlSerializable
52 {
53 private static readonly int MIN_STORE_NAME_LENGTH = 4;
54
55 protected OSDMap m_map;
56
57 public DAMap() { m_map = new OSDMap(); }
58
59 public XmlSchema GetSchema() { return null; }
60
61 public static DAMap FromXml(string rawXml)
62 {
63 DAMap map = new DAMap();
64 map.ReadXml(rawXml);
65 return map;
66 }
67
68 public void ReadXml(string rawXml)
69 {
70 // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml);
71
72 lock (this)
73 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml);
74 }
75
76 public void ReadXml(XmlReader reader)
77 {
78 ReadXml(reader.ReadInnerXml());
79 }
80
81 public string ToXml()
82 {
83 lock (this)
84 return OSDParser.SerializeLLSDXmlString(m_map);
85 }
86
87 public void WriteXml(XmlWriter writer)
88 {
89 writer.WriteRaw(ToXml());
90 }
91
92 public void CopyFrom(DAMap other)
93 {
94 // Deep copy
95
96 string data = null;
97 lock (other)
98 {
99 if (other.Count > 0)
100 {
101 data = OSDParser.SerializeLLSDXmlString(other.m_map);
102 }
103 }
104
105 lock (this)
106 {
107 if (data == null)
108 Clear();
109 else
110 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(data);
111 }
112 }
113
114 /// <summary>
115 /// Returns the number of data stores.
116 /// </summary>
117 public int Count { get { lock (this) { return m_map.Count; } } }
118
119 public bool IsReadOnly { get { return false; } }
120
121 /// <summary>
122 /// Returns the names of the data stores.
123 /// </summary>
124 public ICollection<string> Keys { get { lock (this) { return m_map.Keys; } } }
125
126 /// <summary>
127 /// Returns all the data stores.
128 /// </summary>
129 public ICollection<OSDMap> Values
130 {
131 get
132 {
133 lock (this)
134 {
135 List<OSDMap> stores = new List<OSDMap>(m_map.Count);
136 foreach (OSD llsd in m_map.Values)
137 stores.Add((OSDMap)llsd);
138 return stores;
139 }
140 }
141 }
142
143 /// <summary>
144 /// Gets or sets one data store.
145 /// </summary>
146 /// <param name="key">Store name</param>
147 /// <returns></returns>
148 public OSDMap this[string key]
149 {
150 get
151 {
152 OSD llsd;
153
154 lock (this)
155 {
156 if (m_map.TryGetValue(key, out llsd))
157 return (OSDMap)llsd;
158 else
159 return null;
160 }
161 }
162
163 set
164 {
165 ValidateKey(key);
166 lock (this)
167 m_map[key] = value;
168 }
169 }
170
171 private static void ValidateKey(string key)
172 {
173 if (key.Length < MIN_STORE_NAME_LENGTH)
174 throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH);
175 }
176
177 public bool ContainsKey(string key)
178 {
179 lock (this)
180 return m_map.ContainsKey(key);
181 }
182
183 public void Add(string key, OSDMap store)
184 {
185 ValidateKey(key);
186 lock (this)
187 m_map.Add(key, store);
188 }
189
190 public void Add(KeyValuePair<string, OSDMap> kvp)
191 {
192 lock (this)
193 m_map.Add(kvp.Key, kvp.Value);
194 }
195
196 public bool Remove(string key)
197 {
198 lock (this)
199 return m_map.Remove(key);
200 }
201
202 public bool TryGetValue(string key, out OSDMap store)
203 {
204 lock (this)
205 {
206 OSD llsd;
207 if (m_map.TryGetValue(key, out llsd))
208 {
209 store = (OSDMap)llsd;
210 return true;
211 }
212 else
213 {
214 store = null;
215 return false;
216 }
217 }
218 }
219
220 public void Clear()
221 {
222 lock (this)
223 m_map.Clear();
224 }
225
226 public bool Contains(KeyValuePair<string, OSDMap> kvp)
227 {
228 lock (this)
229 return m_map.ContainsKey(kvp.Key);
230 }
231
232 public void CopyTo(KeyValuePair<string, OSDMap>[] array, int index)
233 {
234 throw new NotImplementedException();
235 }
236
237 public bool Remove(KeyValuePair<string, OSDMap> kvp)
238 {
239 lock (this)
240 return m_map.Remove(kvp.Key);
241 }
242
243 public System.Collections.IDictionaryEnumerator GetEnumerator()
244 {
245 lock (this)
246 return m_map.GetEnumerator();
247 }
248
249 IEnumerator<KeyValuePair<string, OSDMap>> IEnumerable<KeyValuePair<string, OSDMap>>.GetEnumerator()
250 {
251 return null;
252 }
253
254 IEnumerator IEnumerable.GetEnumerator()
255 {
256 lock (this)
257 return m_map.GetEnumerator();
258 }
259 }
260} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
new file mode 100644
index 0000000..d36f65a
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs
@@ -0,0 +1,107 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
45 public class DAExampleModule : INonSharedRegionModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private static readonly bool ENABLED = false; // enable for testing
50
51 protected Scene m_scene;
52 protected IDialogModule m_dialogMod;
53
54 public string Name { get { return "DAExample Module"; } }
55 public Type ReplaceableInterface { get { return null; } }
56
57 public void Initialise(IConfigSource source) {}
58
59 public void AddRegion(Scene scene)
60 {
61 if (ENABLED)
62 {
63 m_scene = scene;
64 m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove;
65 m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>();
66 }
67 }
68
69 public void RemoveRegion(Scene scene)
70 {
71 if (ENABLED)
72 {
73 m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove;
74 }
75 }
76
77 public void RegionLoaded(Scene scene) {}
78
79 public void Close()
80 {
81 RemoveRegion(m_scene);
82 }
83
84 protected bool OnSceneGroupMove(UUID groupId, Vector3 delta)
85 {
86 OSDMap attrs = null;
87 SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId);
88 if (!sop.DynAttrs.TryGetValue(Name, out attrs))
89 attrs = new OSDMap();
90
91 OSDInteger newValue;
92
93 if (!attrs.ContainsKey("moves"))
94 newValue = new OSDInteger(1);
95 else
96 newValue = new OSDInteger(((OSDInteger)attrs["moves"]).AsInteger() + 1);
97
98 attrs["moves"] = newValue;
99
100 sop.DynAttrs[Name] = attrs;
101
102 m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue));
103
104 return true;
105 }
106 }
107} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
index bcb8e2f..b4348c9 100644
--- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
+++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs
@@ -35,6 +35,7 @@ using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Scenes.Serialization; 36using OpenSim.Region.Framework.Scenes.Serialization;
37using OpenSim.Tests.Common; 37using OpenSim.Tests.Common;
38using OpenMetaverse.StructuredData;
38 39
39namespace OpenSim.Region.CoreModules.World.Serialiser.Tests 40namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
40{ 41{
@@ -143,6 +144,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
143 <Flags>None</Flags> 144 <Flags>None</Flags>
144 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound> 145 <CollisionSound><Guid>00000000-0000-0000-0000-000000000000</Guid></CollisionSound>
145 <CollisionSoundVolume>0</CollisionSoundVolume> 146 <CollisionSoundVolume>0</CollisionSoundVolume>
147 <DynAttrs><llsd><map><key>MyStore</key><map><key>the answer</key><integer>42</integer></map></map></llsd></DynAttrs>
146 </SceneObjectPart> 148 </SceneObjectPart>
147 </RootPart> 149 </RootPart>
148 <OtherParts /> 150 <OtherParts />
@@ -331,6 +333,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
331 <EveryoneMask>0</EveryoneMask> 333 <EveryoneMask>0</EveryoneMask>
332 <NextOwnerMask>2147483647</NextOwnerMask> 334 <NextOwnerMask>2147483647</NextOwnerMask>
333 <Flags>None</Flags> 335 <Flags>None</Flags>
336 <DynAttrs><llsd><map><key>MyStore</key><map><key>last words</key><string>Rosebud</string></map></map></llsd></DynAttrs>
334 <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar> 337 <SitTargetAvatar><UUID>00000000-0000-0000-0000-000000000000</UUID></SitTargetAvatar>
335 </SceneObjectPart> 338 </SceneObjectPart>
336 <OtherParts /> 339 <OtherParts />
@@ -359,6 +362,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
359 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); 362 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790")));
360 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); 363 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d")));
361 Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); 364 Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide"));
365 OSDMap store = rootPart.DynAttrs["MyStore"];
366 Assert.AreEqual(42, store["the answer"].AsInteger());
362 367
363 // TODO: Check other properties 368 // TODO: Check other properties
364 } 369 }
@@ -409,6 +414,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
409 rp.CreatorID = rpCreatorId; 414 rp.CreatorID = rpCreatorId;
410 rp.Shape = shape; 415 rp.Shape = shape;
411 416
417 string daStoreName = "MyStore";
418 string daKey = "foo";
419 string daValue = "bar";
420 OSDMap myStore = new OSDMap();
421 myStore.Add(daKey, daValue);
422 rp.DynAttrs = new DAMap();
423 rp.DynAttrs[daStoreName] = myStore;
424
412 SceneObjectGroup so = new SceneObjectGroup(rp); 425 SceneObjectGroup so = new SceneObjectGroup(rp);
413 426
414 // Need to add the object to the scene so that the request to get script state succeeds 427 // Need to add the object to the scene so that the request to get script state succeeds
@@ -424,6 +437,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
424 UUID uuid = UUID.Zero; 437 UUID uuid = UUID.Zero;
425 string name = null; 438 string name = null;
426 UUID creatorId = UUID.Zero; 439 UUID creatorId = UUID.Zero;
440 DAMap daMap = null;
427 441
428 while (xtr.Read() && xtr.Name != "SceneObjectPart") 442 while (xtr.Read() && xtr.Name != "SceneObjectPart")
429 { 443 {
@@ -449,6 +463,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
449 creatorId = UUID.Parse(xtr.ReadElementString("UUID")); 463 creatorId = UUID.Parse(xtr.ReadElementString("UUID"));
450 xtr.ReadEndElement(); 464 xtr.ReadEndElement();
451 break; 465 break;
466 case "DynAttrs":
467 daMap = new DAMap();
468 daMap.ReadXml(xtr);
469 break;
452 } 470 }
453 } 471 }
454 472
@@ -462,6 +480,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
462 Assert.That(uuid, Is.EqualTo(rpUuid)); 480 Assert.That(uuid, Is.EqualTo(rpUuid));
463 Assert.That(name, Is.EqualTo(rpName)); 481 Assert.That(name, Is.EqualTo(rpName));
464 Assert.That(creatorId, Is.EqualTo(rpCreatorId)); 482 Assert.That(creatorId, Is.EqualTo(rpCreatorId));
483 Assert.NotNull(daMap);
484 Assert.AreEqual(daValue, daMap[daStoreName][daKey].AsString());
465 } 485 }
466 486
467 [Test] 487 [Test]
@@ -476,6 +496,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
476 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); 496 Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946")));
477 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); 497 Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef")));
478 Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); 498 Assert.That(rootPart.Name, Is.EqualTo("PrimFun"));
499 OSDMap store = rootPart.DynAttrs["MyStore"];
500 Assert.AreEqual("Rosebud", store["last words"].AsString());
479 501
480 // TODO: Check other properties 502 // TODO: Check other properties
481 } 503 }
@@ -500,6 +522,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
500 rp.CreatorID = rpCreatorId; 522 rp.CreatorID = rpCreatorId;
501 rp.Shape = shape; 523 rp.Shape = shape;
502 524
525 string daStoreName = "MyStore";
526 string daKey = "foo";
527 string daValue = "bar";
528 OSDMap myStore = new OSDMap();
529 myStore.Add(daKey, daValue);
530 rp.DynAttrs = new DAMap();
531 rp.DynAttrs[daStoreName] = myStore;
532
503 SceneObjectGroup so = new SceneObjectGroup(rp); 533 SceneObjectGroup so = new SceneObjectGroup(rp);
504 534
505 // Need to add the object to the scene so that the request to get script state succeeds 535 // Need to add the object to the scene so that the request to get script state succeeds
@@ -516,6 +546,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
516 UUID uuid = UUID.Zero; 546 UUID uuid = UUID.Zero;
517 string name = null; 547 string name = null;
518 UUID creatorId = UUID.Zero; 548 UUID creatorId = UUID.Zero;
549 DAMap daMap = null;
519 550
520 while (xtr.Read() && xtr.Name != "SceneObjectPart") 551 while (xtr.Read() && xtr.Name != "SceneObjectPart")
521 { 552 {
@@ -537,6 +568,10 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
537 creatorId = UUID.Parse(xtr.ReadElementString("Guid")); 568 creatorId = UUID.Parse(xtr.ReadElementString("Guid"));
538 xtr.ReadEndElement(); 569 xtr.ReadEndElement();
539 break; 570 break;
571 case "DynAttrs":
572 daMap = new DAMap();
573 daMap.ReadXml(xtr);
574 break;
540 } 575 }
541 } 576 }
542 577
@@ -549,6 +584,8 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
549 Assert.That(uuid, Is.EqualTo(rpUuid)); 584 Assert.That(uuid, Is.EqualTo(rpUuid));
550 Assert.That(name, Is.EqualTo(rpName)); 585 Assert.That(name, Is.EqualTo(rpName));
551 Assert.That(creatorId, Is.EqualTo(rpCreatorId)); 586 Assert.That(creatorId, Is.EqualTo(rpCreatorId));
587 Assert.NotNull(daMap);
588 Assert.AreEqual(daValue, daMap[daStoreName][daKey].AsString());
552 } 589 }
553 } 590 }
554} \ No newline at end of file 591} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 6720635..189d298 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -37,6 +37,7 @@ using System.Xml.Serialization;
37using log4net; 37using log4net;
38using OpenMetaverse; 38using OpenMetaverse;
39using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
40using OpenMetaverse.StructuredData;
40using OpenSim.Framework; 41using OpenSim.Framework;
41using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes.Scripting; 43using OpenSim.Region.Framework.Scenes.Scripting;
@@ -124,6 +125,11 @@ namespace OpenSim.Region.Framework.Scenes
124 125
125 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 126 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
126 127
128 /// <summary>
129 /// Dynamic attributes can be created and deleted as required.
130 /// </summary>
131 public DAMap DynAttrs { get; set; }
132
127 /// <value> 133 /// <value>
128 /// Is this a root part? 134 /// Is this a root part?
129 /// </value> 135 /// </value>
@@ -335,6 +341,7 @@ namespace OpenSim.Region.Framework.Scenes
335 m_particleSystem = Utils.EmptyBytes; 341 m_particleSystem = Utils.EmptyBytes;
336 Rezzed = DateTime.UtcNow; 342 Rezzed = DateTime.UtcNow;
337 Description = String.Empty; 343 Description = String.Empty;
344 DynAttrs = new DAMap();
338 345
339 // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, 346 // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol,
340 // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from 347 // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from
@@ -1618,6 +1625,8 @@ namespace OpenSim.Region.Framework.Scenes
1618 Array.Copy(Shape.ExtraParams, extraP, extraP.Length); 1625 Array.Copy(Shape.ExtraParams, extraP, extraP.Length);
1619 dupe.Shape.ExtraParams = extraP; 1626 dupe.Shape.ExtraParams = extraP;
1620 1627
1628 dupe.DynAttrs.CopyFrom(DynAttrs);
1629
1621 if (userExposed) 1630 if (userExposed)
1622 { 1631 {
1623/* 1632/*
@@ -4598,4 +4607,4 @@ namespace OpenSim.Region.Framework.Scenes
4598 } 4607 }
4599 } 4608 }
4600 } 4609 }
4601} \ No newline at end of file 4610}
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index 2d4c60a..4a2a47e 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -359,6 +359,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
359 m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound); 359 m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound);
360 m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume); 360 m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume);
361 m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); 361 m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl);
362 m_SOPXmlProcessors.Add("DynAttrs", ProcessDynAttrs);
362 m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); 363 m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation);
363 m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); 364 m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem);
364 m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0); 365 m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0);
@@ -722,6 +723,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
722 obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty); 723 obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty);
723 } 724 }
724 725
726 private static void ProcessDynAttrs(SceneObjectPart obj, XmlTextReader reader)
727 {
728 obj.DynAttrs.ReadXml(reader);
729 }
730
725 private static void ProcessTextureAnimation(SceneObjectPart obj, XmlTextReader reader) 731 private static void ProcessTextureAnimation(SceneObjectPart obj, XmlTextReader reader)
726 { 732 {
727 obj.TextureAnimation = Convert.FromBase64String(reader.ReadElementContentAsString("TextureAnimation", String.Empty)); 733 obj.TextureAnimation = Convert.FromBase64String(reader.ReadElementContentAsString("TextureAnimation", String.Empty));
@@ -1235,6 +1241,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1235 writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); 1241 writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString());
1236 if (sop.MediaUrl != null) 1242 if (sop.MediaUrl != null)
1237 writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); 1243 writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString());
1244
1245 if (sop.DynAttrs.Count > 0)
1246 {
1247 writer.WriteStartElement("DynAttrs");
1248 sop.DynAttrs.WriteXml(writer);
1249 writer.WriteEndElement();
1250 }
1251
1238 WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); 1252 WriteBytes(writer, "TextureAnimation", sop.TextureAnimation);
1239 WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); 1253 WriteBytes(writer, "ParticleSystem", sop.ParticleSystem);
1240 writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString()); 1254 writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString());