Compare commits

...

62 Commits

Author SHA1 Message Date
Dan Lake
e09467b30d Merge branch 'master' of git://opensimulator.org/git/opensim 2013-02-14 20:06:22 -08:00
Dan Lake
afeb5d4917 Use SortedDictionary in StatsManager instead of regular Dictionary so stats will interate and print in a defined order 2013-02-14 20:05:42 -08:00
Justin Clark-Casey (justincc)
8d5fe5c222 Enable one sub-test in TestJsonSetValue() which now works (using identifier with embedded .).
Need to look further at other still commented tests.
Still need to check coverage against some of Mic's scripts.
2013-02-15 01:00:49 +00:00
Justin Clark-Casey (justincc)
61f18d15e1 Rename JsonSetValueJson() -> JsonSetJson() and JsonGetValueJson() -> JsonGetJson()
This is because JsonGetJson() is getting json from anywhere in the structure, not just values.
Equally, JsonSetJson() is setting any type of json, not just json which represents a value.
Agreed with cmickeyb
2013-02-15 00:38:07 +00:00
Justin Clark-Casey (justincc)
0b2608d8f4 Comment out regression TestJsonTestPath and TestJsonTestPathJson as these will go away soon 2013-02-15 00:32:20 +00:00
Justin Clark-Casey (justincc)
30a60d661f Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-02-15 00:28:00 +00:00
Justin Clark-Casey (justincc)
cc40517863 Add regression TestJsonList2Path() 2013-02-15 00:27:30 +00:00
teravus
71862f34b6 * Handle null check on configs in module startup so that the the code can be run on 'stop on handled and unhandled null reference exceptions' mode without pausing during startup a bunch of times. I don't think exceptions were really meant for replacing a single if statement... 2013-02-14 18:52:11 -05:00
teravus
c22276a169 * gracefully handle a Situation where a double close is called on the WebSocket handler 2013-02-14 18:43:53 -05:00
Justin Clark-Casey (justincc)
13d4f6f747 Add regression TestGetArrayLength() 2013-02-14 21:34:57 +00:00
Justin Clark-Casey (justincc)
6fe771f27e Add regression TestJsonGetPathType() 2013-02-14 21:31:34 +00:00
Justin Clark-Casey (justincc)
0ad07eb44d minor: remove some mono compiler warnings 2013-02-14 21:29:35 +00:00
Justin Clark-Casey (justincc)
edb99dcc19 Rename new JsonScript functions JsonPathType() -> JsonGetPathType() and JsonArrayLength() -> JsonGetArrayLength()
This is for consistentency with the verb:noun naming approach existing json script functions and other script functions.
Corresponding c# methods also changed since verb:noun is also the .net c# method naming guideline (as used by OpenSimulator) and for consistency with script functions.
As agreed with cmickeyb
2013-02-14 21:11:58 +00:00
Justin Clark-Casey (justincc)
a52dfd43b6 Make new JsonStore script constants separated with underscores, to be consistent with existing LSL/OSSL, etc script constants.
Agreed with cmickeyb
2013-02-14 21:03:07 +00:00
Robert Adams
5920abbf8d Add EventManager events triggered when a SOP is added or removed
from the physical scene. Invocations added in SceneObjectPart.
2013-02-14 09:48:11 -08:00
Melanie
ef662fc959 Add an event and some logic to allow customizing Simulator Features by avatar 2013-02-14 09:11:57 +00:00
Justin Clark-Casey (justincc)
69d0e168fb Fix a very unlikely-to-occur NullReferenceException race condition in llPushObject() where the code assumed that the physics actor it null-checked would still be null when it invoked a method on it 2013-02-14 00:20:23 +00:00
Mic Bowman
bcb172301d Adds a couple requested functions to the JsonStore script
interface. JsonPathType returns the type of node pointed to by the
path and deprecates the functionality of both JsonTestPath
functions. JsonArrayLength returns the length of an array node.
2013-02-13 07:14:04 -08:00
Mic Bowman
708c3f8b86 Make path parsing more robust in the JsonStore. 2013-02-12 23:21:49 -08:00
Melanie
d652de1d0e Merge branch 'master' of melanie@opensimulator.org:/var/git/opensim 2013-02-13 01:53:29 +00:00
Melanie
c2bfdaa026 Make the sim features module register it's interface so it can be used 2013-02-13 01:52:25 +00:00
Justin Clark-Casey (justincc)
5557b523fd Add more sub-tests to TestJsonSetValue for paths containing []{} without {} delineation.
As expected, values are not set and the set call returns FALSE (0).
As a reminder, these tests are not currently running on jenkins continuous integration as the functionality is only available on .net 4 (mono 2.8 and later).
2013-02-13 01:38:33 +00:00
Justin Clark-Casey (justincc)
b1a165a39a Extend JsonTestSetValue() with tests for escaping brackets, periods and unbalanced braces from paths
The sub-tests that are commented out are currently those which fail unexpectedly based on my understanding of the path syntax
2013-02-13 01:25:30 +00:00
Justin Clark-Casey (justincc)
70e641c708 Add test for array as root element in TestJsonCreateStore() 2013-02-13 00:51:45 +00:00
Justin Clark-Casey (justincc)
3e9f3c0383 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-02-13 00:34:08 +00:00
Justin Clark-Casey (justincc)
4b797f2ead Extend TestJsonRemoveValue() with tests for non-penultimate nodes and arrays 2013-02-13 00:12:20 +00:00
Robert Adams
0194a3d890 BulletSim: fix density since the simulator/viewer track density in a
funny unit that is 100 times real density (default 1000).
Fix avatar drifting slowly when stationary flying.
Fix for physical prims getting corrected for being under terrain when it was
just its geometric center that was below terrain.
Add PreUpdatePropertyAction allowing plugable modifiction of phys
parameters returned from Bullet.
Fix an exception setting GravityMultiplier on initialization.
Update DLLs and SOs for good measure (no functional change).
2013-02-12 15:52:10 -08:00
Robert Adams
fb903ff490 BulletSim: More work on center-of-mass. Remove linksetinfo and rely on simulator to update info. 2013-02-12 15:52:08 -08:00
Justin Clark-Casey (justincc)
992ef9e971 Extend TestJsonCreateStore() with a one key input and an input with raw number values 2013-02-12 23:00:24 +00:00
Diva Canto
aaa80d11a8 Replaced Ionic.Zip.dll with a new one that fixes a bug in it. DotNetZip (from which Ionic.Zip.dll is derived) is now a fork in opensim-libs, forked from 1.9.1.8 and added that simple bug fix. 2013-02-12 14:47:26 -08:00
Justin Clark-Casey (justincc)
a82bd5678e Use an integer when specifying the XWorkItem wait rather than a TimeSpan to avoid a Windows casting issue in SmartThreadPool for large TimeSpans.
TimeSpan.Milliseconds is an int64.  However, STP casts this to an int (32-bit).
If TimeSpan.MaxValue is given then the casting results in an invalid value for the SDK WaitHandle.WaitAll() call.
This was causing the co-op script termination regression tests to fail on Windows but not Mono 2.10.8 (which is perhaps not strict in the negative values that it accepts).
Solution here is to use the int millisecondsTimeout STP call rather than the TimeSpan one.
This also allows us to more clearly specify Timeout.Infinite rather than TimeSpan.MaxValue
Thanks to Teravus for this spot.
2013-02-12 21:34:12 +00:00
Justin Clark-Casey (justincc)
058d477ce7 Re-enable subtest for single quoted token in TestJsonSetValueJson()
This is in response to the resolution of http://opensimulator.org/mantis/view.php?id=6540
2013-02-12 20:51:36 +00:00
Mic Bowman
4b8c22ecfa Adds the parameter for OSD serialization to encode default values. This
makes the JsonStore get/set operations symmetric.
2013-02-12 11:10:17 -08:00
Mic Bowman
d3b2cdc2b4 Fix handling of string values in JsonSetValueJson(). There are
some oddities with empty strings: the Json serializer treats them
as default values and does not return them in serialized hashes.
2013-02-11 19:55:10 -08:00
Justin Clark-Casey (justincc)
586def0bcc Add regression TestJsonSetValueJson()
The part to test setting of single leaf-node string tokens is currently commented out.
See http://opensimulator.org/mantis/view.php?id=6540
2013-02-12 01:27:38 +00:00
Justin Clark-Casey (justincc)
d55974bcb7 Add regression TestJsonGetValueJson() 2013-02-11 23:47:49 +00:00
Justin Clark-Casey (justincc)
6924bd21f4 Add regression TestJsonTestPathJson() 2013-02-11 23:10:07 +00:00
Justin Clark-Casey (justincc)
9d001e40e7 Add section to TestJsonGetValue() to test call on a sub-tree 2013-02-11 22:56:43 +00:00
Justin Clark-Casey (justincc)
8fcfd82241 Extend TestJsonTestPath() for non-terminating section of path (i.e. one that does not point to a value/leaf) 2013-02-11 22:44:25 +00:00
Justin Clark-Casey (justincc)
cbb8d82c7d Add section to TestJsonSetValue() to test attempted set of value where the penultimate section of path does not exist 2013-02-11 22:28:50 +00:00
Justin Clark-Casey (justincc)
c72c189864 Add test to try reading notecard into an invalid path in TestJsonReadNotecard() regression test 2013-02-11 22:16:07 +00:00
Melanie
6f3dcf58b8 Fix code to check for no spawn points. Possibly a merge artefact? 2013-02-10 20:00:39 +00:00
BlueWall
38b476d9d6 Adding contributor to credits: Welcome Allen Kerensky! 2013-02-10 14:17:02 -05:00
Allen Kerensky
7524bd5a7c Additional ThreadPool worker and IOCP thread startup logic
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2013-02-10 14:14:33 -05:00
BlueWall
adedd70c35 Fix teleport/telehub issue:
Fix bug that allowed only login access to regions with mis-configured telehubs. Administrators now have teleport access when there exists a mis-configured telehub in the region. Estate owners are now placed at region center in the absence of spawnpoints instead of being denied access. Grid Gods are unrestricted. All others are denied access to the region until spawnpoints are assigned to the telehub object.
2013-02-10 13:01:33 -05:00
Mic Bowman
0a297a0e52 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-02-08 22:43:56 -08:00
Mic Bowman
7bb82c8f2e Make JsonStore path parsing more robust. Should fix the
invalid path problem.
2013-02-08 22:43:15 -08:00
Oren Hurvitz
745ef40153 Fixed ReadSculptData(): the check whether there are enough bytes to read was incorrect 2013-02-09 02:04:26 +00:00
Oren Hurvitz
ae701eccd2 Fixed check for 0 results in GetUserAccounts() 2013-02-09 01:57:36 +00:00
Justin Clark-Casey (justincc)
6935bec0ab Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-02-09 01:11:41 +00:00
Justin Clark-Casey (justincc)
a8bc08ebe6 Change TestDestroyStore() and TestJsonRemoveValue() to reflect the fact that the return values have changed. 2013-02-09 01:10:53 +00:00
Oren Hurvitz
85b81ff7f2 Added physics parameters support to MSSQL and SQLite (not tested) 2013-02-09 01:03:58 +00:00
Robert Adams
4808b8ee38 BulletSim: add parameter to set global contact breaking threshold. Update DLLs and SOs for setting same. 2013-02-08 16:29:52 -08:00
Robert Adams
222040f1ec BulletSim: Change BSCharacter to use new base Density and Friction
variables rather than own local varaibles.
2013-02-08 16:29:45 -08:00
Robert Adams
1b55a9d81e BulletSim: fix avatar bobbing or jiggling while stationary flying.
Various comments and debugging message mods.
2013-02-08 16:29:40 -08:00
Robert Adams
d92eb80373 BulletSim: add initial instance of the ExtendedPhysics region module which adds new LSL commands for extended physics functions. Uses the modInvoke system. Disabled by default. 2013-02-08 16:29:35 -08:00
Robert Adams
1b203601f4 BulletSim: include the linkage to the layered prim implementation. Separate layers for physical (vs simulator) location displacement and linksets. 2013-02-08 16:29:29 -08:00
Robert Adams
2fd184e350 BulletSim: reclass BSPrim into layers so linkset and physical world displacement is implemented as overlay classes rather than if statements scattered about. 2013-02-08 16:29:24 -08:00
Mic Bowman
6d825d7ea2 Broaden the internal OSD type checks to parse JSON that has
non string values.
2013-02-08 15:46:42 -08:00
Mic Bowman
4d5c04837e Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-02-08 15:09:13 -08:00
Justin Clark-Casey (justincc)
a08e1b60ec Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-02-08 21:56:22 +00:00
Justin Clark-Casey (justincc)
b08977ea7d Don't allow exceptions to propogate from FlotsamAssetCache which may occur when deleting expired files or stamping the region status file.
Changes various error level log lines to warn since these are not fatal to the operation of OpenSimulator
2013-02-08 21:21:20 +00:00
51 changed files with 2062 additions and 565 deletions

View File

@@ -65,6 +65,7 @@ what it is today.
* A_Biondi
* alex_carnell
* Alan Webb (IBM)
* Allen Kerensky
* BigFootAg
* BlueWall Slade
* brianw/Sir_Ahzz

View File

@@ -351,7 +351,8 @@ IF EXISTS (SELECT UUID FROM prims WHERE UUID = @UUID)
ScriptAccessPin = @ScriptAccessPin, AllowedDrop = @AllowedDrop, DieAtEdge = @DieAtEdge, SalePrice = @SalePrice,
SaleType = @SaleType, ColorR = @ColorR, ColorG = @ColorG, ColorB = @ColorB, ColorA = @ColorA, ParticleSystem = @ParticleSystem,
ClickAction = @ClickAction, Material = @Material, CollisionSound = @CollisionSound, CollisionSoundVolume = @CollisionSoundVolume, PassTouches = @PassTouches,
LinkNumber = @LinkNumber, MediaURL = @MediaURL, DynAttrs = @DynAttrs
LinkNumber = @LinkNumber, MediaURL = @MediaURL, DynAttrs = @DynAttrs,
PhysicsShapeType = @PhysicsShapeType, Density = @Density, GravityModifier = @GravityModifier, Friction = @Friction, Restitution = @Restitution
WHERE UUID = @UUID
END
ELSE
@@ -366,7 +367,8 @@ ELSE
PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, LoopedSound, LoopedSoundGain, TextureAnimation, OmegaX,
OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ,
ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA,
ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL, DynAttrs
ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL, DynAttrs,
PhysicsShapeType, Density, GravityModifier, Friction, Restitution
) VALUES (
@UUID, @CreationDate, @Name, @Text, @Description, @SitName, @TouchName, @ObjectFlags, @OwnerMask, @NextOwnerMask, @GroupMask,
@EveryoneMask, @BaseMask, @PositionX, @PositionY, @PositionZ, @GroupPositionX, @GroupPositionY, @GroupPositionZ, @VelocityX,
@@ -376,7 +378,8 @@ ELSE
@PayPrice, @PayButton1, @PayButton2, @PayButton3, @PayButton4, @LoopedSound, @LoopedSoundGain, @TextureAnimation, @OmegaX,
@OmegaY, @OmegaZ, @CameraEyeOffsetX, @CameraEyeOffsetY, @CameraEyeOffsetZ, @CameraAtOffsetX, @CameraAtOffsetY, @CameraAtOffsetZ,
@ForceMouselook, @ScriptAccessPin, @AllowedDrop, @DieAtEdge, @SalePrice, @SaleType, @ColorR, @ColorG, @ColorB, @ColorA,
@ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL, @DynAttrs
@ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL, @DynAttrs,
@PhysicsShapeType, @Density, @GravityModifier, @Friction, @Restitution
)
END";
@@ -1697,6 +1700,12 @@ VALUES
else
prim.DynAttrs = new DAMap();
prim.PhysicsShapeType = Convert.ToByte(primRow["PhysicsShapeType"]);
prim.Density = Convert.ToSingle(primRow["Density"]);
prim.GravityModifier = Convert.ToSingle(primRow["GravityModifier"]);
prim.Friction = Convert.ToSingle(primRow["Friction"]);
prim.Restitution = Convert.ToSingle(primRow["Restitution"]);
return prim;
}
@@ -2095,6 +2104,12 @@ VALUES
parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml()));
else
parameters.Add(_Database.CreateParameter("DynAttrs", null));
parameters.Add(_Database.CreateParameter("PhysicsShapeType", prim.PhysicsShapeType));
parameters.Add(_Database.CreateParameter("Density", (double)prim.Density));
parameters.Add(_Database.CreateParameter("GravityModifier", (double)prim.GravityModifier));
parameters.Add(_Database.CreateParameter("Friction", (double)prim.Friction));
parameters.Add(_Database.CreateParameter("Restitution", (double)prim.Restitution));
return parameters.ToArray();
}

View File

@@ -1156,3 +1156,15 @@ BEGIN TRANSACTION
ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
COMMIT
:VERSION 39 #---------------- Extra physics params
BEGIN TRANSACTION
ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0';
ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000';
ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1';
ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6';
ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5';
COMMIT

View File

@@ -173,9 +173,9 @@ namespace OpenSim.Data.MySQL
"ParticleSystem, ClickAction, Material, " +
"CollisionSound, CollisionSoundVolume, " +
"PassTouches, " +
"LinkNumber, MediaURL, " +
"LinkNumber, MediaURL, DynAttrs, " +
"PhysicsShapeType, Density, GravityModifier, " +
"Friction, Restitution, DynAttrs " +
"Friction, Restitution " +
") values (" + "?UUID, " +
"?CreationDate, ?Name, ?Text, " +
"?Description, ?SitName, ?TouchName, " +
@@ -208,9 +208,9 @@ namespace OpenSim.Data.MySQL
"?ColorB, ?ColorA, ?ParticleSystem, " +
"?ClickAction, ?Material, ?CollisionSound, " +
"?CollisionSoundVolume, ?PassTouches, " +
"?LinkNumber, ?MediaURL, " +
"?LinkNumber, ?MediaURL, ?DynAttrs, " +
"?PhysicsShapeType, ?Density, ?GravityModifier, " +
"?Friction, ?Restitution, ?DynAttrs)";
"?Friction, ?Restitution)";
FillPrimCommand(cmd, prim, obj.UUID, regionUUID);
@@ -1659,16 +1659,17 @@ namespace OpenSim.Data.MySQL
cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum);
cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl);
cmd.Parameters.AddWithValue("PhysicsShapeType", prim.PhysicsShapeType);
cmd.Parameters.AddWithValue("Density", (double)prim.Density);
cmd.Parameters.AddWithValue("GravityModifier", (double)prim.GravityModifier);
cmd.Parameters.AddWithValue("Friction", (double)prim.Friction);
cmd.Parameters.AddWithValue("Restitution", (double)prim.Restitution);
if (prim.DynAttrs.Count > 0)
cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml());
else
cmd.Parameters.AddWithValue("DynAttrs", null);
cmd.Parameters.AddWithValue("PhysicsShapeType", prim.PhysicsShapeType);
cmd.Parameters.AddWithValue("Density", (double)prim.Density);
cmd.Parameters.AddWithValue("GravityModifier", (double)prim.GravityModifier);
cmd.Parameters.AddWithValue("Friction", (double)prim.Friction);
cmd.Parameters.AddWithValue("Restitution", (double)prim.Restitution);
}
/// <summary>

View File

@@ -911,7 +911,7 @@ ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
COMMIT;
:VERSION 47 #---------------- Extra prim params
:VERSION 47 #---------------- Extra physics params
BEGIN;

View File

@@ -580,3 +580,15 @@ COMMIT;
BEGIN;
ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
COMMIT;
:VERSION 28
BEGIN;
ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0';
ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000';
ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1';
ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6';
ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5';
COMMIT;

View File

@@ -1235,6 +1235,12 @@ namespace OpenSim.Data.SQLite
createCol(prims, "DynAttrs", typeof(String));
createCol(prims, "PhysicsShapeType", typeof(Byte));
createCol(prims, "Density", typeof(Double));
createCol(prims, "GravityModifier", typeof(Double));
createCol(prims, "Friction", typeof(Double));
createCol(prims, "Restitution", typeof(Double));
// Add in contraints
prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] };
@@ -1724,6 +1730,12 @@ namespace OpenSim.Data.SQLite
prim.DynAttrs = new DAMap();
}
prim.PhysicsShapeType = Convert.ToByte(row["PhysicsShapeType"]);
prim.Density = Convert.ToSingle(row["Density"]);
prim.GravityModifier = Convert.ToSingle(row["GravityModifier"]);
prim.Friction = Convert.ToSingle(row["Friction"]);
prim.Restitution = Convert.ToSingle(row["Restitution"]);
return prim;
}
@@ -2150,6 +2162,12 @@ namespace OpenSim.Data.SQLite
row["DynAttrs"] = prim.DynAttrs.ToXml();
else
row["DynAttrs"] = null;
row["PhysicsShapeType"] = prim.PhysicsShapeType;
row["Density"] = (double)prim.Density;
row["GravityModifier"] = (double)prim.GravityModifier;
row["Friction"] = (double)prim.Friction;
row["Restitution"] = (double)prim.Restitution;
}
/// <summary>

View File

@@ -359,11 +359,11 @@ Asset service request failures: {3}" + Environment.NewLine,
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
Dictionary<string, Dictionary<string, Stat>> sceneStats;
SortedDictionary<string, SortedDictionary<string, Stat>> sceneStats;
if (StatsManager.TryGetStats("scene", out sceneStats))
{
foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
foreach (KeyValuePair<string, SortedDictionary<string, Stat>> kvp in sceneStats)
{
foreach (Stat stat in kvp.Value.Values)
{

View File

@@ -51,8 +51,8 @@ namespace OpenSim.Framework.Monitoring
/// <remarks>
/// Do not add or remove directly from this dictionary.
/// </remarks>
public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
= new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>> RegisteredStats
= new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>>();
private static AssetStatsCollector assetStats;
private static UserStatsCollector userStats;
@@ -101,7 +101,7 @@ namespace OpenSim.Framework.Monitoring
}
else
{
Dictionary<string, Dictionary<string, Stat>> category;
SortedDictionary<string, SortedDictionary<string, Stat>> category;
if (!RegisteredStats.TryGetValue(categoryName, out category))
{
con.OutputFormat("No such category as {0}", categoryName);
@@ -120,7 +120,7 @@ namespace OpenSim.Framework.Monitoring
}
private static void OutputCategoryStatsToConsole(
ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category)
{
foreach (var container in category.Values)
{
@@ -160,8 +160,8 @@ namespace OpenSim.Framework.Monitoring
/// <returns></returns>
public static bool RegisterStat(Stat stat)
{
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
SortedDictionary<string, SortedDictionary<string, Stat>> category = null, newCategory;
SortedDictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats)
{
@@ -175,14 +175,14 @@ namespace OpenSim.Framework.Monitoring
// This means that we don't need to lock or copy them on iteration, which will be a much more
// common operation after startup.
if (container != null)
newContainer = new Dictionary<string, Stat>(container);
newContainer = new SortedDictionary<string, Stat>(container);
else
newContainer = new Dictionary<string, Stat>();
newContainer = new SortedDictionary<string, Stat>();
if (category != null)
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>(category);
else
newCategory = new Dictionary<string, Dictionary<string, Stat>>();
newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>();
newContainer[stat.ShortName] = stat;
newCategory[stat.Container] = newContainer;
@@ -196,21 +196,21 @@ namespace OpenSim.Framework.Monitoring
/// Deregister a statistic
/// </summary>>
/// <param name='stat'></param>
/// <returns></returns
/// <returns></returns>
public static bool DeregisterStat(Stat stat)
{
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
SortedDictionary<string, SortedDictionary<string, Stat>> category = null, newCategory;
SortedDictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats)
{
if (!TryGetStat(stat, out category, out container))
return false;
newContainer = new Dictionary<string, Stat>(container);
newContainer = new SortedDictionary<string, Stat>(container);
newContainer.Remove(stat.ShortName);
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>(category);
newCategory.Remove(stat.Container);
newCategory[stat.Container] = newContainer;
@@ -220,15 +220,15 @@ namespace OpenSim.Framework.Monitoring
}
}
public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
public static bool TryGetStats(string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats)
{
return RegisteredStats.TryGetValue(category, out stats);
}
public static bool TryGetStat(
Stat stat,
out Dictionary<string, Dictionary<string, Stat>> category,
out Dictionary<string, Stat> container)
out SortedDictionary<string, SortedDictionary<string, Stat>> category,
out SortedDictionary<string, Stat> container)
{
category = null;
container = null;
@@ -252,9 +252,9 @@ namespace OpenSim.Framework.Monitoring
{
lock (RegisteredStats)
{
foreach (Dictionary<string, Dictionary<string, Stat>> category in RegisteredStats.Values)
foreach (SortedDictionary<string, SortedDictionary<string, Stat>> category in RegisteredStats.Values)
{
foreach (Dictionary<string, Stat> container in category.Values)
foreach (SortedDictionary<string, Stat> container in category.Values)
{
foreach (Stat stat in container.Values)
{

View File

@@ -622,6 +622,8 @@ namespace OpenSim.Framework
}
}
// This is only used at runtime. For sculpties this holds the texture data, and for meshes
// the mesh data.
public byte[] SculptData
{
get
@@ -1147,14 +1149,13 @@ namespace OpenSim.Framework
public void ReadSculptData(byte[] data, int pos)
{
byte[] SculptTextureUUID = new byte[16];
UUID SculptUUID = UUID.Zero;
byte SculptTypel = data[16+pos];
UUID SculptUUID;
byte SculptTypel;
if (data.Length+pos >= 17)
if (data.Length-pos >= 17)
{
_sculptEntry = true;
SculptTextureUUID = new byte[16];
byte[] SculptTextureUUID = new byte[16];
SculptTypel = data[16 + pos];
Array.Copy(data, pos, SculptTextureUUID,0, 16);
SculptUUID = new UUID(SculptTextureUUID, 0);

View File

@@ -535,6 +535,8 @@ namespace OpenSim.Framework.Servers.HttpServer
/// <param name="message"></param>
public void Close(string message)
{
if (_networkContext == null)
return;
if (_networkContext.Stream != null)
{
if (_networkContext.Stream.CanWrite)

View File

@@ -102,17 +102,50 @@ namespace OpenSim
m_log.InfoFormat(
"[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset");
// Increase the number of IOCP threads available. Mono defaults to a tragically low number
// Verify the Threadpool allocates or uses enough worker and IO completion threads
// .NET 2.0 workerthreads default to 50 * numcores
// .NET 3.0 workerthreads defaults to 250 * numcores
// .NET 4.0 workerthreads are dynamic based on bitness and OS resources
// Max IO Completion threads are 1000 on all 3 CLRs.
int workerThreadsMin = 500;
int workerThreadsMax = 1000; // may need further adjustment to match other CLR
int iocpThreadsMin = 1000;
int iocpThreadsMax = 2000; // may need further adjustment to match other CLR
int workerThreads, iocpThreads;
System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads);
if (workerThreads < 500 || iocpThreads < 1000)
if (workerThreads < workerThreadsMin)
{
workerThreads = 500;
iocpThreads = 1000;
m_log.Info("[OPENSIM MAIN]: Bumping up to 500 worker threads and 1000 IOCP threads");
System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads);
workerThreads = workerThreadsMin;
m_log.InfoFormat("[OPENSIM MAIN]: Bumping up to worker threads to {0}",workerThreads);
}
if (workerThreads > workerThreadsMax)
{
workerThreads = workerThreadsMax;
m_log.InfoFormat("[OPENSIM MAIN]: Limiting worker threads to {0}",workerThreads);
}
// Increase the number of IOCP threads available.
// Mono defaults to a tragically low number (24 on 6-core / 8GB Fedora 17)
if (iocpThreads < iocpThreadsMin)
{
iocpThreads = iocpThreadsMin;
m_log.InfoFormat("[OPENSIM MAIN]: Bumping up IO completion threads to {0}",iocpThreads);
}
// Make sure we don't overallocate IOCP threads and thrash system resources
if ( iocpThreads > iocpThreadsMax )
{
iocpThreads = iocpThreadsMax;
m_log.InfoFormat("[OPENSIM MAIN]: Limiting IO completion threads to {0}",iocpThreads);
}
// set the resulting worker and IO completion thread counts back to ThreadPool
if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) )
{
m_log.InfoFormat("[OPENSIM MAIN]: Threadpool set to {0} worker threads and {1} IO completion threads", workerThreads, iocpThreads);
}
else
{
m_log.Info("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect.");
}
// Check if the system is compatible with OpenSimulator.
// Ensures that the minimum system requirements are met

View File

@@ -59,6 +59,8 @@ namespace OpenSim.Region.ClientStack.Linden
// private static readonly ILog m_log =
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
private Scene m_scene;
/// <summary>
@@ -94,6 +96,8 @@ namespace OpenSim.Region.ClientStack.Linden
{
m_scene = s;
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
m_scene.RegisterModuleInterface<ISimulatorFeaturesModule>(this);
}
public void RemoveRegion(Scene s)
@@ -156,7 +160,7 @@ namespace OpenSim.Region.ClientStack.Linden
IRequestHandler reqHandler
= new RestHTTPHandler(
"GET", "/CAPS/" + UUID.Random(),
HandleSimulatorFeaturesRequest, "SimulatorFeatures", agentID.ToString());
x => { return HandleSimulatorFeaturesRequest(x, agentID); }, "SimulatorFeatures", agentID.ToString());
caps.RegisterHandler("SimulatorFeatures", reqHandler);
}
@@ -185,18 +189,33 @@ namespace OpenSim.Region.ClientStack.Linden
return new OSDMap(m_features);
}
private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod)
private OSDMap DeepCopy()
{
// This isn't the cheapest way of doing this but the rate
// of occurrence is low (on sim entry only) and it's a sure
// way to get a true deep copy.
OSD copy = OSDParser.DeserializeLLSDXml(OSDParser.SerializeLLSDXmlString(m_features));
return (OSDMap)copy;
}
private Hashtable HandleSimulatorFeaturesRequest(Hashtable mDhttpMethod, UUID agentID)
{
// m_log.DebugFormat("[SIMULATOR FEATURES MODULE]: SimulatorFeatures request");
OSDMap copy = DeepCopy();
SimulatorFeaturesRequestDelegate handlerOnSimulatorFeaturesRequest = OnSimulatorFeaturesRequest;
if (handlerOnSimulatorFeaturesRequest != null)
handlerOnSimulatorFeaturesRequest(agentID, ref copy);
//Send back data
Hashtable responsedata = new Hashtable();
responsedata["int_response_code"] = 200;
responsedata["content_type"] = "text/plain";
responsedata["keepalive"] = false;
lock (m_features)
responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(m_features);
responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(copy);
return responsedata;
}

View File

@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
public class AssetTransactionModule : INonSharedRegionModule,
IAgentAssetTransactions
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected Scene m_Scene;
private bool m_dumpAssetsToFile = false;

View File

@@ -299,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Asset
}
catch (Exception e)
{
m_log.ErrorFormat(
m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}",
asset.ID, e.Message, e.StackTrace);
}
@@ -339,12 +339,13 @@ namespace OpenSim.Region.CoreModules.Asset
/// Try to get an asset from the file cache.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <returns>An asset retrieved from the file cache. null if there was a problem retrieving an asset.</returns>
private AssetBase GetFromFileCache(string id)
{
AssetBase asset = null;
string filename = GetFileName(id);
if (File.Exists(filename))
{
FileStream stream = null;
@@ -359,7 +360,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);
@@ -371,7 +372,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);
}
@@ -469,7 +470,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);
}
@@ -520,29 +521,39 @@ namespace OpenSim.Region.CoreModules.Asset
/// <param name="purgeLine"></param>
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);
}
}
@@ -601,7 +612,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);
@@ -680,17 +691,31 @@ namespace OpenSim.Region.CoreModules.Asset
/// <summary>
/// This notes the last time the Region had a deep asset scan performed on it.
/// </summary>
/// <param name="RegionID"></param>
private void StampRegionStatusFile(UUID RegionID)
/// <param name="regionID"></param>
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);
}
}
@@ -759,7 +784,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);
}
@@ -773,7 +798,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);
}

View File

@@ -44,7 +44,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
public class DAExampleModule : INonSharedRegionModule
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly bool ENABLED = false; // enable for testing

View File

@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
try
{
IConfig statConfig = source.Configs["Statistics.Binary"];
if (statConfig.Contains("enabled") && statConfig.GetBoolean("enabled"))
if (statConfig != null && statConfig.Contains("enabled") && statConfig.GetBoolean("enabled"))
{
if (statConfig.Contains("collect_region_stats"))
{

View File

@@ -111,13 +111,15 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC
m_rpcPending = new Dictionary<UUID, RPCRequestInfo>();
m_rpcPendingResponses = new Dictionary<UUID, RPCRequestInfo>();
m_pendingSRDResponses = new Dictionary<UUID, SendRemoteDataRequest>();
try
{
m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
}
catch (Exception)
if (config.Configs["XMLRPC"] != null)
{
try
{
m_remoteDataPort = config.Configs["XMLRPC"].GetInt("XmlRpcPort", m_remoteDataPort);
}
catch (Exception)
{
}
}
}

View File

@@ -31,6 +31,16 @@ using OpenMetaverse;
namespace OpenSim.Region.Framework.Interfaces
{
// these could be expanded at some point to provide more type information
// for now value accounts for all base types
public enum JsonStoreNodeType
{
Undefined = 0,
Object = 1,
Array = 2,
Value = 3
}
public delegate void TakeValueCallback(string s);
public interface IJsonStoreModule
@@ -38,13 +48,18 @@ namespace OpenSim.Region.Framework.Interfaces
bool AttachObjectStore(UUID objectID);
bool CreateStore(string value, ref UUID result);
bool DestroyStore(UUID storeID);
JsonStoreNodeType GetPathType(UUID storeID, string path);
bool TestStore(UUID storeID);
bool TestPath(UUID storeID, string path, bool useJson);
bool SetValue(UUID storeID, string path, string value, bool useJson);
bool RemoveValue(UUID storeID, string path);
bool GetValue(UUID storeID, string path, bool useJson, out string value);
void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback);
void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback);
int GetArrayLength(UUID storeID, string path);
}
}

View File

@@ -26,18 +26,22 @@
*/
using System;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenSim.Region.Framework.Interfaces
{
public delegate void SimulatorFeaturesRequestDelegate(UUID agentID, ref OSDMap features);
/// <summary>
/// Add remove or retrieve Simulator Features that will be given to a viewer via the SimulatorFeatures capability.
/// </summary>
public interface ISimulatorFeaturesModule
{
event SimulatorFeaturesRequestDelegate OnSimulatorFeaturesRequest;
void AddFeature(string name, OSD value);
bool RemoveFeature(string name);
bool TryGetFeature(string name, out OSD value);
OSDMap GetFeatures();
}
}
}

View File

@@ -790,6 +790,19 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="obj">The object being removed from the scene</param>
public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
/// <summary>
/// Triggered when an object is placed into the physical scene (PhysicsActor created).
/// </summary>
public event Action<SceneObjectPart> OnObjectAddedToPhysicalScene;
/// <summary>
/// Triggered when an object is removed from the physical scene (PhysicsActor destroyed).
/// </summary>
/// <remarks>
/// Note: this is triggered just before the PhysicsActor is removed from the
/// physics engine so the receiver can do any necessary cleanup before its destruction.
/// </remarks>
public event Action<SceneObjectPart> OnObjectRemovedFromPhysicalScene;
/// <summary>
/// Triggered when an object is removed from the scene.
/// </summary>
@@ -1516,6 +1529,48 @@ namespace OpenSim.Region.Framework.Scenes
}
}
public void TriggerObjectAddedToPhysicalScene(SceneObjectPart obj)
{
Action<SceneObjectPart> handler = OnObjectAddedToPhysicalScene;
if (handler != null)
{
foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
{
try
{
d(obj);
}
catch (Exception e)
{
m_log.ErrorFormat(
"[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}",
e.Message, e.StackTrace);
}
}
}
}
public void TriggerObjectRemovedFromPhysicalScene(SceneObjectPart obj)
{
Action<SceneObjectPart> handler = OnObjectRemovedFromPhysicalScene;
if (handler != null)
{
foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
{
try
{
d(obj);
}
catch (Exception e)
{
m_log.ErrorFormat(
"[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}",
e.Message, e.StackTrace);
}
}
}
}
public void TriggerShutdown()
{
Action handlerShutdown = OnShutdown;

View File

@@ -5506,8 +5506,13 @@ namespace OpenSim.Region.Framework.Scenes
if (banned)
{
reason = "No suitable landing point found";
return false;
if(Permissions.IsAdministrator(agentID) == false || Permissions.IsGridGod(agentID) == false)
{
reason = "No suitable landing point found";
return false;
}
reason = "Administrative access only";
return true;
}
}
}

View File

@@ -4316,6 +4316,7 @@ namespace OpenSim.Region.Framework.Scenes
}
PhysActor = pa;
ParentGroup.Scene.EventManager.TriggerObjectAddedToPhysicalScene(this);
}
/// <summary>
@@ -4328,6 +4329,7 @@ namespace OpenSim.Region.Framework.Scenes
/// </remarks>
public void RemoveFromPhysics()
{
ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this);
ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
PhysActor = null;
}

View File

@@ -4021,6 +4021,7 @@ namespace OpenSim.Region.Framework.Scenes
(m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
(m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)
{
if (GodLevel < 200 &&
((!m_scene.Permissions.IsGod(m_uuid) &&
!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) ||
@@ -4029,7 +4030,14 @@ namespace OpenSim.Region.Framework.Scenes
{
SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray();
if (spawnPoints.Length == 0)
{
if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid))
{
pos.X = 128.0f;
pos.Y = 128.0f;
}
return;
}
int index;
bool selected = false;
@@ -4038,6 +4046,8 @@ namespace OpenSim.Region.Framework.Scenes
{
case "random":
if (spawnPoints.Length == 0)
return;
do
{
index = Util.RandomClass.Next(spawnPoints.Length - 1);
@@ -4049,6 +4059,7 @@ namespace OpenSim.Region.Framework.Scenes
// SpawnPoint sp = spawnPoints[index];
ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y);
if (land == null || land.IsEitherBannedOrRestricted(UUID))
selected = false;
else

View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using OpenSim.Framework;
using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.CoreModules;
using Mono.Addins;
using Nini.Config;
using log4net;
using OpenMetaverse;
namespace OpenSim.Region.OptionalModules.Scripting
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
public class ExtendedPhysics : INonSharedRegionModule
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[EXTENDED PHYSICS]";
private IConfig Configuration { get; set; }
private bool Enabled { get; set; }
private Scene BaseScene { get; set; }
private IScriptModuleComms Comms { get; set; }
#region INonSharedRegionModule
public string Name { get { return this.GetType().Name; } }
public void Initialise(IConfigSource config)
{
BaseScene = null;
Enabled = false;
Configuration = null;
Comms = null;
try
{
if ((Configuration = config.Configs["ExtendedPhysics"]) != null)
{
Enabled = Configuration.GetBoolean("Enabled", Enabled);
}
}
catch (Exception e)
{
m_log.ErrorFormat("{0} Initialization error: {0}", LogHeader, e);
}
m_log.InfoFormat("{0} module {1} enabled", LogHeader, (Enabled ? "is" : "is not"));
}
public void Close()
{
if (BaseScene != null)
{
BaseScene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene;
BaseScene.EventManager.OnSceneObjectPartUpdated -= EventManager_OnSceneObjectPartUpdated;
BaseScene = null;
}
}
public void AddRegion(Scene scene)
{
}
public void RemoveRegion(Scene scene)
{
if (BaseScene != null && BaseScene == scene)
{
Close();
}
}
public void RegionLoaded(Scene scene)
{
if (!Enabled) return;
BaseScene = scene;
Comms = BaseScene.RequestModuleInterface<IScriptModuleComms>();
if (Comms == null)
{
m_log.WarnFormat("{0} ScriptModuleComms interface not defined", LogHeader);
Enabled = false;
return;
}
// Register as LSL functions all the [ScriptInvocation] marked methods.
Comms.RegisterScriptInvocations(this);
// When an object is modified, we might need to update its extended physics parameters
BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
BaseScene.EventManager.OnSceneObjectPartUpdated += EventManager_OnSceneObjectPartUpdated;
}
public Type ReplaceableInterface { get { return null; } }
#endregion // INonSharedRegionModule
private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
{
throw new NotImplementedException();
}
// Event generated when some property of a prim changes.
private void EventManager_OnSceneObjectPartUpdated(SceneObjectPart sop, bool isFullUpdate)
{
}
[ScriptConstant]
public static int PHYS_CENTER_OF_MASS = 1 << 0;
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_CONSTRAINT = 1;
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_COMPOUND = 2;
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_MANUAL = 3;
[ScriptInvocation]
public string physGetEngineType(UUID hostID, UUID scriptID)
{
string ret = string.Empty;
if (BaseScene.PhysicsScene != null)
{
ret = BaseScene.PhysicsScene.EngineType;
}
return ret;
}
[ScriptInvocation]
public void physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
{
}
}
}

View File

@@ -68,23 +68,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
protected List<TakeValueCallbackClass> m_TakeStore;
protected List<TakeValueCallbackClass> m_ReadStore;
// add separators for quoted paths
protected static Regex m_ParsePassOne = new Regex("{[^}]+}");
// add separators for array references
protected static Regex m_ParsePassTwo = new Regex("(\\[[0-9]+\\]|\\[\\+\\])");
// add separators for quoted paths and array references
protected static Regex m_ParsePassOne = new Regex("({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
// add quotes to bare identifiers which are limited to alphabetic characters
protected static Regex m_ParsePassThree = new Regex("\\.([a-zA-Z]+)");
protected static Regex m_ParsePassThree = new Regex("(?<!{[^}]*)\\.([a-zA-Z]+)(?=\\.)");
// remove extra separator characters
protected static Regex m_ParsePassFour = new Regex("\\.+");
// expression used to validate the full path, this is canonical representation
protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)+$");
protected static Regex m_ValidatePath = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)*$");
// expression used to match path components
protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\]+)");
protected static Regex m_PathComponent = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])");
// extract the internals of an array reference
protected static Regex m_SimpleArrayPattern = new Regex("\\[([0-9]+)\\]");
@@ -107,9 +104,17 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
///
/// </summary>
// -----------------------------------------------------------------
public static string CanonicalPathExpression(string path)
public static bool CanonicalPathExpression(string ipath, out string opath)
{
return PathExpressionToKey(ParsePathExpression(path));
Stack<string> path;
if (! ParsePathExpression(ipath,out path))
{
opath = "";
return false;
}
opath = PathExpressionToKey(path);
return true;
}
// -----------------------------------------------------------------
@@ -123,15 +128,46 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
m_TakeStore = new List<TakeValueCallbackClass>();
m_ReadStore = new List<TakeValueCallbackClass>();
}
public JsonStore(string value) : this()
{
// This is going to throw an exception if the value is not
// a valid JSON chunk. Calling routines should catch the
// exception and handle it appropriately
if (String.IsNullOrEmpty(value))
ValueStore = new OSDMap();
else
ValueStore = OSDParser.DeserializeJson(value);
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public JsonStoreNodeType PathType(string expr)
{
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return JsonStoreNodeType.Undefined;
OSD result = ProcessPathExpression(ValueStore,path);
if (result == null)
return JsonStoreNodeType.Undefined;
if (result is OSDMap)
return JsonStoreNodeType.Object;
if (result is OSDArray)
return JsonStoreNodeType.Array;
if (OSDBaseType(result.Type))
return JsonStoreNodeType.Value;
return JsonStoreNodeType.Undefined;
}
// -----------------------------------------------------------------
/// <summary>
///
@@ -139,18 +175,42 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// -----------------------------------------------------------------
public bool TestPath(string expr, bool useJson)
{
Stack<string> path = ParsePathExpression(expr);
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return false;
OSD result = ProcessPathExpression(ValueStore,path);
if (result == null)
return false;
if (useJson || result.Type == OSDType.String)
if (useJson || OSDBaseType(result.Type))
return true;
return false;
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public int ArrayLength(string expr)
{
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return -1;
OSD result = ProcessPathExpression(ValueStore,path);
if (result != null && result.Type == OSDType.Array)
{
OSDArray arr = result as OSDArray;
return arr.Count;
}
return -1;
}
// -----------------------------------------------------------------
/// <summary>
///
@@ -158,7 +218,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// -----------------------------------------------------------------
public bool GetValue(string expr, out string value, bool useJson)
{
Stack<string> path = ParsePathExpression(expr);
Stack<string> path;
if (! ParsePathExpression(expr,out path))
{
value = "";
return false;
}
OSD result = ProcessPathExpression(ValueStore,path);
return ConvertOutputValue(result,out value,useJson);
}
@@ -181,7 +247,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// -----------------------------------------------------------------
public bool SetValue(string expr, string value, bool useJson)
{
OSD ovalue = useJson ? OSDParser.DeserializeJson(value) : new OSDString(value);
OSD ovalue;
// One note of caution... if you use an empty string in the
// structure it will be assumed to be a default value and will
// not be seialized in the json
if (useJson)
{
// There doesn't appear to be a good way to determine if the
// value is valid Json other than to let the parser crash
try
{
ovalue = OSDParser.DeserializeJson(value);
}
catch (Exception e)
{
if (value.StartsWith("'") && value.EndsWith("'"))
{
ovalue = new OSDString(value.Substring(1,value.Length - 2));
}
else
{
return false;
}
}
}
else
{
ovalue = new OSDString(value);
}
return SetValueFromExpression(expr,ovalue);
}
@@ -192,7 +288,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// -----------------------------------------------------------------
public bool TakeValue(string expr, bool useJson, TakeValueCallback cback)
{
Stack<string> path = ParsePathExpression(expr);
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return false;
string pexpr = PathExpressionToKey(path);
OSD result = ProcessPathExpression(ValueStore,path);
@@ -223,7 +322,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// -----------------------------------------------------------------
public bool ReadValue(string expr, bool useJson, TakeValueCallback cback)
{
Stack<string> path = ParsePathExpression(expr);
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return false;
string pexpr = PathExpressionToKey(path);
OSD result = ProcessPathExpression(ValueStore,path);
@@ -253,7 +355,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// -----------------------------------------------------------------
protected bool SetValueFromExpression(string expr, OSD ovalue)
{
Stack<string> path = ParsePathExpression(expr);
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return false;
if (path.Count == 0)
{
ValueStore = ovalue;
@@ -399,34 +504,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
/// use a stack because we process the path in inverse order later
/// </summary>
// -----------------------------------------------------------------
protected static Stack<string> ParsePathExpression(string path)
protected static bool ParsePathExpression(string expr, out Stack<string> path)
{
Stack<string> m_path = new Stack<string>();
path = new Stack<string>();
// add front and rear separators
path = "." + path + ".";
expr = "." + expr + ".";
// add separators for quoted paths
path = m_ParsePassOne.Replace(path,".$0.",-1,0);
// add separators for array references
path = m_ParsePassTwo.Replace(path,".$0.",-1,0);
// add separators for quoted exprs and array references
expr = m_ParsePassOne.Replace(expr,".$1.",-1,0);
// add quotes to bare identifier
path = m_ParsePassThree.Replace(path,".{$1}",-1,0);
expr = m_ParsePassThree.Replace(expr,".{$1}",-1,0);
// remove extra separators
path = m_ParsePassFour.Replace(path,".",-1,0);
expr = m_ParsePassFour.Replace(expr,".",-1,0);
// validate the results (catches extra quote characters for example)
if (m_ValidatePath.IsMatch(path))
if (m_ValidatePath.IsMatch(expr))
{
MatchCollection matches = m_PathComponent.Matches(path,0);
MatchCollection matches = m_PathComponent.Matches(expr,0);
foreach (Match match in matches)
m_path.Push(match.Groups[1].Value);
path.Push(match.Groups[1].Value);
return true;
}
return m_path;
return false;
}
// -----------------------------------------------------------------
@@ -516,14 +620,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// The path pointed to an intermediate hash structure
if (result.Type == OSDType.Map)
{
value = OSDParser.SerializeJsonString(result as OSDMap);
value = OSDParser.SerializeJsonString(result as OSDMap,true);
return true;
}
// The path pointed to an intermediate hash structure
if (result.Type == OSDType.Array)
{
value = OSDParser.SerializeJsonString(result as OSDArray);
value = OSDParser.SerializeJsonString(result as OSDArray,true);
return true;
}
@@ -531,7 +635,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return true;
}
if (result.Type == OSDType.String)
if (OSDBaseType(result.Type))
{
value = result.AsString();
return true;
@@ -557,6 +661,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return pkey;
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
protected static bool OSDBaseType(OSDType type)
{
// Should be the list of base types for which AsString() returns
// something useful
if (type == OSDType.Boolean)
return true;
if (type == OSDType.Integer)
return true;
if (type == OSDType.Real)
return true;
if (type == OSDType.String)
return true;
if (type == OSDType.UUID)
return true;
if (type == OSDType.Date)
return true;
if (type == OSDType.URI)
return true;
return false;
}
// -----------------------------------------------------------------
/// <summary>
///

View File

@@ -227,7 +227,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
}
catch (Exception e)
{
m_log.Error(string.Format("[JsonStore]: Unable to initialize store from {0}", value), e);
m_log.ErrorFormat("[JsonStore]: Unable to initialize store from {0}", value);
return false;
}
@@ -265,6 +265,38 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return m_JsonValueStore.ContainsKey(storeID);
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public JsonStoreNodeType GetPathType(UUID storeID, string path)
{
if (! m_enabled) return JsonStoreNodeType.Undefined;
JsonStore map = null;
lock (m_JsonValueStore)
{
if (! m_JsonValueStore.TryGetValue(storeID,out map))
{
m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
return JsonStoreNodeType.Undefined;
}
}
try
{
lock (map)
return map.PathType(path);
}
catch (Exception e)
{
m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
}
return JsonStoreNodeType.Undefined;
}
// -----------------------------------------------------------------
/// <summary>
///
@@ -370,6 +402,37 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return false;
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public int GetArrayLength(UUID storeID, string path)
{
if (! m_enabled) return -1;
JsonStore map = null;
lock (m_JsonValueStore)
{
if (! m_JsonValueStore.TryGetValue(storeID,out map))
return -1;
}
try
{
lock (map)
{
return map.ArrayLength(path);
}
}
catch (Exception e)
{
m_log.Error("[JsonStore]: unable to retrieve value", e);
}
return -1;
}
// -----------------------------------------------------------------
/// <summary>
///

View File

@@ -167,7 +167,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
try
{
m_comms.RegisterScriptInvocations(this);
m_comms.RegisterConstants(this);
// m_comms.RegisterScriptInvocation(this, "JsonCreateStore");
// m_comms.RegisterScriptInvocation(this, "JsonAttachObjectStore");
// m_comms.RegisterScriptInvocation(this, "JsonDestroyStore");
@@ -214,6 +215,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
#endregion
#region ScriptConstantsInterface
[ScriptConstant]
public static readonly int JSON_TYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
[ScriptConstant]
public static readonly int JSON_TYPE_OBJECT = (int)JsonStoreNodeType.Object;
[ScriptConstant]
public static readonly int JSON_TYPE_ARRAY = (int)JsonStoreNodeType.Array;
[ScriptConstant]
public static readonly int JSON_TYPE_VALUE = (int)JsonStoreNodeType.Value;
#endregion
#region ScriptInvocationInteface
// -----------------------------------------------------------------
/// <summary>
@@ -301,7 +318,16 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
[ScriptInvocation]
public string JsonList2Path(UUID hostID, UUID scriptID, object[] pathlist)
{
return JsonStore.CanonicalPathExpression(ConvertList2Path(pathlist));
string ipath = ConvertList2Path(pathlist);
string opath;
if (JsonStore.CanonicalPathExpression(ipath,out opath))
return opath;
// This won't parse if passed to the other routines as opposed to
// returning an empty string which is a valid path and would overwrite
// the entire store
return "**INVALID**";
}
// -----------------------------------------------------------------
@@ -309,6 +335,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
///
/// </summary>
// -----------------------------------------------------------------
[ScriptInvocation]
public int JsonGetPathType(UUID hostID, UUID scriptID, UUID storeID, string path)
{
return (int)m_store.GetPathType(storeID,path);
}
[ScriptInvocation]
public int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path)
{
@@ -333,7 +365,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
}
[ScriptInvocation]
public int JsonSetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
public int JsonSetJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value)
{
return m_store.SetValue(storeID,path,value,true) ? 1 : 0;
}
@@ -349,6 +381,17 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return m_store.RemoveValue(storeID,path) ? 1 : 0;
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
[ScriptInvocation]
public int JsonGetArrayLength(UUID hostID, UUID scriptID, UUID storeID, string path)
{
return m_store.GetArrayLength(storeID,path);
}
// -----------------------------------------------------------------
/// <summary>
///
@@ -363,7 +406,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
}
[ScriptInvocation]
public string JsonGetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path)
public string JsonGetJson(UUID hostID, UUID scriptID, UUID storeID, string path)
{
string value = String.Empty;
m_store.GetValue(storeID,path,true, out value);
@@ -421,6 +464,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
// -----------------------------------------------------------------
protected void GenerateRuntimeError(string msg)
{
m_log.InfoFormat("[JsonStore] runtime error: {0}",msg);
throw new Exception("JsonStore Runtime Error: " + msg);
}

View File

@@ -53,6 +53,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
private Scene m_scene;
private MockScriptEngine m_engine;
private ScriptModuleCommsModule m_smcm;
private JsonStoreScriptModule m_jssm;
[TestFixtureSetUp]
public void FixtureInit()
@@ -82,10 +83,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
m_engine = new MockScriptEngine();
m_smcm = new ScriptModuleCommsModule();
JsonStoreModule jsm = new JsonStoreModule();
JsonStoreScriptModule jssm = new JsonStoreScriptModule();
m_jssm = new JsonStoreScriptModule();
m_scene = new SceneHelpers().SetupScene();
SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, jssm);
SceneHelpers.SetupSceneModules(m_scene, configSource, m_engine, m_smcm, jsm, m_jssm);
try
{
@@ -115,8 +116,35 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
// Test blank store
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
}
// Test single element store
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
}
// Test with an integer value
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 42.15 }");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(value, Is.EqualTo("42.15"));
}
// Test with an array as the root node
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "[ 'one', 'two', 'three' ]");
Assert.That(storeId, Is.Not.EqualTo(UUID.Zero));
string value = (string)InvokeOp("JsonGetValue", storeId, "[1]");
Assert.That(value, Is.EqualTo("two"));
}
}
[Test]
@@ -144,8 +172,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
int dsrv = (int)InvokeOp("JsonDestroyStore", fakeStoreId);
// XXX: Current returns 'true' even though no such store existed. Need to ask if this is best behaviour.
Assert.That(dsrv, Is.EqualTo(1));
Assert.That(dsrv, Is.EqualTo(0));
}
[Test]
@@ -154,19 +181,64 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }");
string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(value, Is.EqualTo("World"));
{
string value = (string)InvokeOp("JsonGetValue", storeId, "Hello.World");
Assert.That(value, Is.EqualTo("Two"));
}
// Test get of path section instead of leaf
{
string value = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(value, Is.EqualTo(""));
}
// Test get of non-existing value
string fakeValueGet = (string)InvokeOp("JsonGetValue", storeId, "foo");
Assert.That(fakeValueGet, Is.EqualTo(""));
{
string fakeValueGet = (string)InvokeOp("JsonGetValue", storeId, "foo");
Assert.That(fakeValueGet, Is.EqualTo(""));
}
// Test get from non-existing store
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
string fakeStoreValueGet = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello");
Assert.That(fakeStoreValueGet, Is.EqualTo(""));
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
string fakeStoreValueGet = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello");
Assert.That(fakeStoreValueGet, Is.EqualTo(""));
}
}
[Test]
public void TestJsonGetJson()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Two' } }");
{
string value = (string)InvokeOp("JsonGetJson", storeId, "Hello.World");
Assert.That(value, Is.EqualTo("'Two'"));
}
// Test get of path section instead of leaf
{
string value = (string)InvokeOp("JsonGetJson", storeId, "Hello");
Assert.That(value, Is.EqualTo("{\"World\":\"Two\"}"));
}
// Test get of non-existing value
{
string fakeValueGet = (string)InvokeOp("JsonGetJson", storeId, "foo");
Assert.That(fakeValueGet, Is.EqualTo(""));
}
// Test get from non-existing store
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
string fakeStoreValueGet = (string)InvokeOp("JsonGetJson", fakeStoreId, "Hello");
Assert.That(fakeStoreValueGet, Is.EqualTo(""));
}
}
// [Test]
@@ -198,47 +270,237 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
// Test remove of node in object pointing to a string
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
Assert.That(returnValue, Is.EqualTo(1));
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
Assert.That(result, Is.EqualTo(0));
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
Assert.That(result, Is.EqualTo(0));
string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(returnValue2, Is.EqualTo(""));
string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(returnValue2, Is.EqualTo(""));
}
// Test remove of node in object pointing to another object
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'Wally' } }");
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
Assert.That(result, Is.EqualTo(0));
string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
Assert.That(returnValue2, Is.EqualTo(""));
}
// Test remove of node in an array
{
UUID storeId
= (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : [ 'value1', 'value2' ] }");
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello[0]");
Assert.That(result, Is.EqualTo(1));
result = (int)InvokeOp("JsonTestPath", storeId, "Hello[1]");
Assert.That(result, Is.EqualTo(0));
string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
Assert.That(stringReturnValue, Is.EqualTo("value2"));
stringReturnValue = (string)InvokeOp("JsonGetJson", storeId, "Hello[1]");
Assert.That(stringReturnValue, Is.EqualTo(""));
}
// Test remove of non-existing value
int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Hello");
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
// XXX: Is this the best response to removing a value that isn't there?
Assert.That(fakeValueRemove, Is.EqualTo(1));
int fakeValueRemove = (int)InvokeOp("JsonRemoveValue", storeId, "Cheese");
Assert.That(fakeValueRemove, Is.EqualTo(0));
}
// Test get from non-existing store
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello");
Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
{
// Test get from non-existing store
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueRemove = (int)InvokeOp("JsonRemoveValue", fakeStoreId, "Hello");
Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
}
}
// [Test]
// public void TestJsonTestPath()
// {
// TestHelpers.InMethod();
//// TestHelpers.EnableLogging();
//
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
//
// {
// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello.World");
// Assert.That(result, Is.EqualTo(1));
// }
//
// // Test for path which does not resolve to a value.
// {
// int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
// Assert.That(result, Is.EqualTo(0));
// }
//
// {
// int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo");
// Assert.That(result2, Is.EqualTo(0));
// }
//
// // Test with fake store
// {
// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello");
// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
// }
// }
// [Test]
// public void TestJsonTestPathJson()
// {
// TestHelpers.InMethod();
//// TestHelpers.EnableLogging();
//
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : 'One' } }");
//
// {
// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello.World");
// Assert.That(result, Is.EqualTo(1));
// }
//
// // Test for path which does not resolve to a value.
// {
// int result = (int)InvokeOp("JsonTestPathJson", storeId, "Hello");
// Assert.That(result, Is.EqualTo(1));
// }
//
// {
// int result2 = (int)InvokeOp("JsonTestPathJson", storeId, "foo");
// Assert.That(result2, Is.EqualTo(0));
// }
//
// // Test with fake store
// {
// UUID fakeStoreId = TestHelpers.ParseTail(0x500);
// int fakeStoreValueRemove = (int)InvokeOp("JsonTestPathJson", fakeStoreId, "Hello");
// Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
// }
// }
[Test]
public void TestJsonTestPath()
public void TestGetArrayLength()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : 'World' }");
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
int result = (int)InvokeOp("JsonTestPath", storeId, "Hello");
Assert.That(result, Is.EqualTo(1));
{
int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello.World");
Assert.That(result, Is.EqualTo(2));
}
int result2 = (int)InvokeOp("JsonTestPath", storeId, "foo");
Assert.That(result2, Is.EqualTo(0));
// Test path which is not an array
{
int result = (int)InvokeOp("JsonGetArrayLength", storeId, "Hello");
Assert.That(result, Is.EqualTo(-1));
}
// Test with fake store
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueRemove = (int)InvokeOp("JsonTestPath", fakeStoreId, "Hello");
Assert.That(fakeStoreValueRemove, Is.EqualTo(0));
// Test fake path
{
int result = (int)InvokeOp("JsonGetArrayLength", storeId, "foo");
Assert.That(result, Is.EqualTo(-1));
}
// Test fake store
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int result = (int)InvokeOp("JsonGetArrayLength", fakeStoreId, "Hello.World");
Assert.That(result, Is.EqualTo(-1));
}
}
[Test]
public void TestJsonGetPathType()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
{
int result = (int)InvokeOp("JsonGetPathType", storeId, ".");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_ARRAY));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[0]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[1]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
}
// Test for non-existant path
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "foo");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
}
// Test for non-existant store
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int result = (int)InvokeOp("JsonGetPathType", fakeStoreId, ".");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
}
}
[Test]
public void TestJsonList2Path()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
// Invoking these methods directly since I just couldn't get comms module invocation to work for some reason
// - some confusion with the methods that take a params object[] invocation.
{
string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo" });
Assert.That(result, Is.EqualTo("{foo}"));
}
{
string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", "bar" });
Assert.That(result, Is.EqualTo("{foo}.{bar}"));
}
{
string result = m_jssm.JsonList2Path(UUID.Zero, UUID.Zero, new object[] { "foo", 1, "bar" });
Assert.That(result, Is.EqualTo("{foo}.[1].{bar}"));
}
}
[Test]
@@ -247,18 +509,237 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times");
Assert.That(result, Is.EqualTo(1));
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
Assert.That(value, Is.EqualTo("Times"));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
Assert.That(value, Is.EqualTo("Times"));
}
// Test setting a key containing periods with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun.Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun.Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// *** Test [] ***
// Test setting a key containing unbalanced ] without delineation. Expecting failure
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun]Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun]Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test setting a key containing unbalanced [ without delineation. Expecting failure
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test setting a key containing unbalanced [] without delineation. Expecting failure
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun[]Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun[]Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test setting a key containing unbalanced ] with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun]Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun]Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// Test setting a key containing unbalanced [ with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// Test setting a key containing empty balanced [] with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[]Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[]Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// // Commented out as this currently unexpectedly fails.
// // Test setting a key containing brackets around an integer with delineation
// {
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
//
// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun[0]Circus}", "Times");
// Assert.That(result, Is.EqualTo(1));
//
// string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun[0]Circus}");
// Assert.That(value, Is.EqualTo("Times"));
// }
// *** Test {} ***
// Test setting a key containing unbalanced } without delineation. Expecting failure (?)
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun}Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test setting a key containing unbalanced { without delineation. Expecting failure (?)
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun{Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun}Circus");
Assert.That(value, Is.EqualTo(""));
}
// // Commented out as this currently unexpectedly fails.
// // Test setting a key containing unbalanced }
// {
// UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
//
// int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun}Circus}", "Times");
// Assert.That(result, Is.EqualTo(0));
// }
// Test setting a key containing unbalanced { with delineation
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Circus}", "Times");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Circus}");
Assert.That(value, Is.EqualTo("Times"));
}
// Test setting a key containing balanced {} with delineation. This should fail.
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "{Fun{Filled}Circus}", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "{Fun{Filled}Circus}");
Assert.That(value, Is.EqualTo(""));
}
// Test setting to location that does not exist. This should fail.
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{}");
int result = (int)InvokeOp("JsonSetValue", storeId, "Fun.Circus", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test with fake store
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueSet = (int)InvokeOp("JsonSetValue", fakeStoreId, "Hello", "World");
Assert.That(fakeStoreValueSet, Is.EqualTo(0));
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueSet = (int)InvokeOp("JsonSetValue", fakeStoreId, "Hello", "World");
Assert.That(fakeStoreValueSet, Is.EqualTo(0));
}
}
[Test]
public void TestJsonSetJson()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
// Single quoted token case
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "'Times'");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
Assert.That(value, Is.EqualTo("Times"));
}
// Sub-tree case
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "{ 'Filled' : 'Times' }");
Assert.That(result, Is.EqualTo(1));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Filled");
Assert.That(value, Is.EqualTo("Times"));
}
// If setting single strings in JsonSetValueJson, these must be single quoted tokens, not bare strings.
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
int result = (int)InvokeOp("JsonSetJson", storeId, "Fun", "Times");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun");
Assert.That(value, Is.EqualTo(""));
}
// Test setting to location that does not exist. This should fail.
{
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ }");
int result = (int)InvokeOp("JsonSetJson", storeId, "Fun.Circus", "'Times'");
Assert.That(result, Is.EqualTo(0));
string value = (string)InvokeOp("JsonGetValue", storeId, "Fun.Circus");
Assert.That(value, Is.EqualTo(""));
}
// Test with fake store
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int fakeStoreValueSet = (int)InvokeOp("JsonSetJson", fakeStoreId, "Hello", "'World'");
Assert.That(fakeStoreValueSet, Is.EqualTo(0));
}
}
/// <summary>
@@ -360,8 +841,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
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(""));
@@ -370,27 +850,24 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
}
{
// Read notecard to new multi-component path
// Read notecard to new multi-component path. This should not work.
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
// Read notecard to existing multi-component path. This should work
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(""));
@@ -398,11 +875,21 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
Assert.That(value, Is.EqualTo("World"));
}
{
// Read notecard to invalid path. This should not work.
UUID receivingStoreId = (UUID)InvokeOp("JsonCreateStore", "{ 'make' : { 'it' : 'so' } }");
UUID readNotecardRequestId = (UUID)InvokeOpOnHost("JsonReadNotecard", so.UUID, receivingStoreId, "/", notecardName);
Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
string value = (string)InvokeOp("JsonGetValue", receivingStoreId, "Hello");
Assert.That(value, Is.EqualTo(""));
}
{
// 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));
Assert.That(readNotecardRequestId, Is.Not.EqualTo(UUID.Zero));
string value = (string)InvokeOp("JsonGetValue", fakeStoreId, "Hello");
Assert.That(value, Is.EqualTo(""));

View File

@@ -183,6 +183,7 @@ public struct ConfigurationParameters
public float shouldEnableFrictionCaching;
public float numberOfSolverIterations;
public float useSingleSidedMeshes;
public float globalContactBreakingThreshold;
public float physicsLoggingFrames;
@@ -224,9 +225,10 @@ public enum CollisionFlags : uint
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
// Following used by BulletSim to control collisions and updates
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
BS_FLOATS_ON_WATER = 1 << 11,
BS_VEHICLE_COLLISIONS = 1 << 12,
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
BS_NONE = 0,
BS_ALL = 0xFFFFFFFF
};

View File

@@ -45,7 +45,6 @@ public sealed class BSCharacter : BSPhysObject
private bool _selected;
private OMV.Vector3 _position;
private float _mass;
private float _avatarDensity;
private float _avatarVolume;
private OMV.Vector3 _force;
private OMV.Vector3 _velocity;
@@ -63,9 +62,6 @@ public sealed class BSCharacter : BSPhysObject
private bool _kinematic;
private float _buoyancy;
// The friction and velocity of the avatar is modified depending on whether walking or not.
private float _currentFriction; // the friction currently being used (changed by setVelocity).
private BSVMotor _velocityMotor;
private OMV.Vector3 _PIDTarget;
@@ -86,8 +82,8 @@ public sealed class BSCharacter : BSPhysObject
_orientation = OMV.Quaternion.Identity;
_velocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
_currentFriction = BSParam.AvatarStandingFriction;
_avatarDensity = BSParam.AvatarDensity;
Friction = BSParam.AvatarStandingFriction;
Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values.
@@ -104,7 +100,7 @@ public sealed class BSCharacter : BSPhysObject
SetupMovementMotor();
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
LocalID, _size, Scale, Density, _avatarVolume, RawMass);
// do actual creation in taint time
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
@@ -140,7 +136,7 @@ public sealed class BSCharacter : BSPhysObject
ZeroMotion(true);
ForcePosition = _position;
// Set the velocity and compute the proper friction
// Set the velocity
_velocityMotor.Reset();
_velocityMotor.SetTarget(_velocity);
_velocityMotor.SetCurrent(_velocity);
@@ -214,35 +210,47 @@ public sealed class BSCharacter : BSPhysObject
_velocityMotor.Step(timeStep);
// If we're not supposed to be moving, make sure things are zero.
if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero && IsColliding)
if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero)
{
// The avatar shouldn't be moving
_velocityMotor.Zero();
// If we are colliding with a stationary object, presume we're standing and don't move around
if (!ColliderIsMoving)
if (IsColliding)
{
DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
ZeroMotion(true /* inTaintTime */);
// If we are colliding with a stationary object, presume we're standing and don't move around
if (!ColliderIsMoving)
{
DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
ZeroMotion(true /* inTaintTime */);
}
// Standing has more friction on the ground
if (Friction != BSParam.AvatarStandingFriction)
{
Friction = BSParam.AvatarStandingFriction;
PhysicsScene.PE.SetFriction(PhysBody, Friction);
}
}
else
{
if (Flying)
{
// Flying and not collising and velocity nearly zero.
ZeroMotion(true /* inTaintTime */);
}
}
// Standing has more friction on the ground
if (_currentFriction != BSParam.AvatarStandingFriction)
{
_currentFriction = BSParam.AvatarStandingFriction;
PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
}
DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1}", LocalID, _velocityMotor.TargetValue);
DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
}
else
{
OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
if (_currentFriction != BSParam.AvatarFriction)
if (Friction != BSParam.AvatarFriction)
{
// Probably starting up walking. Set friction to moving friction.
_currentFriction = BSParam.AvatarFriction;
PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
Friction = BSParam.AvatarFriction;
PhysicsScene.PE.SetFriction(PhysBody, Friction);
}
// If falling, we keep the world's downward vector no matter what the other axis specify.
@@ -275,7 +283,7 @@ public sealed class BSCharacter : BSPhysObject
// This test is done if moving forward, not flying and is colliding with something.
// DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
// LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
if (IsColliding && !Flying && TargetSpeed > 0.1f /* && ForwardSpeed < 0.1f */)
if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
{
// The range near the character's feet where we will consider stairs
float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
@@ -342,7 +350,7 @@ public sealed class BSCharacter : BSPhysObject
Scale = ComputeAvatarScale(_size);
ComputeAvatarVolumeAndMass();
DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
LocalID, _size, Scale, Density, _avatarVolume, RawMass);
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
{
@@ -870,7 +878,7 @@ public sealed class BSCharacter : BSPhysObject
* Math.Min(Size.X, Size.Y) / 2
* Size.Y / 2f // plus the volume of the capsule end caps
);
_mass = _avatarDensity * _avatarVolume;
_mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
}
// The physics engine says that properties have updated. Update same and inform
@@ -901,7 +909,7 @@ public sealed class BSCharacter : BSPhysObject
CurrentEntityProperties = entprop;
// Tell the linkset about value changes
Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
// Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
// base.RequestPhysicsterseUpdate();

View File

@@ -597,7 +597,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if (IsActive)
{
// Remember the mass so we don't have to fetch it every step
m_vehicleMass = Prim.Linkset.LinksetMass;
m_vehicleMass = Prim.TotalMass;
// Friction affects are handled by this vehicle code
PhysicsScene.PE.SetFriction(Prim.PhysBody, BSParam.VehicleFriction);

View File

@@ -52,7 +52,7 @@ public abstract class BSLinkset
Manual = 2 // linkset tied together manually (code moves all the pieces)
}
// Create the correct type of linkset for this child
public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
{
BSLinkset ret = null;
@@ -71,10 +71,14 @@ public abstract class BSLinkset
ret = new BSLinksetCompound(physScene, parent);
break;
}
if (ret == null)
{
physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
}
return ret;
}
public BSPhysObject LinksetRoot { get; protected set; }
public BSPrimLinkable LinksetRoot { get; protected set; }
public BSScene PhysicsScene { get; private set; }
@@ -82,7 +86,7 @@ public abstract class BSLinkset
public int LinksetID { get; private set; }
// The children under the root in this linkset.
protected HashSet<BSPhysObject> m_children;
protected HashSet<BSPrimLinkable> m_children;
// We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes
@@ -91,7 +95,7 @@ public abstract class BSLinkset
// Some linksets have a preferred physical shape.
// Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
{
return BSPhysicsShapeType.SHAPE_UNKNOWN;
}
@@ -111,7 +115,7 @@ public abstract class BSLinkset
get { return ComputeLinksetGeometricCenter(); }
}
protected BSLinkset(BSScene scene, BSPhysObject parent)
protected BSLinkset(BSScene scene, BSPrimLinkable parent)
{
// A simple linkset of one (no children)
LinksetID = m_nextLinksetID++;
@@ -120,16 +124,18 @@ public abstract class BSLinkset
m_nextLinksetID = 1;
PhysicsScene = scene;
LinksetRoot = parent;
m_children = new HashSet<BSPhysObject>();
m_children = new HashSet<BSPrimLinkable>();
LinksetMass = parent.RawMass;
Rebuilding = false;
parent.ClearDisplacement();
}
// Link to a linkset where the child knows the parent.
// Parent changing should not happen so do some sanity checking.
// We return the parent's linkset so the child can track its membership.
// Called at runtime.
public BSLinkset AddMeToLinkset(BSPhysObject child)
public BSLinkset AddMeToLinkset(BSPrimLinkable child)
{
lock (m_linksetActivityLock)
{
@@ -145,14 +151,13 @@ public abstract class BSLinkset
// Returns a new linkset for the child which is a linkset of one (just the
// orphened child).
// Called at runtime.
public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child)
{
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
// Cannot remove the root from a linkset.
child.PositionDisplacement = OMV.Vector3.Zero;
return this;
}
RemoveChildFromLinkset(child);
@@ -160,12 +165,11 @@ public abstract class BSLinkset
}
// The child is down to a linkset of just itself
child.PositionDisplacement = OMV.Vector3.Zero;
return BSLinkset.Factory(PhysicsScene, child);
}
// Return 'true' if the passed object is the root object of this linkset
public bool IsRoot(BSPhysObject requestor)
public bool IsRoot(BSPrimLinkable requestor)
{
return (requestor.LocalID == LinksetRoot.LocalID);
}
@@ -176,14 +180,14 @@ public abstract class BSLinkset
public bool HasAnyChildren { get { return (m_children.Count > 0); } }
// Return 'true' if this child is in this linkset
public bool HasChild(BSPhysObject child)
public bool HasChild(BSPrimLinkable child)
{
bool ret = false;
lock (m_linksetActivityLock)
{
ret = m_children.Contains(child);
/* Safer version but the above should work
foreach (BSPhysObject bp in m_children)
foreach (BSPrimLinkable bp in m_children)
{
if (child.LocalID == bp.LocalID)
{
@@ -198,14 +202,14 @@ public abstract class BSLinkset
// Perform an action on each member of the linkset including root prim.
// Depends on the action on whether this should be done at taint time.
public delegate bool ForEachMemberAction(BSPhysObject obj);
public delegate bool ForEachMemberAction(BSPrimLinkable obj);
public virtual bool ForEachMember(ForEachMemberAction action)
{
bool ret = false;
lock (m_linksetActivityLock)
{
action(LinksetRoot);
foreach (BSPhysObject po in m_children)
foreach (BSPrimLinkable po in m_children)
{
if (action(po))
break;
@@ -216,16 +220,16 @@ public abstract class BSLinkset
// I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked.
protected abstract void AddChildToLinkset(BSPhysObject child);
protected abstract void AddChildToLinkset(BSPrimLinkable child);
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
protected abstract void RemoveChildFromLinkset(BSPhysObject child);
protected abstract void RemoveChildFromLinkset(BSPrimLinkable child);
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// May be called at runtime or taint-time.
public virtual void Refresh(BSPhysObject requestor)
public virtual void Refresh(BSPrimLinkable requestor)
{
LinksetMass = ComputeLinksetMass();
}
@@ -240,26 +244,26 @@ public abstract class BSLinkset
// has not yet been fully constructed.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
public abstract bool MakeDynamic(BSPhysObject child);
public abstract bool MakeDynamic(BSPrimLinkable child);
// The object is going static (non-physical). Do any setup necessary
// for a static linkset.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
public abstract bool MakeStatic(BSPhysObject child);
public abstract bool MakeStatic(BSPrimLinkable child);
// Called when a parameter update comes from the physics engine for any object
// of the linkset is received.
// Passed flag is update came from physics engine (true) or the user (false).
// Called at taint-time!!
public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject physObject);
public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
// Routine used when rebuilding the body of the root of the linkset
// Destroy all the constraints have have been made to root.
// This is called when the root body is changing.
// Returns 'true' of something was actually removed and would need restoring
// Called at taint-time!!
public abstract bool RemoveBodyDependencies(BSPrim child);
public abstract bool RemoveBodyDependencies(BSPrimLinkable child);
// ================================================================
protected virtual float ComputeLinksetMass()
@@ -269,7 +273,7 @@ public abstract class BSLinkset
{
lock (m_linksetActivityLock)
{
foreach (BSPhysObject bp in m_children)
foreach (BSPrimLinkable bp in m_children)
{
mass += bp.RawMass;
}
@@ -278,6 +282,7 @@ public abstract class BSLinkset
return mass;
}
// Computes linkset's center of mass in world coordinates.
protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
{
OMV.Vector3 com;
@@ -286,7 +291,7 @@ public abstract class BSLinkset
com = LinksetRoot.Position * LinksetRoot.RawMass;
float totalMass = LinksetRoot.RawMass;
foreach (BSPhysObject bp in m_children)
foreach (BSPrimLinkable bp in m_children)
{
com += bp.Position * bp.RawMass;
totalMass += bp.RawMass;
@@ -305,7 +310,7 @@ public abstract class BSLinkset
{
com = LinksetRoot.Position;
foreach (BSPhysObject bp in m_children)
foreach (BSPrimLinkable bp in m_children)
{
com += bp.Position;
}

View File

@@ -52,7 +52,7 @@ sealed class BSLinksetCompoundInfo : BSLinksetInfo
OffsetRot = r;
}
// 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape)
public BSLinksetCompoundInfo(int indx, BSPhysObject root, BSPhysObject child, OMV.Vector3 centerDisplacement)
public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement)
{
// Each child position and rotation is given relative to the center-of-mass.
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation);
@@ -93,12 +93,13 @@ public sealed class BSLinksetCompound : BSLinkset
{
private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
: base(scene, parent)
{
}
// For compound implimented linksets, if there are children, use compound shape for the root.
public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
{
// Returning 'unknown' means we don't have a preference.
BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
@@ -112,7 +113,7 @@ public sealed class BSLinksetCompound : BSLinkset
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
public override void Refresh(BSPhysObject requestor)
public override void Refresh(BSPrimLinkable requestor)
{
base.Refresh(requestor);
@@ -121,7 +122,7 @@ public sealed class BSLinksetCompound : BSLinkset
}
// Schedule a refresh to happen after all the other taint processing.
private void ScheduleRebuild(BSPhysObject requestor)
private void ScheduleRebuild(BSPrimLinkable requestor)
{
DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
@@ -143,7 +144,7 @@ public sealed class BSLinksetCompound : BSLinkset
// has not yet been fully constructed.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
public override bool MakeDynamic(BSPhysObject child)
public override bool MakeDynamic(BSPrimLinkable child)
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
@@ -173,7 +174,7 @@ public sealed class BSLinksetCompound : BSLinkset
// This doesn't normally happen -- OpenSim removes the objects from the physical
// world if it is a static linkset.
// Called at taint-time!
public override bool MakeStatic(BSPhysObject child)
public override bool MakeStatic(BSPrimLinkable child)
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
@@ -197,7 +198,7 @@ public sealed class BSLinksetCompound : BSLinkset
// 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
// Called at taint-time.
public override void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject updated)
public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
{
// The user moving a child around requires the rebuilding of the linkset compound shape
// One problem is this happens when a border is crossed -- the simulator implementation
@@ -217,59 +218,45 @@ public sealed class BSLinksetCompound : BSLinkset
// and that is caused by us updating the object.
if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
{
// Gather the child info. It might not be there if the linkset is in transition.
BSLinksetCompoundInfo lsi = updated.LinksetInfo as BSLinksetCompoundInfo;
if (lsi != null)
{
// Since the child moved or rotationed, it needs a new relative position within the linkset
BSLinksetCompoundInfo newLsi = new BSLinksetCompoundInfo(lsi.Index, LinksetRoot, updated, LinksetRoot.PositionDisplacement);
updated.LinksetInfo = newLsi;
// Find the physical instance of the child
if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
{
// It is possible that the linkset is still under construction and the child is not yet
// inserted into the compound shape. A rebuild of the linkset in a pre-step action will
// build the whole thing with the new position or rotation.
// The index must be checked because Bullet references the child array but does no validity
// checking of the child index passed.
int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
if (updated.LinksetChildIndex < numLinksetChildren)
{
// It is possible that the linkset is still under construction and the child is not yet
// inserted into the compound shape. A rebuild of the linkset in a pre-step action will
// build the whole thing with the new position or rotation.
// The index must be checked because Bullet references the child array but does no validity
// checking of the child index passed.
int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape);
if (lsi.Index < numLinksetChildren)
BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex);
if (linksetChildShape.HasPhysicalShape)
{
BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, lsi.Index);
if (linksetChildShape.HasPhysicalShape)
{
// Found the child shape within the compound shape
PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, lsi.Index,
newLsi.OffsetFromCenterOfMass,
newLsi.OffsetRot,
true /* shouldRecalculateLocalAabb */);
updatedChild = true;
DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},newLsi={2}",
updated.LocalID, whichUpdated, newLsi);
}
else // DEBUG DEBUG
{ // DEBUG DEBUG
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
updated.LocalID, linksetChildShape);
} // DEBUG DEBUG
// Found the child shape within the compound shape
PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex,
updated.RawPosition - LinksetRoot.RawPosition,
updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
true /* shouldRecalculateLocalAabb */);
updatedChild = true;
DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
}
else // DEBUG DEBUG
{ // DEBUG DEBUG
// the child is not yet in the compound shape. This is non-fatal.
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
updated.LocalID, numLinksetChildren, lsi.Index);
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
updated.LocalID, linksetChildShape);
} // DEBUG DEBUG
}
else // DEBUG DEBUG
{ // DEBUG DEBUG
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
// the child is not yet in the compound shape. This is non-fatal.
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
} // DEBUG DEBUG
}
else // DEBUG DEBUG
{ // DEBUG DEBUG
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noLinkSetInfo,rootPhysShape={1}",
updated.LocalID, LinksetRoot.PhysShape);
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
} // DEBUG DEBUG
if (!updatedChild)
@@ -291,7 +278,7 @@ public sealed class BSLinksetCompound : BSLinkset
// Since we don't keep in world relationships, do nothing unless it's a child changing.
// Returns 'true' of something was actually removed and would need restoring
// Called at taint-time!!
public override bool RemoveBodyDependencies(BSPrim child)
public override bool RemoveBodyDependencies(BSPrimLinkable child)
{
bool ret = false;
@@ -316,7 +303,7 @@ public sealed class BSLinksetCompound : BSLinkset
// When the linkset is built, the child shape is added to the compound shape relative to the
// root shape. The linkset then moves around but this does not move the actual child
// prim. The child prim's location must be recomputed based on the location of the root shape.
private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime)
{
// For the moment (20130201), disable this computation (converting the child physical addr back to
// a region address) until we have a good handle on center-of-mass offsets and what the physics
@@ -361,7 +348,7 @@ public sealed class BSLinksetCompound : BSLinkset
// Add a new child to the linkset.
// Called while LinkActivity is locked.
protected override void AddChildToLinkset(BSPhysObject child)
protected override void AddChildToLinkset(BSPrimLinkable child)
{
if (!HasChild(child))
{
@@ -377,8 +364,10 @@ public sealed class BSLinksetCompound : BSLinkset
// Remove the specified child from the linkset.
// Safe to call even if the child is not really in the linkset.
protected override void RemoveChildFromLinkset(BSPhysObject child)
protected override void RemoveChildFromLinkset(BSPrimLinkable child)
{
child.ClearDisplacement();
if (m_children.Remove(child))
{
DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
@@ -424,69 +413,65 @@ public sealed class BSLinksetCompound : BSLinkset
// The center of mass for the linkset is the geometric center of the group.
// Compute a displacement for each component so it is relative to the center-of-mass.
// Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
OMV.Vector3 centerOfMass;
OMV.Vector3 centerDisplacement = OMV.Vector3.Zero;
if (disableCOM) // DEBUG DEBUG
{ // DEBUG DEBUG
centerOfMass = LinksetRoot.RawPosition; // DEBUG DEBUG
LinksetRoot.PositionDisplacement = OMV.Vector3.Zero;
} // DEBUG DEBUG
else
OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
if (!disableCOM) // DEBUG DEBUG
{
centerOfMass = ComputeLinksetCenterOfMass();
// 'centerDisplacement' is the value to *add* to all the shape offsets
centerDisplacement = LinksetRoot.RawPosition - centerOfMass;
// Since we're displacing the center of the shape, we need to move the body in the world
LinksetRoot.PositionDisplacement = centerDisplacement;
// This causes the root prim position to be set properly based on the new PositionDisplacement
LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
// Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement);
// Compute a center-of-mass in world coordinates.
centerOfMassW = ComputeLinksetCenterOfMass();
}
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
// 'centerDisplacement' is the value to subtract from children to give physical offset position
OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement);
// This causes the physical position of the root prim to be offset to accomodate for the displacements
LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
// Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */,
-centerDisplacement,
OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
// Add a shape for each of the other children in the linkset
int memberIndex = 1;
ForEachMember(delegate(BSPhysObject cPrim)
ForEachMember(delegate(BSPrimLinkable cPrim)
{
if (!IsRoot(cPrim))
if (IsRoot(cPrim))
{
// Compute the displacement of the child from the root of the linkset.
// This info is saved in the child prim so the relationship does not
// change over time and the new child position can be computed
// when the linkset is being disassembled (the linkset may have moved).
BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
if (lci == null)
{
lci = new BSLinksetCompoundInfo(memberIndex, LinksetRoot, cPrim, centerDisplacement);
cPrim.LinksetInfo = lci;
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
}
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},lci={3}",
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci);
cPrim.LinksetChildIndex = 0;
}
else
{
cPrim.LinksetChildIndex = memberIndex;
if (cPrim.PhysShape.isNativeShape)
{
// A native shape is turned into a hull collision shape because native
// shapes are not shared so we have to hullify it so it will be tracked
// and freed at the correct time. This also solves the scaling problem
// (native shapes scaled but hull/meshes are assumed to not be).
// (native shapes scale but hull/meshes are assumed to not be).
// TODO: decide of the native shape can just be used in the compound shape.
// Use call to CreateGeomNonSpecial().
BulletShape saveShape = cPrim.PhysShape;
cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
// PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
BulletShape newShape = cPrim.PhysShape;
cPrim.PhysShape = saveShape;
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
}
else
{
@@ -498,9 +483,13 @@ public sealed class BSLinksetCompound : BSLinkset
PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
}
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetFromCenterOfMass, lci.OffsetRot);
OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
}
lci.Index = memberIndex;
memberIndex++;
}
return false; // 'false' says to move onto the next child in the list
@@ -509,12 +498,16 @@ public sealed class BSLinksetCompound : BSLinkset
// With all of the linkset packed into the root prim, it has the mass of everyone.
LinksetMass = ComputeLinksetMass();
LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
// Enable the physical position updator to return the position and rotation of the root shape
PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
}
finally
{
Rebuilding = false;
}
// See that the Aabb surrounds the new shape
PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
}
}

View File

@@ -36,7 +36,7 @@ public sealed class BSLinksetConstraints : BSLinkset
{
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
{
}
@@ -44,7 +44,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// its internal properties.
// This is queued in the 'post taint' queue so the
// refresh will happen once after all the other taints are applied.
public override void Refresh(BSPhysObject requestor)
public override void Refresh(BSPrimLinkable requestor)
{
base.Refresh(requestor);
@@ -65,7 +65,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// has not yet been fully constructed.
// Return 'true' if any properties updated on the passed object.
// Called at taint-time!
public override bool MakeDynamic(BSPhysObject child)
public override bool MakeDynamic(BSPrimLinkable child)
{
// What is done for each object in BSPrim is what we want.
return false;
@@ -76,14 +76,14 @@ public sealed class BSLinksetConstraints : BSLinkset
// This doesn't normally happen -- OpenSim removes the objects from the physical
// world if it is a static linkset.
// Called at taint-time!
public override bool MakeStatic(BSPhysObject child)
public override bool MakeStatic(BSPrimLinkable child)
{
// What is done for each object in BSPrim is what we want.
return false;
}
// Called at taint-time!!
public override void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject pObj)
public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
{
// Nothing to do for constraints on property updates
}
@@ -93,7 +93,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// up to rebuild the constraints before the next simulation step.
// Returns 'true' of something was actually removed and would need restoring
// Called at taint-time!!
public override bool RemoveBodyDependencies(BSPrim child)
public override bool RemoveBodyDependencies(BSPrimLinkable child)
{
bool ret = false;
@@ -114,7 +114,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// Add a new child to the linkset.
// Called while LinkActivity is locked.
protected override void AddChildToLinkset(BSPhysObject child)
protected override void AddChildToLinkset(BSPrimLinkable child)
{
if (!HasChild(child))
{
@@ -130,12 +130,12 @@ public sealed class BSLinksetConstraints : BSLinkset
// Remove the specified child from the linkset.
// Safe to call even if the child is not really in my linkset.
protected override void RemoveChildFromLinkset(BSPhysObject child)
protected override void RemoveChildFromLinkset(BSPrimLinkable child)
{
if (m_children.Remove(child))
{
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BSPhysObject childx = child;
BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
BSPrimLinkable childx = child;
DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
childx.LocalID,
@@ -159,13 +159,13 @@ public sealed class BSLinksetConstraints : BSLinkset
// Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
{
// Don't build the constraint when asked. Put it off until just before the simulation step.
Refresh(rootPrim);
}
private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
{
// Zero motion for children so they don't interpolate
childPrim.ZeroMotion(true);
@@ -239,7 +239,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// The root and child bodies are passed in because we need to remove the constraint between
// the bodies that were present at unlink time.
// Called at taint time!
private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
{
bool ret = false;
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
@@ -261,7 +261,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// Remove linkage between myself and any possible children I might have.
// Returns 'true' of any constraints were destroyed.
// Called at taint time!
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
{
DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
@@ -281,7 +281,7 @@ public sealed class BSLinksetConstraints : BSLinkset
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
foreach (BSPhysObject child in m_children)
foreach (BSPrimLinkable child in m_children)
{
// A child in the linkset physically shows the mass of the whole linkset.
// This allows Bullet to apply enough force on the child to move the whole linkset.

View File

@@ -49,6 +49,7 @@ public static class BSParam
public static float MaxLinearVelocity { get; private set; }
public static float MaxAngularVelocity { get; private set; }
public static float MaxAddForceMagnitude { get; private set; }
public static float DensityScaleFactor { get; private set; }
public static float LinearDamping { get; private set; }
public static float AngularDamping { get; private set; }
@@ -87,6 +88,7 @@ public static class BSParam
public static float NumberOfSolverIterations;
public static bool UseSingleSidedMeshes { get { return UseSingleSidedMeshesF != ConfigurationParameters.numericFalse; } }
public static float UseSingleSidedMeshesF;
public static float GlobalContactBreakingThreshold;
// Avatar parameters
public static float AvatarFriction { get; private set; }
@@ -280,29 +282,35 @@ public static class BSParam
new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
0.0001f,
(s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)MinimumObjectMass; },
(s) => { return MinimumObjectMass; },
(s,p,l,v) => { MinimumObjectMass = v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f,
(s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)MaximumObjectMass; },
(s) => { return MaximumObjectMass; },
(s,p,l,v) => { MaximumObjectMass = v; } ),
new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
1000.0f,
(s,cf,p,v) => { MaxLinearVelocity = cf.GetFloat(p, v); },
(s) => { return (float)MaxLinearVelocity; },
(s) => { return MaxLinearVelocity; },
(s,p,l,v) => { MaxLinearVelocity = v; } ),
new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
1000.0f,
(s,cf,p,v) => { MaxAngularVelocity = cf.GetFloat(p, v); },
(s) => { return (float)MaxAngularVelocity; },
(s) => { return MaxAngularVelocity; },
(s,p,l,v) => { MaxAngularVelocity = v; } ),
// LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
20000.0f,
(s,cf,p,v) => { MaxAddForceMagnitude = cf.GetFloat(p, v); },
(s) => { return (float)MaxAddForceMagnitude; },
(s) => { return MaxAddForceMagnitude; },
(s,p,l,v) => { MaxAddForceMagnitude = v; } ),
// Density is passed around as 100kg/m3. This scales that to 1kg/m3.
new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
0.01f,
(s,cf,p,v) => { DensityScaleFactor = cf.GetFloat(p, v); },
(s) => { return DensityScaleFactor; },
(s,p,l,v) => { DensityScaleFactor = v; } ),
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
2200f,
@@ -424,7 +432,7 @@ public static class BSParam
(s) => { return AvatarFriction; },
(s,p,l,v) => { AvatarFriction = v; } ),
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
10.0f,
0.95f,
(s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
(s) => { return AvatarStandingFriction; },
(s,p,l,v) => { AvatarStandingFriction = v; } ),
@@ -570,6 +578,11 @@ public static class BSParam
(s,cf,p,v) => { UseSingleSidedMeshesF = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
(s) => { return UseSingleSidedMeshesF; },
(s,p,l,v) => { UseSingleSidedMeshesF = v; s.UnmanagedParams[0].useSingleSidedMeshes = v; } ),
new ParameterDefn("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))",
0f,
(s,cf,p,v) => { GlobalContactBreakingThreshold = cf.GetFloat(p, v); },
(s) => { return GlobalContactBreakingThreshold; },
(s,p,l,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
(float)BSLinkset.LinksetImplementation.Compound,

View File

@@ -86,10 +86,6 @@ public abstract class BSPhysObject : PhysicsActor
PhysBody = new BulletBody(localID);
PhysShape = new BulletShape();
// A linkset of just me
Linkset = BSLinkset.Factory(PhysicsScene, this);
PositionDisplacement = OMV.Vector3.Zero;
LastAssetBuildFailed = false;
// Default material type. Also sets Friction, Restitution and Density.
@@ -103,6 +99,9 @@ public abstract class BSPhysObject : PhysicsActor
CollisionAccumulation = 0;
ColliderIsMoving = false;
CollisionScore = 0;
// All axis free.
LockedAxis = LockedAxisFree;
}
// Tell the object to clean up.
@@ -117,8 +116,6 @@ public abstract class BSPhysObject : PhysicsActor
public string PhysObjectName { get; protected set; }
public string TypeName { get; protected set; }
public BSLinkset Linkset { get; set; }
public BSLinksetInfo LinksetInfo { get; set; }
// Return the object mass without calculating it or having side effects
public abstract float RawMass { get; }
@@ -142,6 +139,7 @@ public abstract class BSPhysObject : PhysicsActor
// The objects base shape information. Null if not a prim type shape.
public PrimitiveBaseShape BaseShape { get; protected set; }
// Some types of objects have preferred physical representations.
// Returns SHAPE_UNKNOWN if there is no preference.
public virtual BSPhysicsShapeType PreferredPhysicalShape
@@ -156,15 +154,17 @@ public abstract class BSPhysObject : PhysicsActor
public EntityProperties LastEntityProperties { get; set; }
public virtual OMV.Vector3 Scale { get; set; }
public abstract bool IsSolid { get; }
public abstract bool IsStatic { get; }
public abstract bool IsSelected { get; }
// It can be confusing for an actor to know if it should move or update an object
// depeneding on the setting of 'selected', 'physical, ...
// This flag is the true test -- if true, the object is being acted on in the physical world
public abstract bool IsPhysicallyActive { get; }
// Detailed state of the object.
public abstract bool IsSolid { get; }
public abstract bool IsStatic { get; }
public abstract bool IsSelected { get; }
// Materialness
public MaterialAttributes.Material Material { get; private set; }
public override void SetMaterial(int material)
@@ -175,7 +175,8 @@ public abstract class BSPhysObject : PhysicsActor
MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
Friction = matAttrib.friction;
Restitution = matAttrib.restitution;
Density = matAttrib.density;
Density = matAttrib.density / BSParam.DensityScaleFactor;
DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
}
// Stop all physical motion.
@@ -188,26 +189,9 @@ public abstract class BSPhysObject : PhysicsActor
public abstract OMV.Vector3 RawPosition { get; set; }
public abstract OMV.Vector3 ForcePosition { get; set; }
// 'Position' and 'Orientation' is what the simulator thinks the positions of the prim is.
// Because Bullet needs the zero coordinate to be the center of mass of the linkset,
// sometimes it is necessary to displace the position the physics engine thinks
// the position is. PositionDisplacement must be added and removed from the
// position as the simulator position is stored and fetched from the physics
// engine. Similar to OrientationDisplacement.
public virtual OMV.Vector3 PositionDisplacement { get; set; }
public virtual OMV.Quaternion OrientationDisplacement { get; set; }
public abstract OMV.Quaternion RawOrientation { get; set; }
public abstract OMV.Quaternion ForceOrientation { get; set; }
public virtual float TargetSpeed
{
get
{
OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
return characterOrientedVelocity.X;
}
}
public abstract OMV.Vector3 RawVelocity { get; set; }
public abstract OMV.Vector3 ForceVelocity { get; set; }
@@ -217,6 +201,7 @@ public abstract class BSPhysObject : PhysicsActor
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
// The current velocity forward
public virtual float ForwardSpeed
{
get
@@ -225,6 +210,22 @@ public abstract class BSPhysObject : PhysicsActor
return characterOrientedVelocity.X;
}
}
// The forward speed we are trying to achieve (TargetVelocity)
public virtual float TargetVelocitySpeed
{
get
{
OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
return characterOrientedVelocity.X;
}
}
// The user can optionally set the center of mass. The user's setting will override any
// computed center-of-mass (like in linksets).
public OMV.Vector3? UserSetCenterOfMass { get; set; }
public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
#region Collisions
@@ -302,22 +303,16 @@ public abstract class BSPhysObject : PhysicsActor
CollidingObjectStep = PhysicsScene.SimulationStep;
}
// prims in the same linkset cannot collide with each other
if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
{
return ret;
}
CollisionAccumulation++;
// For movement tests, remember if we are colliding with an object that is moving.
ColliderIsMoving = collidee != null ? collidee.RawVelocity != OMV.Vector3.Zero : false;
ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
// If someone has subscribed for collision events log the collision so it will be reported up
if (SubscribedEvents()) {
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
ret = true;
}
@@ -428,9 +423,7 @@ public abstract class BSPhysObject : PhysicsActor
{
// Clean out any existing action
UnRegisterPreStepAction(op, id);
RegisteredPrestepActions[identifier] = actn;
PhysicsScene.BeforeStep += actn;
}
DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
@@ -476,9 +469,7 @@ public abstract class BSPhysObject : PhysicsActor
{
// Clean out any existing action
UnRegisterPostStepAction(op, id);
RegisteredPoststepActions[identifier] = actn;
PhysicsScene.AfterStep += actn;
}
DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
@@ -515,7 +506,58 @@ public abstract class BSPhysObject : PhysicsActor
}
DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
}
// When an update to the physical properties happens, this event is fired to let
// different actors to modify the update before it is passed around
public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
public event PreUpdatePropertyAction OnPreUpdateProperty;
protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
{
PreUpdatePropertyAction actions = OnPreUpdateProperty;
if (actions != null)
actions(ref entprop);
}
private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
{
lock (RegisteredPreUpdatePropertyActions)
{
// Clean out any existing action
UnRegisterPreUpdatePropertyAction(identifier);
RegisteredPreUpdatePropertyActions[identifier] = actn;
OnPreUpdateProperty += actn;
}
DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
}
public bool UnRegisterPreUpdatePropertyAction(string identifier)
{
bool removed = false;
lock (RegisteredPreUpdatePropertyActions)
{
if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
{
OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
RegisteredPreUpdatePropertyActions.Remove(identifier);
removed = true;
}
}
DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
return removed;
}
public void UnRegisterAllPreUpdatePropertyActions()
{
lock (RegisteredPreUpdatePropertyActions)
{
foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
{
OnPreUpdateProperty -= kvp.Value;
}
RegisteredPreUpdatePropertyActions.Clear();
}
DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
}
#endregion // Per Simulation Step actions
// High performance detailed logging routine used by the physical objects.

View File

@@ -39,7 +39,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
[Serializable]
public sealed class BSPrim : BSPhysObject
public class BSPrim : BSPhysObject
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS PRIM]";
@@ -102,9 +102,6 @@ public sealed class BSPrim : BSPhysObject
_mass = CalculateMass();
// Cause linkset variables to be initialized (like mass)
Linkset.Refresh(this);
DetailLog("{0},BSPrim.constructor,call", LocalID);
// do the actual object creation at taint time
PhysicsScene.TaintedObject("BSPrim.create", delegate()
@@ -121,15 +118,6 @@ public sealed class BSPrim : BSPhysObject
// m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
base.Destroy();
// Undo any links between me and any other object
BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG DEBUG
int childrenBefore = Linkset.NumberOfChildren; // DEBUG DEBUG
Linkset = Linkset.RemoveMeFromLinkset(this);
DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
// Undo any vehicle properties
this.VehicleType = (int)Vehicle.TYPE_NONE;
@@ -166,9 +154,9 @@ public sealed class BSPrim : BSPhysObject
ForceBodyShapeRebuild(false);
}
}
// Whatever the linkset wants is what I want.
// 'unknown' says to choose the best type
public override BSPhysicsShapeType PreferredPhysicalShape
{ get { return Linkset.PreferredPhysicalShape(this); } }
{ get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } }
public override bool ForceBodyShapeRebuild(bool inTaintTime)
{
@@ -213,33 +201,10 @@ public sealed class BSPrim : BSPhysObject
// link me to the specified parent
public override void link(PhysicsActor obj) {
BSPrim parent = obj as BSPrim;
if (parent != null)
{
BSPhysObject parentBefore = Linkset.LinksetRoot;
int childrenBefore = Linkset.NumberOfChildren;
Linkset = parent.Linkset.AddMeToLinkset(this);
DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
}
return;
}
// delink me from my linkset
public override void delink() {
// TODO: decide if this parent checking needs to happen at taint time
// Race condition here: if link() and delink() in same simulation tick, the delink will not happen
BSPhysObject parentBefore = Linkset.LinksetRoot;
int childrenBefore = Linkset.NumberOfChildren;
Linkset = Linkset.RemoveMeFromLinkset(this);
DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
return;
}
// Set motion values to zero.
@@ -277,6 +242,45 @@ public sealed class BSPrim : BSPhysObject
public override void LockAngularMotion(OMV.Vector3 axis)
{
DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f);
if (axis.X != 1) locking.X = 0f;
if (axis.Y != 1) locking.Y = 0f;
if (axis.Z != 1) locking.Z = 0f;
LockedAxis = locking;
/* Not implemented yet
if (LockedAxis != LockedAxisFree)
{
// Something is locked so start the thingy that keeps that axis from changing
RegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion", delegate(ref EntityProperties entprop)
{
if (LockedAxis != LockedAxisFree)
{
if (IsPhysicallyActive)
{
// Bullet can lock axis but it only works for global axis.
// Check if this prim is aligned on global axis and use Bullet's
// system if so.
ForceOrientation = entprop.Rotation;
ForceRotationalVelocity = entprop.RotationalVelocity;
}
}
else
{
UnRegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion");
}
});
}
else
{
// Everything seems unlocked
UnRegisterPreUpdatePropertyAction("BSPrim.LockAngularMotion");
}
*/
return;
}
@@ -287,15 +291,8 @@ public sealed class BSPrim : BSPhysObject
}
public override OMV.Vector3 Position {
get {
/* NOTE: this refetch is not necessary. The simulator knows about linkset children
* and does not fetch this position info for children. Thus this is commented out.
// child prims move around based on their parent. Need to get the latest location
if (!Linkset.IsRoot(this))
_position = Linkset.PositionGet(this);
*/
// don't do the GetObjectPosition for root elements because this function is called a zillion times.
// _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody) - PositionDisplacement;
// _position = ForcePosition;
return _position;
}
set {
@@ -313,24 +310,20 @@ public sealed class BSPrim : BSPhysObject
{
DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
ForcePosition = _position;
// A linkset might need to know if a component information changed.
Linkset.UpdateProperties(UpdatedProperties.Position, this);
});
}
}
public override OMV.Vector3 ForcePosition {
get {
_position = PhysicsScene.PE.GetPosition(PhysBody) - PositionDisplacement;
_position = PhysicsScene.PE.GetPosition(PhysBody);
return _position;
}
set {
_position = value;
if (PhysBody.HasPhysicalBody)
{
PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
ActivateIfPhysical(false);
}
}
@@ -357,7 +350,8 @@ public sealed class BSPrim : BSPhysObject
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
OMV.Vector3 upForce = OMV.Vector3.Zero;
if (RawPosition.Z < terrainHeight)
float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
{
DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
float targetHeight = terrainHeight + (Size.Z / 2f);
@@ -398,12 +392,13 @@ public sealed class BSPrim : BSPhysObject
// If the simulator cares about the mass of the linkset, it will sum it itself.
public override float Mass
{
get
{
return _mass;
}
get { return _mass; }
}
// TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
public virtual float TotalMass
{
get { return _mass; }
}
// used when we only want this prim's mass and not the linkset thing
public override float RawMass {
get { return _mass; }
@@ -467,13 +462,13 @@ public sealed class BSPrim : BSPhysObject
// Is this used?
public override OMV.Vector3 CenterOfMass
{
get { return Linkset.CenterOfMass; }
get { return RawPosition; }
}
// Is this used?
public override OMV.Vector3 GeometricCenter
{
get { return Linkset.GeometricCenter; }
get { return RawPosition; }
}
public override OMV.Vector3 Force {
@@ -487,7 +482,7 @@ public sealed class BSPrim : BSPhysObject
RegisterPreStepAction("BSPrim.setForce", LocalID,
delegate(float timeStep)
{
if (!IsPhysicallyActive)
if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
{
UnRegisterPreStepAction("BSPrim.setForce", LocalID);
return;
@@ -621,6 +616,8 @@ public sealed class BSPrim : BSPhysObject
}
}
}
// The simulator/viewer keep density as 100kg/m3.
// Remember to use BSParam.DensityScaleFactor to create the physical density.
public override float Density
{
get { return base.Density; }
@@ -692,7 +689,7 @@ public sealed class BSPrim : BSPhysObject
RegisterPreStepAction("BSPrim.setTorque", LocalID,
delegate(float timeStep)
{
if (!IsPhysicallyActive)
if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
{
UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
return;
@@ -721,14 +718,6 @@ public sealed class BSPrim : BSPhysObject
}
public override OMV.Quaternion Orientation {
get {
/* NOTE: this refetch is not necessary. The simulator knows about linkset children
* and does not fetch this position info for children. Thus this is commented out.
// Children move around because tied to parent. Get a fresh value.
if (!Linkset.IsRoot(this))
{
_orientation = Linkset.OrientationGet(this);
}
*/
return _orientation;
}
set {
@@ -739,10 +728,6 @@ public sealed class BSPrim : BSPhysObject
PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
{
ForceOrientation = _orientation;
// A linkset might need to know if a component information changed.
Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
});
}
}
@@ -758,7 +743,7 @@ public sealed class BSPrim : BSPhysObject
{
_orientation = value;
if (PhysBody.HasPhysicalBody)
PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
}
}
public override int PhysicsActorType {
@@ -814,7 +799,7 @@ public sealed class BSPrim : BSPhysObject
// isSolid: other objects bounce off of this object
// isVolumeDetect: other objects pass through but can generate collisions
// collisionEvents: whether this object returns collision events
public void UpdatePhysicalParameters()
public virtual void UpdatePhysicalParameters()
{
if (!PhysBody.HasPhysicalBody)
{
@@ -844,12 +829,6 @@ public sealed class BSPrim : BSPhysObject
// Rebuild its shape
PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
// Recompute any linkset parameters.
// When going from non-physical to physical, this re-enables the constraints that
// had been automatically disabled when the mass was set to zero.
// For compound based linksets, this enables and disables interactions of the children.
Linkset.Refresh(this);
DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
}
@@ -859,7 +838,7 @@ public sealed class BSPrim : BSPhysObject
// When dynamic, the object can fall and be pushed by others.
// This is independent of its 'solidness' which controls what passes through
// this object and what interacts with it.
private void MakeDynamic(bool makeStatic)
protected virtual void MakeDynamic(bool makeStatic)
{
if (makeStatic)
{
@@ -889,9 +868,6 @@ public sealed class BSPrim : BSPhysObject
// This collides like a static object
PhysBody.collisionType = CollisionType.Static;
// There can be special things needed for implementing linksets
Linkset.MakeStatic(this);
}
else
{
@@ -908,10 +884,7 @@ public sealed class BSPrim : BSPhysObject
// PhysicsScene.PE.ClearAllForces(BSBody);
// For good measure, make sure the transform is set through to the motion state
PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
// Center of mass is at the center of the object
// DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation);
ForcePosition = _position;
// A dynamic object has mass
UpdatePhysicalMassProperties(RawMass, false);
@@ -935,9 +908,6 @@ public sealed class BSPrim : BSPhysObject
// Force activation of the object so Bullet will act on it.
// Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
// There might be special things needed for implementing linksets.
Linkset.MakeDynamic(this);
}
}
@@ -1641,17 +1611,8 @@ public sealed class BSPrim : BSPhysObject
profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
volume *= (profileEnd - profileBegin);
returnMass = Density * volume;
/* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
if (IsRootOfLinkset)
{
foreach (BSPrim prim in _childrenPrims)
{
returnMass += prim.CalculateMass();
}
}
*/
returnMass = Density * BSParam.DensityScaleFactor * volume;
DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
@@ -1672,8 +1633,7 @@ public sealed class BSPrim : BSPhysObject
// Called if the current prim body is about to be destroyed.
// Remove all the physical dependencies on the old body.
// (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
Linkset.RemoveBodyDependencies(this);
VehicleController.RemoveBodyDependencies(this);
RemoveBodyDependencies();
});
// Make sure the properties are set on the new object
@@ -1681,57 +1641,56 @@ public sealed class BSPrim : BSPhysObject
return;
}
protected virtual void RemoveBodyDependencies()
{
VehicleController.RemoveBodyDependencies(this);
}
// The physics engine says that properties have updated. Update same and inform
// the world that things have changed.
public override void UpdateProperties(EntityProperties entprop)
{
// Updates only for individual prims and for the root object of a linkset.
if (Linkset.IsRoot(this))
TriggerPreUpdatePropertyAction(ref entprop);
// A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
// TODO: handle physics introduced by Bullet with computed vehicle physics.
if (VehicleController.IsActive)
{
// A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
// TODO: handle physics introduced by Bullet with computed vehicle physics.
if (VehicleController.IsActive)
{
entprop.RotationalVelocity = OMV.Vector3.Zero;
}
// DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
// Undo any center-of-mass displacement that might have been done.
if (PositionDisplacement != OMV.Vector3.Zero)
{
// Correct for any rotation around the center-of-mass
// TODO!!!
entprop.Position -= PositionDisplacement;
}
// Assign directly to the local variables so the normal set actions do not happen
_position = entprop.Position;
_orientation = entprop.Rotation;
_velocity = entprop.Velocity;
_acceleration = entprop.Acceleration;
_rotationalVelocity = entprop.RotationalVelocity;
// DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
// The sanity check can change the velocity and/or position.
if (PositionSanityCheck(true /* inTaintTime */ ))
{
entprop.Position = _position;
entprop.Velocity = _velocity;
entprop.RotationalVelocity = _rotationalVelocity;
entprop.Acceleration = _acceleration;
}
OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
// remember the current and last set values
LastEntityProperties = CurrentEntityProperties;
CurrentEntityProperties = entprop;
base.RequestPhysicsterseUpdate();
entprop.RotationalVelocity = OMV.Vector3.Zero;
}
// DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
// Assign directly to the local variables so the normal set actions do not happen
_position = entprop.Position;
_orientation = entprop.Rotation;
// _velocity = entprop.Velocity;
// DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
// very sensitive to velocity changes.
if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f))
_velocity = entprop.Velocity;
_acceleration = entprop.Acceleration;
_rotationalVelocity = entprop.RotationalVelocity;
// DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
// The sanity check can change the velocity and/or position.
if (PositionSanityCheck(true /* inTaintTime */ ))
{
entprop.Position = _position;
entprop.Velocity = _velocity;
entprop.RotationalVelocity = _rotationalVelocity;
entprop.Acceleration = _acceleration;
}
OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
// remember the current and last set values
LastEntityProperties = CurrentEntityProperties;
CurrentEntityProperties = entprop;
base.RequestPhysicsterseUpdate();
/*
else
{
@@ -1741,9 +1700,6 @@ public sealed class BSPrim : BSPhysObject
entprop.Acceleration, entprop.RotationalVelocity);
}
*/
// The linkset implimentation might want to know about this.
Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
}
}
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
* are Copyright (c) 2009 Linden Research, Inc and are used under their license
* of Creative Commons Attribution-Share Alike 3.0
* (http://creativecommons.org/licenses/by-sa/3.0/).
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSPrimDisplaced : BSPrim
{
// The purpose of this module is to do any mapping between what the simulator thinks
// the prim position and orientation is and what the physical position/orientation.
// This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
// of the prim/linkset. The simulator tracks the location of the prim/linkset by
// the location of the root prim. So, if center-of-mass is anywhere but the origin
// of the root prim, the physical origin is displaced from the simulator origin.
//
// This routine works by capturing the Force* setting of position/orientation/... and
// adjusting the simulator values (being set) into the physical values.
// The conversion is also done in the opposite direction (physical origin -> simulator origin).
//
// The updateParameter call is also captured and the values from the physics engine
// are converted into simulator origin values before being passed to the base
// class.
public virtual OMV.Vector3 PositionDisplacement { get; set; }
public virtual OMV.Quaternion OrientationDisplacement { get; set; }
public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
: base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
{
ClearDisplacement();
}
public void ClearDisplacement()
{
PositionDisplacement = OMV.Vector3.Zero;
OrientationDisplacement = OMV.Quaternion.Identity;
}
// Set this sets and computes the displacement from the passed prim to the center-of-mass.
// A user set value for center-of-mass overrides whatever might be passed in here.
// The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement)
{
Vector3 comDisp;
if (UserSetCenterOfMass.HasValue)
comDisp = (OMV.Vector3)UserSetCenterOfMass;
else
comDisp = centerOfMassDisplacement;
if (comDisp == Vector3.Zero)
{
// If there is no diplacement. Things get reset.
PositionDisplacement = OMV.Vector3.Zero;
OrientationDisplacement = OMV.Quaternion.Identity;
}
else
{
// Remember the displacement from root as well as the origional rotation of the
// new center-of-mass.
PositionDisplacement = comDisp;
OrientationDisplacement = OMV.Quaternion.Identity;
}
}
public override Vector3 ForcePosition
{
get { return base.ForcePosition; }
set
{
if (PositionDisplacement != OMV.Vector3.Zero)
base.ForcePosition = value - (PositionDisplacement * RawOrientation);
else
base.ForcePosition = value;
}
}
public override Quaternion ForceOrientation
{
get { return base.ForceOrientation; }
set
{
base.ForceOrientation = value;
}
}
// TODO: decide if this is the right place for these variables.
// Somehow incorporate the optional settability by the user.
// Is this used?
public override OMV.Vector3 CenterOfMass
{
get { return RawPosition; }
}
// Is this used?
public override OMV.Vector3 GeometricCenter
{
get { return RawPosition; }
}
public override void UpdateProperties(EntityProperties entprop)
{
// Undo any center-of-mass displacement that might have been done.
if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity)
{
// Correct for any rotation around the center-of-mass
// TODO!!!
entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation);
// entprop.Rotation = something;
}
base.UpdateProperties(entprop);
}
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenSim.Framework;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSPrimLinkable : BSPrimDisplaced
{
public BSLinkset Linkset { get; set; }
// The index of this child prim.
public int LinksetChildIndex { get; set; }
public BSLinksetInfo LinksetInfo { get; set; }
public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
: base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
{
Linkset = BSLinkset.Factory(PhysicsScene, this);
PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate()
{
Linkset.Refresh(this);
});
}
public override void Destroy()
{
Linkset = Linkset.RemoveMeFromLinkset(this);
base.Destroy();
}
public override BSPhysicsShapeType PreferredPhysicalShape
{ get { return Linkset.PreferredPhysicalShape(this); } }
public override void link(Manager.PhysicsActor obj)
{
BSPrimLinkable parent = obj as BSPrimLinkable;
if (parent != null)
{
BSPhysObject parentBefore = Linkset.LinksetRoot;
int childrenBefore = Linkset.NumberOfChildren;
Linkset = parent.Linkset.AddMeToLinkset(this);
DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
}
return;
}
public override void delink()
{
// TODO: decide if this parent checking needs to happen at taint time
// Race condition here: if link() and delink() in same simulation tick, the delink will not happen
BSPhysObject parentBefore = Linkset.LinksetRoot;
int childrenBefore = Linkset.NumberOfChildren;
Linkset = Linkset.RemoveMeFromLinkset(this);
DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
return;
}
// When simulator changes position, this might be moving a child of the linkset.
public override OMV.Vector3 Position
{
get { return base.Position; }
set
{
base.Position = value;
PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate()
{
Linkset.UpdateProperties(UpdatedProperties.Position, this);
});
}
}
// When simulator changes orientation, this might be moving a child of the linkset.
public override OMV.Quaternion Orientation
{
get { return base.Orientation; }
set
{
base.Orientation = value;
PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate()
{
Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
});
}
}
public override float TotalMass
{
get { return Linkset.LinksetMass; }
}
public override void UpdatePhysicalParameters()
{
base.UpdatePhysicalParameters();
// Recompute any linkset parameters.
// When going from non-physical to physical, this re-enables the constraints that
// had been automatically disabled when the mass was set to zero.
// For compound based linksets, this enables and disables interactions of the children.
if (Linkset != null) // null can happen during initialization
Linkset.Refresh(this);
}
protected override void MakeDynamic(bool makeStatic)
{
base.MakeDynamic(makeStatic);
if (makeStatic)
Linkset.MakeStatic(this);
else
Linkset.MakeDynamic(this);
}
// Body is being taken apart. Remove physical dependencies and schedule a rebuild.
protected override void RemoveBodyDependencies()
{
Linkset.RemoveBodyDependencies(this);
base.RemoveBodyDependencies();
}
public override void UpdateProperties(EntityProperties entprop)
{
if (Linkset.IsRoot(this))
{
// Properties are only updated for the roots of a linkset.
// TODO: this will have to change when linksets are articulated.
base.UpdateProperties(entprop);
}
// The linkset might like to know about changing locations
Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
}
public override bool Collide(uint collidingWith, BSPhysObject collidee,
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
{
// prims in the same linkset cannot collide with each other
BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID))
{
return false;
}
return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
}
}
}

View File

@@ -434,7 +434,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
{
if (!m_initialized) return;
BSPrim bsprim = prim as BSPrim;
BSPhysObject bsprim = prim as BSPhysObject;
if (bsprim != null)
{
DetailLog("{0},RemovePrim,call", bsprim.LocalID);
@@ -463,9 +463,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
if (!m_initialized) return null;
DetailLog("{0},AddPrimShape,call", localID);
DetailLog("{0},BSScene.AddPrimShape,call", localID);
BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
lock (PhysObjects) PhysObjects.Add(localID, prim);
return prim;
}

View File

@@ -52,7 +52,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
{
bool Cancel();
void Abort();
bool Wait(TimeSpan t);
/// <summary>
/// Wait for the work item to complete.
/// </summary>
/// <param name='t'>The number of milliseconds to wait. Must be >= -1 (Timeout.Infinite).</param>
bool Wait(int t);
}
/// <summary>

View File

@@ -4479,6 +4479,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
}
}
}
if (pushAllowed)
{
float distance = (PusheePos - m_host.AbsolutePosition).Length();
@@ -4507,17 +4508,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
applied_linear_impulse *= scaling_factor;
}
if (pusheeIsAvatar)
{
if (pusheeav != null)
{
if (pusheeav.PhysicsActor != null)
PhysicsActor pa = pusheeav.PhysicsActor;
if (pa != null)
{
if (local != 0)
{
applied_linear_impulse *= m_host.GetWorldRotation();
}
pusheeav.PhysicsActor.AddForce(applied_linear_impulse, true);
pa.AddForce(applied_linear_impulse, true);
}
}
}

View File

@@ -595,7 +595,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
if (!m_coopTermination)
{
// If we're not co-operative terminating then try and wait for the event to complete before stopping
if (workItem.Wait(new TimeSpan((long)timeout * 100000)))
if (workItem.Wait(timeout))
return true;
}
else
@@ -610,7 +610,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
// For now, we will wait forever since the event should always cleanly terminate once LSL loop
// checking is implemented. May want to allow a shorter timeout option later.
if (workItem.Wait(TimeSpan.MaxValue))
if (workItem.Wait(Timeout.Infinite))
{
if (DebugLevel >= 1)
m_log.DebugFormat(

View File

@@ -57,8 +57,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
wr.Abort();
}
public bool Wait(TimeSpan t)
public bool Wait(int t)
{
// We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
// TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
// int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8
// (or very likely other versions of Mono at least up until 3.0.3).
return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
}
}

View File

@@ -162,7 +162,7 @@ namespace OpenSim.Services.Connectors
if (replyData != null)
{
if (replyData.ContainsKey("result") && replyData.ContainsKey("result").ToString() == "null")
if (replyData.ContainsKey("result") && replyData["result"].ToString() == "null")
{
return accounts;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.