diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 730643d52a..96e8f3504e 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -363,12 +363,13 @@ namespace OpenSim.Region.CoreModules.Asset
/// Try to get an asset from the file cache.
///
///
- ///
+ /// An asset retrieved from the file cache. null if there was a problem retrieving an asset.
private AssetBase GetFromFileCache(string id)
{
AssetBase asset = null;
-
+
string filename = GetFileName(id);
+
if (File.Exists(filename))
{
FileStream stream = null;
@@ -383,7 +384,7 @@ namespace OpenSim.Region.CoreModules.Asset
}
catch (System.Runtime.Serialization.SerializationException e)
{
- m_log.ErrorFormat(
+ m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
filename, id, e.Message, e.StackTrace);
@@ -395,7 +396,7 @@ namespace OpenSim.Region.CoreModules.Asset
}
catch (Exception e)
{
- m_log.ErrorFormat(
+ m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
filename, id, e.Message, e.StackTrace);
}
@@ -552,7 +553,7 @@ namespace OpenSim.Region.CoreModules.Asset
}
catch (Exception e)
{
- m_log.ErrorFormat(
+ m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Failed to expire cached file {0}. Exception {1} {2}",
id, e.Message, e.StackTrace);
}
@@ -603,29 +604,39 @@ namespace OpenSim.Region.CoreModules.Asset
///
private void CleanExpiredFiles(string dir, DateTime purgeLine)
{
- foreach (string file in Directory.GetFiles(dir))
+ try
{
- if (File.GetLastAccessTime(file) < purgeLine)
+ foreach (string file in Directory.GetFiles(dir))
{
- File.Delete(file);
+ if (File.GetLastAccessTime(file) < purgeLine)
+ {
+ File.Delete(file);
+ }
+ }
+
+ // Recurse into lower tiers
+ foreach (string subdir in Directory.GetDirectories(dir))
+ {
+ CleanExpiredFiles(subdir, purgeLine);
+ }
+
+ // Check if a tier directory is empty, if so, delete it
+ int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length;
+ if (dirSize == 0)
+ {
+ Directory.Delete(dir);
+ }
+ else if (dirSize >= m_CacheWarnAt)
+ {
+ m_log.WarnFormat(
+ "[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration",
+ dir, dirSize);
}
}
-
- // Recurse into lower tiers
- foreach (string subdir in Directory.GetDirectories(dir))
+ catch (Exception e)
{
- CleanExpiredFiles(subdir, purgeLine);
- }
-
- // Check if a tier directory is empty, if so, delete it
- int dirSize = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length;
- if (dirSize == 0)
- {
- Directory.Delete(dir);
- }
- else if (dirSize >= m_CacheWarnAt)
- {
- m_log.WarnFormat("[FLOTSAM ASSET CACHE]: Cache folder exceeded CacheWarnAt limit {0} {1}. Suggest increasing tiers, tier length, or reducing cache expiration", dir, dirSize);
+ m_log.Warn(
+ string.Format("[FLOTSAM ASSET CACHE]: Could not complete clean of expired files in {0}, exception ", dir), e);
}
}
@@ -684,7 +695,7 @@ namespace OpenSim.Region.CoreModules.Asset
}
catch (IOException e)
{
- m_log.ErrorFormat(
+ m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.",
asset.ID, tempname, filename, directory, e.Message, e.StackTrace);
@@ -763,17 +774,31 @@ namespace OpenSim.Region.CoreModules.Asset
///
/// This notes the last time the Region had a deep asset scan performed on it.
///
- ///
- private void StampRegionStatusFile(UUID RegionID)
+ ///
+ private void StampRegionStatusFile(UUID regionID)
{
- string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + RegionID.ToString() + ".fac");
- if (File.Exists(RegionCacheStatusFile))
+ string RegionCacheStatusFile = Path.Combine(m_CacheDirectory, "RegionStatus_" + regionID.ToString() + ".fac");
+
+ try
{
- File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now);
+ if (File.Exists(RegionCacheStatusFile))
+ {
+ File.SetLastWriteTime(RegionCacheStatusFile, DateTime.Now);
+ }
+ else
+ {
+ File.WriteAllText(
+ RegionCacheStatusFile,
+ "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache.");
+ }
}
- else
+ catch (Exception e)
{
- File.WriteAllText(RegionCacheStatusFile, "Please do not delete this file unless you are manually clearing your Flotsam Asset Cache.");
+ m_log.Warn(
+ string.Format(
+ "[FLOTSAM ASSET CACHE]: Could not stamp region status file for region {0}. Exception ",
+ regionID),
+ e);
}
}
@@ -842,7 +867,7 @@ namespace OpenSim.Region.CoreModules.Asset
}
catch (Exception e)
{
- m_log.ErrorFormat(
+ m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Couldn't clear asset cache directory {0} from {1}. Exception {2} {3}",
dir, m_CacheDirectory, e.Message, e.StackTrace);
}
@@ -856,7 +881,7 @@ namespace OpenSim.Region.CoreModules.Asset
}
catch (Exception e)
{
- m_log.ErrorFormat(
+ m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Couldn't clear asset cache file {0} from {1}. Exception {1} {2}",
file, m_CacheDirectory, e.Message, e.StackTrace);
}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index dc2b0e0664..6c3ac0c8c5 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -487,6 +487,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
{
// m_log.DebugFormat(
// "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count);
+
+ if (coa.Objects.Count == 0)
+ {
+ m_log.WarnFormat(
+ "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of coalesced object from asset {0} as it has zero loaded components",
+ assetId);
+ return false;
+ }
sceneObjects.AddRange(coa.Objects);
}
@@ -495,7 +503,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
if (deserializedObject != null)
+ {
sceneObjects.Add(deserializedObject);
+ }
+ else
+ {
+ m_log.WarnFormat(
+ "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of object from asset {0} as deserialization failed",
+ assetId);
+
+ return false;
+ }
}
foreach (SceneObjectGroup sog in sceneObjects)
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
index a4f730d375..5cb271ddad 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
@@ -42,9 +42,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
///
/// Serialize and deserialize coalesced scene objects.
///
- ///
- /// Deserialization not yet here.
- ///
public class CoalescedSceneObjectsSerializer
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -128,6 +125,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
coa = null;
+ int i = 0;
using (StringReader sr = new StringReader(xml))
{
@@ -153,7 +151,23 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
if (reader.Name == "SceneObjectGroup")
{
string soXml = reader.ReadOuterXml();
- coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml));
+
+ SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(soXml);
+
+ if (so != null)
+ {
+ coa.Add(so);
+ }
+ else
+ {
+ // XXX: Possibly we should fail outright here rather than continuing if a particular component of the
+ // coalesced object fails to load.
+ m_log.WarnFormat(
+ "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.",
+ i);
+ }
+
+ i++;
}
}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
index 5808d46d51..088d0cdf88 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs
@@ -93,6 +93,15 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// extract the internals of a has reference
protected static Regex m_HashPattern = new Regex("{([^}]+)}");
+ // -----------------------------------------------------------------
+ ///
+ /// This is a simple estimator for the size of the stored data, it
+ /// is not precise, but should be close enough to implement reasonable
+ /// limits on the storage space used
+ ///
+ // -----------------------------------------------------------------
+ public int StringSpace { get; set; }
+
// -----------------------------------------------------------------
///
///
@@ -110,6 +119,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// -----------------------------------------------------------------
public JsonStore()
{
+ StringSpace = 0;
m_TakeStore = new List();
m_ReadStore = new List();
}
@@ -247,9 +257,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
if (path.Count == 0)
{
ValueStore = ovalue;
+ StringSpace = 0;
return true;
}
+ // pkey will be the final element in the path, we pull it out here to make sure
+ // that the assignment works correctly
string pkey = path.Pop();
string pexpr = PathExpressionToKey(path);
if (pexpr != "")
@@ -259,7 +272,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
if (result == null)
return false;
- // Check for and extract array references
+ // Check pkey, the last element in the path, for and extract array references
MatchCollection amatches = m_ArrayPattern.Matches(pkey,0);
if (amatches.Count > 0)
{
@@ -276,8 +289,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
{
string npkey = String.Format("[{0}]",amap.Count);
- amap.Add(ovalue);
- InvokeNextCallback(pexpr + npkey);
+ if (ovalue != null)
+ {
+ StringSpace += ComputeSizeOf(ovalue);
+
+ amap.Add(ovalue);
+ InvokeNextCallback(pexpr + npkey);
+ }
return true;
}
@@ -285,9 +303,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
if (0 <= aval && aval < amap.Count)
{
if (ovalue == null)
+ {
+ StringSpace -= ComputeSizeOf(amap[aval]);
amap.RemoveAt(aval);
+ }
else
{
+ StringSpace -= ComputeSizeOf(amap[aval]);
+ StringSpace += ComputeSizeOf(ovalue);
amap[aval] = ovalue;
InvokeNextCallback(pexpr + pkey);
}
@@ -307,16 +330,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
if (result is OSDMap)
{
+ // this is the assignment case
OSDMap hmap = result as OSDMap;
if (ovalue != null)
{
+ StringSpace -= ComputeSizeOf(hmap[hkey]);
+ StringSpace += ComputeSizeOf(ovalue);
+
hmap[hkey] = ovalue;
InvokeNextCallback(pexpr + pkey);
+ return true;
}
- else if (hmap.ContainsKey(hkey))
+
+ // this is the remove case
+ if (hmap.ContainsKey(hkey))
+ {
+ StringSpace -= ComputeSizeOf(hmap[hkey]);
hmap.Remove(hkey);
-
- return true;
+ return true;
+ }
+
+ return false;
}
return false;
@@ -522,8 +556,27 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return pkey;
}
+
+ // -----------------------------------------------------------------
+ ///
+ ///
+ ///
+ // -----------------------------------------------------------------
+ protected static int ComputeSizeOf(OSD value)
+ {
+ string sval;
+
+ if (ConvertOutputValue(value,out sval,true))
+ return sval.Length;
+
+ return 0;
+ }
}
+ // -----------------------------------------------------------------
+ ///
+ ///
+ // -----------------------------------------------------------------
public class JsonObjectStore : JsonStore
{
private static readonly ILog m_log =
@@ -557,6 +610,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
{
m_scene = scene;
m_objectID = oid;
+
+ // the size limit is imposed on whatever is already in the store
+ StringSpace = ComputeSizeOf(ValueStore);
}
}
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
index 3b52e445b3..f1ce856995 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs
@@ -54,6 +54,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
private IConfig m_config = null;
private bool m_enabled = false;
+ private bool m_enableObjectStore = false;
+ private int m_maxStringSpace = Int32.MaxValue;
+
private Scene m_scene = null;
private Dictionary m_JsonValueStore;
@@ -90,6 +93,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
}
m_enabled = m_config.GetBoolean("Enabled", m_enabled);
+ m_enableObjectStore = m_config.GetBoolean("EnableObjectStore", m_enableObjectStore);
+ m_maxStringSpace = m_config.GetInt("MaxStringSpace", m_maxStringSpace);
+ if (m_maxStringSpace == 0)
+ m_maxStringSpace = Int32.MaxValue;
}
catch (Exception e)
{
@@ -178,6 +185,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
public bool AttachObjectStore(UUID objectID)
{
if (! m_enabled) return false;
+ if (! m_enableObjectStore) return false;
SceneObjectPart sop = m_scene.GetSceneObjectPart(objectID);
if (sop == null)
@@ -239,7 +247,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
if (! m_enabled) return false;
lock (m_JsonValueStore)
- m_JsonValueStore.Remove(storeID);
+ return m_JsonValueStore.Remove(storeID);
return true;
}
@@ -311,8 +319,16 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
try
{
lock (map)
- if (map.SetValue(path,value,useJson))
- return true;
+ {
+ if (map.StringSpace > m_maxStringSpace)
+ {
+ m_log.WarnFormat("[JsonStore] {0} exceeded string size; {1} bytes used of {2} limit",
+ storeID,map.StringSpace,m_maxStringSpace);
+ return false;
+ }
+
+ return map.SetValue(path,value,useJson);
+ }
}
catch (Exception e)
{
@@ -344,8 +360,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
try
{
lock (map)
- if (map.RemoveValue(path))
- return true;
+ return map.RemoveValue(path);
}
catch (Exception e)
{
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
index 48b4a9f302..d75cd32e64 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs
@@ -504,7 +504,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
{
string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data));
int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0;
- m_comms.DispatchReply(scriptID,result, "", reqID.ToString());
+ m_comms.DispatchReply(scriptID, result, "", reqID.ToString());
return;
}
catch (Exception e)
diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
index 6658e1e48e..ca88d1a146 100644
--- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs
@@ -283,7 +283,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
string notecardName = "nc1";
// Write notecard
- UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "/", notecardName);
+ UUID writeNotecardRequestId = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "", notecardName);
Assert.That(writeNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
TaskInventoryItem nc1Item = so.RootPart.Inventory.GetInventoryItem(notecardName);
@@ -292,8 +292,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
// TODO: Should independently check the contents.
}
+ // TODO: Write partial test
+
{
- // Try to write notecard against bad path
+ // Try to write notecard for a bad path
// In this case we do get a request id but no notecard is written.
string badPathNotecardName = "badPathNotecardName";
@@ -312,7 +314,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
UUID fakeStoreWriteNotecardValue
- = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, fakeStoreId, "/", fakeStoreNotecardName);
+ = (UUID)InvokeOpOnHost("JsonWriteNotecard", so.UUID, fakeStoreId, "", fakeStoreNotecardName);
Assert.That(fakeStoreWriteNotecardValue, Is.Not.EqualTo(UUID.Zero));
TaskInventoryItem fakeStoreItem = so.RootPart.Inventory.GetInventoryItem(fakeStoreNotecardName);
@@ -321,7 +323,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
}
///
- /// Test for reading and writing json to a notecard
+ /// Test for reading json from a notecard
///
///
/// TODO: Really needs to test correct receipt of the link_message event. Could do this by directly fetching
@@ -338,20 +340,73 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1));
m_scene.AddSceneObject(so);
- UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }");
+ UUID creatingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello':'World' }");
// Write notecard
- InvokeOpOnHost("JsonWriteNotecard", so.UUID, storeId, "/", notecardName);
+ InvokeOpOnHost("JsonWriteNotecard", so.UUID, creatingStoreId, "", notecardName);
- // Read notecard
- UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ }");
- UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName);
- Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
+ {
+ // Read notecard
+ UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
+ UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "", notecardName);
+ Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
- string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
- Assert.That(value, Is.EqualTo("World"));
+ string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
+ Assert.That(value, Is.EqualTo("World"));
+ }
+ {
+ // Read notecard to new single component path
+ UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
+ UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make", notecardName);
+ Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
+ // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root.
+ string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
+ Assert.That(value, Is.EqualTo(""));
+
+ value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.Hello");
+ Assert.That(value, Is.EqualTo("World"));
+ }
+
+ {
+ // Read notecard to new multi-component path
+ UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{}");
+ UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName);
+ Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
+
+ // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root.
+ string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
+ Assert.That(value, Is.EqualTo(""));
+
+ // TODO: Check that we are not expecting reading to a new path to work.
+ value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello");
+ Assert.That(value, Is.EqualTo(""));
+ }
+
+ {
+ // Read notecard to existing multi-component path
+ UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }");
+ UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "make.it", notecardName);
+ Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
+
+ // These don't behave as I expect yet - reading to a path still seems to place the notecard contents at the root.
+ string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
+ Assert.That(value, Is.EqualTo(""));
+
+ value = (string)InvokeOp("JsonGetValue", receivingStoreId, "make.it.Hello");
+ Assert.That(value, Is.EqualTo("World"));
+ }
+
+ {
+ // Try read notecard to fake store.
+ UUID fakeStoreId = TestHelpers.ParseTail(0x500);
+ UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, fakeStoreId, "", notecardName);
+ Assert.That(fakeStoreId, Is.Not.EqualTo(UUID.Zero));
+
+ string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello");
+ Assert.That(value, Is.EqualTo(""));
+ }
}
public object DummyTestMethod(object o1, object o2, object o3, object o4, object o5) { return null; }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 192bcb5f3a..d694a6a5e7 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -749,9 +749,10 @@ public sealed class BSCharacter : BSPhysObject
_buoyancy = value;
DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
// Buoyancy is faked by changing the gravity applied to the object
- float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
+ float grav = BSParam.Gravity * (1f - _buoyancy);
+ Gravity = new OMV.Vector3(0f, 0f, grav);
if (PhysBody.HasPhysicalBody)
- PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav));
+ PhysicsScene.PE.SetGravity(PhysBody, Gravity);
}
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index ec25aa927e..0d8bb0304c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -78,6 +78,10 @@ public abstract class BSPhysObject : PhysicsActor
Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
TypeName = typeName;
+ // Initialize variables kept in base.
+ GravModifier = 1.0f;
+ Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
+
// We don't have any physical representation yet.
PhysBody = new BulletBody(localID);
PhysShape = new BulletShape();
@@ -88,8 +92,8 @@ public abstract class BSPhysObject : PhysicsActor
LastAssetBuildFailed = false;
- // Default material type
- Material = MaterialAttributes.Material.Wood;
+ // Default material type. Also sets Friction, Restitution and Density.
+ SetMaterial((int)MaterialAttributes.Material.Wood);
CollisionCollection = new CollisionEventUpdate();
CollisionsLastTick = CollisionCollection;
@@ -122,6 +126,8 @@ public abstract class BSPhysObject : PhysicsActor
// 'inWorld' true if the object has already been added to the dynamic world.
public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
+ // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
+ public virtual OMV.Vector3 Gravity { get; set; }
// The last value calculated for the prim's inertia
public OMV.Vector3 Inertia { get; set; }
@@ -164,15 +170,18 @@ public abstract class BSPhysObject : PhysicsActor
public override void SetMaterial(int material)
{
Material = (MaterialAttributes.Material)material;
+
+ // Setting the material sets the material attributes also.
+ MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
+ Friction = matAttrib.friction;
+ Restitution = matAttrib.restitution;
+ Density = matAttrib.density;
}
// Stop all physical motion.
public abstract void ZeroMotion(bool inTaintTime);
public abstract void ZeroAngularMotion(bool inTaintTime);
- // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
- public virtual void StepVehicle(float timeStep) { }
-
// Update the physical location and motion of the object. Called with data from Bullet.
public abstract void UpdateProperties(EntityProperties entprop);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 54bf063add..85c2627f1c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -55,7 +55,6 @@ public sealed class BSPrim : BSPhysObject
private OMV.Vector3 _position;
private float _mass; // the mass of this object
- private float _density;
private OMV.Vector3 _force;
private OMV.Vector3 _velocity;
private OMV.Vector3 _torque;
@@ -64,8 +63,6 @@ public sealed class BSPrim : BSPhysObject
private int _physicsActorType;
private bool _isPhysical;
private bool _flying;
- private float _friction;
- private float _restitution;
private bool _setAlwaysRun;
private bool _throttleUpdates;
private bool _floatOnWater;
@@ -101,12 +98,6 @@ public sealed class BSPrim : BSPhysObject
_isPhysical = pisPhysical;
_isVolumeDetect = false;
- // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
- // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
- _density = PhysicsScene.Params.defaultDensity;
- _friction = PhysicsScene.Params.defaultFriction;
- _restitution = PhysicsScene.Params.defaultRestitution;
-
VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness
_mass = CalculateMass();
@@ -432,8 +423,6 @@ public sealed class BSPrim : BSPhysObject
}
else
{
- OMV.Vector3 grav = ComputeGravity(Buoyancy);
-
if (inWorld)
{
// Changing interesting properties doesn't change proxy and collision cache
@@ -443,25 +432,20 @@ public sealed class BSPrim : BSPhysObject
}
// The computation of mass props requires gravity to be set on the object.
- PhysicsScene.PE.SetGravity(PhysBody, grav);
+ Gravity = ComputeGravity(Buoyancy);
+ PhysicsScene.PE.SetGravity(PhysBody, Gravity);
Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
- // center of mass is at the zero of the object
- // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation);
- DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld);
+ DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
+ LocalID, physMass, Inertia, Gravity, inWorld);
if (inWorld)
{
AddObjectToPhysicalWorld();
}
-
- // Must set gravity after it has been added to the world because, for unknown reasons,
- // adding the object resets the object's gravity to world gravity
- PhysicsScene.PE.SetGravity(PhysBody, grav);
-
}
}
}
@@ -472,7 +456,10 @@ public sealed class BSPrim : BSPhysObject
OMV.Vector3 ret = PhysicsScene.DefaultGravity;
if (!IsStatic)
+ {
ret *= (1f - buoyancy);
+ ret *= GravModifier;
+ }
return ret;
}
@@ -596,6 +583,74 @@ public sealed class BSPrim : BSPhysObject
}
return;
}
+ public override void SetMaterial(int material)
+ {
+ base.SetMaterial(material);
+ PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ public override float Friction
+ {
+ get { return base.Friction; }
+ set
+ {
+ if (base.Friction != value)
+ {
+ base.Friction = value;
+ PhysicsScene.TaintedObject("BSPrim.setFriction", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ }
+ public override float Restitution
+ {
+ get { return base.Restitution; }
+ set
+ {
+ if (base.Restitution != value)
+ {
+ base.Restitution = value;
+ PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ }
+ public override float Density
+ {
+ get { return base.Density; }
+ set
+ {
+ if (base.Density != value)
+ {
+ base.Density = value;
+ PhysicsScene.TaintedObject("BSPrim.setDensity", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ }
+ public override float GravModifier
+ {
+ get { return base.GravModifier; }
+ set
+ {
+ if (base.GravModifier != value)
+ {
+ base.GravModifier = value;
+ PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ }
public override OMV.Vector3 RawVelocity
{
get { return _velocity; }
@@ -761,7 +816,12 @@ public sealed class BSPrim : BSPhysObject
// collisionEvents: whether this object returns collision events
public void UpdatePhysicalParameters()
{
- // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
+ if (!PhysBody.HasPhysicalBody)
+ {
+ // This would only happen if updates are called for during initialization when the body is not set up yet.
+ DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
+ return;
+ }
// Mangling all the physical properties requires the object not be in the physical world.
// This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
@@ -810,8 +870,8 @@ public sealed class BSPrim : BSPhysObject
// Set various physical properties so other object interact properly
MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
- PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
- PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
+ PhysicsScene.PE.SetFriction(PhysBody, Friction);
+ PhysicsScene.PE.SetRestitution(PhysBody, Restitution);
// Mass is zero which disables a bunch of physics stuff in Bullet
UpdatePhysicalMassProperties(0f, false);
@@ -839,9 +899,9 @@ public sealed class BSPrim : BSPhysObject
CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
// Set various physical properties so other object interact properly
- MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
- PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
- PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
+ PhysicsScene.PE.SetFriction(PhysBody, Friction);
+ PhysicsScene.PE.SetRestitution(PhysBody, Restitution);
+ // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
// per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
// Since this can be called multiple times, only zero forces when becoming physical
@@ -944,7 +1004,7 @@ public sealed class BSPrim : BSPhysObject
else
{
m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
- DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
+ DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
}
}
@@ -1581,7 +1641,7 @@ public sealed class BSPrim : BSPhysObject
profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
volume *= (profileEnd - profileBegin);
- returnMass = _density * volume;
+ returnMass = Density * volume;
/* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
if (IsRootOfLinkset)
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
index e2789d68fc..7cd364b248 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
@@ -274,7 +274,7 @@ namespace OpenSim.Region.Physics.Manager
public virtual float Density { get; set; }
public virtual float GravModifier { get; set; }
public virtual float Friction { get; set; }
- public virtual float Bounce { get; set; }
+ public virtual float Restitution { get; set; }
///
/// Position of this actor.
diff --git a/bin/HttpServer_OpenSim.dll b/bin/HttpServer_OpenSim.dll
index 2512b851e8..fd7ad742d0 100755
Binary files a/bin/HttpServer_OpenSim.dll and b/bin/HttpServer_OpenSim.dll differ
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index 6409cdb4fd..e2d952a8ec 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -1648,6 +1648,10 @@
[JsonStore]
Enabled = False
+;; Enable direct access to the SOP dynamic attributes
+EnableObjectStore = False
+MaxStringSpace = 0
+
;;
;; These are defaults that are overwritten below in [Architecture].
;; These defaults allow OpenSim to work out of the box with