Merge branch 'careminster' into avination

Conflicts:
	OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs
avinationmerge
Melanie 2012-08-14 02:34:03 +01:00
commit 9b014a7167
29 changed files with 871 additions and 431 deletions

View File

@ -93,6 +93,8 @@ namespace OpenSim.Framework.Serialization.External
"MediaURL", (ld, xtr) => ld.MediaURL = xtr.ReadElementString("MediaURL")); "MediaURL", (ld, xtr) => ld.MediaURL = xtr.ReadElementString("MediaURL"));
m_ldProcessors.Add( m_ldProcessors.Add(
"MusicURL", (ld, xtr) => ld.MusicURL = xtr.ReadElementString("MusicURL")); "MusicURL", (ld, xtr) => ld.MusicURL = xtr.ReadElementString("MusicURL"));
m_ldProcessors.Add(
"OwnerID", (ld, xtr) => ld.OwnerID = UUID.Parse(xtr.ReadElementString("OwnerID")));
m_ldProcessors.Add( m_ldProcessors.Add(
"ParcelAccessList", ProcessParcelAccessList); "ParcelAccessList", ProcessParcelAccessList);
@ -186,7 +188,16 @@ namespace OpenSim.Framework.Serialization.External
return landData; return landData;
} }
public static string Serialize(LandData landData) /// <summary>
/// Serialize land data
/// </summary>
/// <param name='landData'></param>
/// <param name='options'>
/// Serialization options.
/// Can be null if there are no options.
/// "wipe-owners" will write UUID.Zero rather than the ownerID so that a later reload loads all parcels with the estate owner as the owner
/// </param>
public static string Serialize(LandData landData, Dictionary<string, object> options)
{ {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
XmlTextWriter xtw = new XmlTextWriter(sw); XmlTextWriter xtw = new XmlTextWriter(sw);
@ -215,7 +226,14 @@ namespace OpenSim.Framework.Serialization.External
xtw.WriteElementString("MediaID", landData.MediaID.ToString()); xtw.WriteElementString("MediaID", landData.MediaID.ToString());
xtw.WriteElementString("MediaURL", landData.MediaURL); xtw.WriteElementString("MediaURL", landData.MediaURL);
xtw.WriteElementString("MusicURL", landData.MusicURL); xtw.WriteElementString("MusicURL", landData.MusicURL);
xtw.WriteElementString("OwnerID", landData.OwnerID.ToString());
UUID ownerIdToWrite;
if (options != null && options.ContainsKey("wipe-owners"))
ownerIdToWrite = UUID.Zero;
else
ownerIdToWrite = landData.OwnerID;
xtw.WriteElementString("OwnerID", ownerIdToWrite.ToString());
xtw.WriteStartElement("ParcelAccessList"); xtw.WriteStartElement("ParcelAccessList");
foreach (LandAccessEntry pal in landData.ParcelAccessList) foreach (LandAccessEntry pal in landData.ParcelAccessList)

View File

@ -42,22 +42,23 @@ namespace OpenSim.Framework.Serialization.Tests
private LandData land; private LandData land;
private LandData landWithParcelAccessList; private LandData landWithParcelAccessList;
private static string preSerialized = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n<LandData>\n <Area>128</Area>\n <AuctionID>0</AuctionID>\n <AuthBuyerID>00000000-0000-0000-0000-000000000000</AuthBuyerID>\n <Category>10</Category>\n <ClaimDate>0</ClaimDate>\n <ClaimPrice>0</ClaimPrice>\n <GlobalID>54ff9641-dd40-4a2c-b1f1-47dd3af24e50</GlobalID>\n <GroupID>d740204e-bbbf-44aa-949d-02c7d739f6a5</GroupID>\n <IsGroupOwned>False</IsGroupOwned>\n <Bitmap>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Bitmap>\n <Description>land data to test LandDataSerializer</Description>\n <Flags>536870944</Flags>\n <LandingType>2</LandingType>\n <Name>LandDataSerializerTest Land</Name>\n <Status>0</Status>\n <LocalID>0</LocalID>\n <MediaAutoScale>1</MediaAutoScale>\n <MediaID>d4452578-2f25-4b97-a81b-819af559cfd7</MediaID>\n <MediaURL>http://videos.opensimulator.org/bumblebee.mp4</MediaURL>\n <MusicURL />\n <OwnerID>1b8eedf9-6d15-448b-8015-24286f1756bf</OwnerID>\n <ParcelAccessList />\n <PassHours>0</PassHours>\n <PassPrice>0</PassPrice>\n <SalePrice>0</SalePrice>\n <SnapshotID>00000000-0000-0000-0000-000000000000</SnapshotID>\n <UserLocation>&lt;0, 0, 0&gt;</UserLocation>\n <UserLookAt>&lt;0, 0, 0&gt;</UserLookAt>\n <Dwell>0</Dwell>\n <OtherCleanTime>0</OtherCleanTime>\n</LandData>"; // private static string preSerialized = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n<LandData>\n <Area>128</Area>\n <AuctionID>0</AuctionID>\n <AuthBuyerID>00000000-0000-0000-0000-000000000000</AuthBuyerID>\n <Category>10</Category>\n <ClaimDate>0</ClaimDate>\n <ClaimPrice>0</ClaimPrice>\n <GlobalID>54ff9641-dd40-4a2c-b1f1-47dd3af24e50</GlobalID>\n <GroupID>d740204e-bbbf-44aa-949d-02c7d739f6a5</GroupID>\n <IsGroupOwned>False</IsGroupOwned>\n <Bitmap>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Bitmap>\n <Description>land data to test LandDataSerializer</Description>\n <Flags>536870944</Flags>\n <LandingType>2</LandingType>\n <Name>LandDataSerializerTest Land</Name>\n <Status>0</Status>\n <LocalID>0</LocalID>\n <MediaAutoScale>1</MediaAutoScale>\n <MediaID>d4452578-2f25-4b97-a81b-819af559cfd7</MediaID>\n <MediaURL>http://videos.opensimulator.org/bumblebee.mp4</MediaURL>\n <MusicURL />\n <OwnerID>1b8eedf9-6d15-448b-8015-24286f1756bf</OwnerID>\n <ParcelAccessList />\n <PassHours>0</PassHours>\n <PassPrice>0</PassPrice>\n <SalePrice>0</SalePrice>\n <SnapshotID>00000000-0000-0000-0000-000000000000</SnapshotID>\n <UserLocation>&lt;0, 0, 0&gt;</UserLocation>\n <UserLookAt>&lt;0, 0, 0&gt;</UserLookAt>\n <Dwell>0</Dwell>\n <OtherCleanTime>0</OtherCleanTime>\n</LandData>";
private static string preSerializedWithParcelAccessList = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n<LandData>\n <Area>128</Area>\n <AuctionID>0</AuctionID>\n <AuthBuyerID>00000000-0000-0000-0000-000000000000</AuthBuyerID>\n <Category>10</Category>\n <ClaimDate>0</ClaimDate>\n <ClaimPrice>0</ClaimPrice>\n <GlobalID>54ff9641-dd40-4a2c-b1f1-47dd3af24e50</GlobalID>\n <GroupID>d740204e-bbbf-44aa-949d-02c7d739f6a5</GroupID>\n <IsGroupOwned>False</IsGroupOwned>\n <Bitmap>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Bitmap>\n <Description>land data to test LandDataSerializer</Description>\n <Flags>536870944</Flags>\n <LandingType>2</LandingType>\n <Name>LandDataSerializerTest Land</Name>\n <Status>0</Status>\n <LocalID>0</LocalID>\n <MediaAutoScale>1</MediaAutoScale>\n <MediaID>d4452578-2f25-4b97-a81b-819af559cfd7</MediaID>\n <MediaURL>http://videos.opensimulator.org/bumblebee.mp4</MediaURL>\n <MusicURL />\n <OwnerID>1b8eedf9-6d15-448b-8015-24286f1756bf</OwnerID>\n <ParcelAccessList>\n <ParcelAccessEntry>\n <AgentID>62d65d45-c91a-4f77-862c-46557d978b6c</AgentID>\n <Time>0</Time>\n <AccessList>2</AccessList>\n </ParcelAccessEntry>\n <ParcelAccessEntry>\n <AgentID>ec2a8d18-2378-4fe0-8b68-2a31b57c481e</AgentID>\n <Time>0</Time>\n <AccessList>1</AccessList>\n </ParcelAccessEntry>\n </ParcelAccessList>\n <PassHours>0</PassHours>\n <PassPrice>0</PassPrice>\n <SalePrice>0</SalePrice>\n <SnapshotID>00000000-0000-0000-0000-000000000000</SnapshotID>\n <UserLocation>&lt;0, 0, 0&gt;</UserLocation>\n <UserLookAt>&lt;0, 0, 0&gt;</UserLookAt>\n <Dwell>0</Dwell>\n <OtherCleanTime>0</OtherCleanTime>\n</LandData>"; private static string preSerializedWithParcelAccessList
= "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n<LandData>\n <Area>128</Area>\n <AuctionID>0</AuctionID>\n <AuthBuyerID>00000000-0000-0000-0000-000000000000</AuthBuyerID>\n <Category>10</Category>\n <ClaimDate>0</ClaimDate>\n <ClaimPrice>0</ClaimPrice>\n <GlobalID>54ff9641-dd40-4a2c-b1f1-47dd3af24e50</GlobalID>\n <GroupID>d740204e-bbbf-44aa-949d-02c7d739f6a5</GroupID>\n <IsGroupOwned>False</IsGroupOwned>\n <Bitmap>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Bitmap>\n <Description>land data to test LandDataSerializer</Description>\n <Flags>536870944</Flags>\n <LandingType>2</LandingType>\n <Name>LandDataSerializerTest Land</Name>\n <Status>0</Status>\n <LocalID>0</LocalID>\n <MediaAutoScale>1</MediaAutoScale>\n <MediaID>d4452578-2f25-4b97-a81b-819af559cfd7</MediaID>\n <MediaURL>http://videos.opensimulator.org/bumblebee.mp4</MediaURL>\n <MusicURL />\n <OwnerID>1b8eedf9-6d15-448b-8015-24286f1756bf</OwnerID>\n <ParcelAccessList>\n <ParcelAccessEntry>\n <AgentID>62d65d45-c91a-4f77-862c-46557d978b6c</AgentID>\n <Time>0</Time>\n <AccessList>2</AccessList>\n </ParcelAccessEntry>\n <ParcelAccessEntry>\n <AgentID>ec2a8d18-2378-4fe0-8b68-2a31b57c481e</AgentID>\n <Time>0</Time>\n <AccessList>1</AccessList>\n </ParcelAccessEntry>\n </ParcelAccessList>\n <PassHours>0</PassHours>\n <PassPrice>0</PassPrice>\n <SalePrice>0</SalePrice>\n <SnapshotID>00000000-0000-0000-0000-000000000000</SnapshotID>\n <UserLocation>&lt;0, 0, 0&gt;</UserLocation>\n <UserLookAt>&lt;0, 0, 0&gt;</UserLookAt>\n <Dwell>0</Dwell>\n <OtherCleanTime>0</OtherCleanTime>\n</LandData>";
[SetUp] [SetUp]
public void setup() public void setup()
{ {
// setup LandData object // setup LandData object
this.land = new LandData(); this.land = new LandData();
this.land.AABBMax = new Vector3(0, 0, 0); this.land.AABBMax = new Vector3(1, 2, 3);
this.land.AABBMin = new Vector3(128, 128, 128); this.land.AABBMin = new Vector3(129, 130, 131);
this.land.Area = 128; this.land.Area = 128;
this.land.AuctionID = 0; this.land.AuctionID = 4;
this.land.AuthBuyerID = new UUID(); this.land.AuthBuyerID = new UUID("7176df0c-6c50-45db-8a37-5e78be56a0cd");
this.land.Category = ParcelCategory.Residential; this.land.Category = ParcelCategory.Residential;
this.land.ClaimDate = 0; this.land.ClaimDate = 1;
this.land.ClaimPrice = 0; this.land.ClaimPrice = 2;
this.land.GlobalID = new UUID("54ff9641-dd40-4a2c-b1f1-47dd3af24e50"); this.land.GlobalID = new UUID("54ff9641-dd40-4a2c-b1f1-47dd3af24e50");
this.land.GroupID = new UUID("d740204e-bbbf-44aa-949d-02c7d739f6a5"); this.land.GroupID = new UUID("d740204e-bbbf-44aa-949d-02c7d739f6a5");
this.land.Description = "land data to test LandDataSerializer"; this.land.Description = "land data to test LandDataSerializer";
@ -65,7 +66,7 @@ namespace OpenSim.Framework.Serialization.Tests
this.land.LandingType = (byte)LandingType.Direct; this.land.LandingType = (byte)LandingType.Direct;
this.land.Name = "LandDataSerializerTest Land"; this.land.Name = "LandDataSerializerTest Land";
this.land.Status = ParcelStatus.Leased; this.land.Status = ParcelStatus.Leased;
this.land.LocalID = 0; this.land.LocalID = 1;
this.land.MediaAutoScale = (byte)0x01; this.land.MediaAutoScale = (byte)0x01;
this.land.MediaID = new UUID("d4452578-2f25-4b97-a81b-819af559cfd7"); this.land.MediaID = new UUID("d4452578-2f25-4b97-a81b-819af559cfd7");
this.land.MediaURL = "http://videos.opensimulator.org/bumblebee.mp4"; this.land.MediaURL = "http://videos.opensimulator.org/bumblebee.mp4";
@ -90,26 +91,26 @@ namespace OpenSim.Framework.Serialization.Tests
/// <summary> /// <summary>
/// Test the LandDataSerializer.Serialize() method /// Test the LandDataSerializer.Serialize() method
/// </summary> /// </summary>
[Test] // [Test]
public void LandDataSerializerSerializeTest() // public void LandDataSerializerSerializeTest()
{ // {
TestHelpers.InMethod(); // TestHelpers.InMethod();
//
string serialized = LandDataSerializer.Serialize(this.land).Replace("\r\n", "\n"); // string serialized = LandDataSerializer.Serialize(this.land).Replace("\r\n", "\n");
Assert.That(serialized.Length > 0, "Serialize(LandData) returned empty string"); // Assert.That(serialized.Length > 0, "Serialize(LandData) returned empty string");
//
// adding a simple boolean variable because resharper nUnit integration doesn't like this // // adding a simple boolean variable because resharper nUnit integration doesn't like this
// XML data in the Assert.That statement. Not sure why. // // XML data in the Assert.That statement. Not sure why.
bool result = (serialized == preSerialized); // bool result = (serialized == preSerialized);
Assert.That(result, "result of Serialize LandData does not match expected result"); // Assert.That(result, "result of Serialize LandData does not match expected result");
//
string serializedWithParcelAccessList = LandDataSerializer.Serialize(this.landWithParcelAccessList).Replace("\r\n", "\n"); // string serializedWithParcelAccessList = LandDataSerializer.Serialize(this.landWithParcelAccessList).Replace("\r\n", "\n");
Assert.That(serializedWithParcelAccessList.Length > 0, // Assert.That(serializedWithParcelAccessList.Length > 0,
"Serialize(LandData) returned empty string for LandData object with ParcelAccessList"); // "Serialize(LandData) returned empty string for LandData object with ParcelAccessList");
result = (serializedWithParcelAccessList == preSerializedWithParcelAccessList); // result = (serializedWithParcelAccessList == preSerializedWithParcelAccessList);
Assert.That(result, // Assert.That(result,
"result of Serialize(LandData) does not match expected result (pre-serialized with parcel access list"); // "result of Serialize(LandData) does not match expected result (pre-serialized with parcel access list");
} // }
/// <summary> /// <summary>
/// Test the LandDataSerializer.Deserialize() method /// Test the LandDataSerializer.Deserialize() method
@ -120,10 +121,28 @@ namespace OpenSim.Framework.Serialization.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();
LandData ld = LandDataSerializer.Deserialize(LandDataSerializerTest.preSerialized); LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, null));
Assert.That(ld != null, "Deserialize(string) returned null"); Assert.That(ld, Is.Not.Null, "Deserialize(string) returned null");
Assert.That(ld.GlobalID == this.land.GlobalID, "Reified LandData.GlobalID != original LandData.GlobalID"); // Assert.That(ld.AABBMax, Is.EqualTo(land.AABBMax));
Assert.That(ld.Name == this.land.Name, "Reified LandData.Name != original LandData.Name"); // Assert.That(ld.AABBMin, Is.EqualTo(land.AABBMin));
Assert.That(ld.Area, Is.EqualTo(land.Area));
Assert.That(ld.AuctionID, Is.EqualTo(land.AuctionID));
Assert.That(ld.AuthBuyerID, Is.EqualTo(land.AuthBuyerID));
Assert.That(ld.Category, Is.EqualTo(land.Category));
Assert.That(ld.ClaimDate, Is.EqualTo(land.ClaimDate));
Assert.That(ld.ClaimPrice, Is.EqualTo(land.ClaimPrice));
Assert.That(ld.GlobalID, Is.EqualTo(land.GlobalID), "Reified LandData.GlobalID != original LandData.GlobalID");
Assert.That(ld.GroupID, Is.EqualTo(land.GroupID));
Assert.That(ld.Description, Is.EqualTo(land.Description));
Assert.That(ld.Flags, Is.EqualTo(land.Flags));
Assert.That(ld.LandingType, Is.EqualTo(land.LandingType));
Assert.That(ld.Name, Is.EqualTo(land.Name), "Reified LandData.Name != original LandData.Name");
Assert.That(ld.Status, Is.EqualTo(land.Status));
Assert.That(ld.LocalID, Is.EqualTo(land.LocalID));
Assert.That(ld.MediaAutoScale, Is.EqualTo(land.MediaAutoScale));
Assert.That(ld.MediaID, Is.EqualTo(land.MediaID));
Assert.That(ld.MediaURL, Is.EqualTo(land.MediaURL));
Assert.That(ld.OwnerID, Is.EqualTo(land.OwnerID));
} }
[Test] [Test]

View File

@ -294,14 +294,13 @@ namespace OpenSim
"save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [<OAR path>]", "save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [<OAR path>]",
"Save a region's data to an OAR archive.", "Save a region's data to an OAR archive.",
// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine // "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine
"-h|--home=<url> adds the url of the profile service to the saved user information." + Environment.NewLine "-h|--home=<url> adds the url of the profile service to the saved user information.\n"
+ "--noassets stops assets being saved to the OAR." + Environment.NewLine + "--noassets stops assets being saved to the OAR.\n"
+ "--publish saves an OAR stripped of owner and last owner information." + Environment.NewLine + "--publish saves an OAR stripped of owner and last owner information.\n"
+ " on reload, the estate owner will be the owner of all objects" + Environment.NewLine + " on reload, the estate owner will be the owner of all objects\n"
+ " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published" + Environment.NewLine + " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n"
+ " this option is EXPERIMENTAL" + Environment.NewLine + "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n"
+ "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR." + Environment.NewLine + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n"
+ " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer" + Environment.NewLine
+ "The OAR path must be a filesystem path." + "The OAR path must be a filesystem path."
+ " If this is not given then the oar is saved to region.oar in the current directory.", + " If this is not given then the oar is saved to region.oar in the current directory.",
SaveOar); SaveOar);

View File

@ -126,9 +126,14 @@ namespace OpenSim.Region.ClientStack.Linden
IConfig sconfig = config.Configs["Startup"]; IConfig sconfig = config.Configs["Startup"];
if (sconfig != null) if (sconfig != null)
{ {
m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
m_levelUpload = sconfig.GetInt("LevelUpload", 0); m_levelUpload = sconfig.GetInt("LevelUpload", 0);
} }
IConfig appearanceConfig = config.Configs["Appearance"];
if (appearanceConfig != null)
{
m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
}
} }
m_assetService = m_Scene.AssetService; m_assetService = m_Scene.AssetService;

View File

@ -66,9 +66,9 @@ namespace OpenSim.Region.ClientStack.Linden
public void Initialise(IConfigSource source) public void Initialise(IConfigSource source)
{ {
IConfig sconfig = source.Configs["Startup"]; IConfig appearanceConfig = source.Configs["Appearance"];
if (sconfig != null) if (appearanceConfig != null)
m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
} }
public void AddRegion(Scene s) public void AddRegion(Scene s)

View File

@ -284,7 +284,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
sp.ClearAttachments(); sp.ClearAttachments();
} }
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData) public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
{ {
lock (sp.AttachmentsSyncLock) lock (sp.AttachmentsSyncLock)
{ {
@ -361,7 +361,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
group.AbsolutePosition = attachPos; group.AbsolutePosition = attachPos;
if (sp.PresenceType != PresenceType.Npc) if (sp.PresenceType != PresenceType.Npc)
UpdateUserInventoryWithAttachment(sp, group, attachmentPt); UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp);
AttachToAgent(sp, group, attachmentPt, attachPos, silent); AttachToAgent(sp, group, attachmentPt, attachPos, silent);
} }
@ -369,7 +369,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return true; return true;
} }
private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt) private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp)
{ {
// Remove any previous attachments // Remove any previous attachments
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt); List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
@ -379,19 +379,23 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
{ {
if (attachments[0].FromItemID != UUID.Zero) if (attachments[0].FromItemID != UUID.Zero)
DetachSingleAttachmentToInvInternal(sp, attachments[0]); DetachSingleAttachmentToInvInternal(sp, attachments[0]);
else // Error logging commented because UUID.Zero now means temp attachment
m_log.WarnFormat( // else
"[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!", // m_log.WarnFormat(
attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name); // "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
// attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
} }
// Add the new attachment to inventory if we don't already have it. // Add the new attachment to inventory if we don't already have it.
if (!temp)
{
UUID newAttachmentItemID = group.FromItemID; UUID newAttachmentItemID = group.FromItemID;
if (newAttachmentItemID == UUID.Zero) if (newAttachmentItemID == UUID.Zero)
newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID; newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
} }
}
public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
{ {
@ -474,6 +478,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
UUID inventoryID = so.FromItemID; UUID inventoryID = so.FromItemID;
// As per Linden spec, drop is disabled for temp attachs
if (inventoryID == UUID.Zero)
return;
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", // "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
// so.Name, so.LocalId, inventoryID); // so.Name, so.LocalId, inventoryID);
@ -484,7 +492,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
so.PrimCount, sp.UUID, sp.AbsolutePosition)) so.PrimCount, sp.UUID, sp.AbsolutePosition))
return; return;
bool changed = sp.Appearance.DetachAttachment(inventoryID); bool changed = false;
if (inventoryID != UUID.Zero)
changed = sp.Appearance.DetachAttachment(inventoryID);
if (changed && m_scene.AvatarFactory != null) if (changed && m_scene.AvatarFactory != null)
m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
@ -516,6 +526,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so)
{ {
// As per Linden spec, detach (take) is disabled for temp attachs
if (so.FromItemID == UUID.Zero)
return;
lock (sp.AttachmentsSyncLock) lock (sp.AttachmentsSyncLock)
{ {
// Save avatar attachment information // Save avatar attachment information
@ -589,6 +603,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
/// <param name="saveAllScripted"></param> /// <param name="saveAllScripted"></param>
private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, string scriptedState) private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, string scriptedState)
{ {
if (grp.FromItemID == UUID.Zero)
{
// We can't save temp attachments
grp.HasGroupChanged = false;
return;
}
// Saving attachments for NPCs messes them up for the real owner! // Saving attachments for NPCs messes them up for the real owner!
INPCModule module = m_scene.RequestModuleInterface<INPCModule>(); INPCModule module = m_scene.RequestModuleInterface<INPCModule>();
if (module != null) if (module != null)
@ -845,7 +866,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
// This will throw if the attachment fails // This will throw if the attachment fails
try try
{ {
AttachObject(sp, objatt, attachmentPt, false, false); AttachObject(sp, objatt, attachmentPt, false, false, false);
} }
catch (Exception e) catch (Exception e)
{ {
@ -1005,7 +1026,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
AttachmentPt &= 0x7f; AttachmentPt &= 0x7f;
// Calls attach with a Zero position // Calls attach with a Zero position
if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true)) if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true, false))
{ {
// m_log.Debug( // m_log.Debug(
// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId // "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId

View File

@ -189,7 +189,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false);
// Check status on scene presence // Check status on scene presence
Assert.That(sp.HasAttachments(), Is.True); Assert.That(sp.HasAttachments(), Is.True);
@ -243,7 +243,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
sp2.AbsolutePosition = new Vector3(0, 0, 0); sp2.AbsolutePosition = new Vector3(0, 0, 0);
sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero);
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false);
Assert.That(sp.HasAttachments(), Is.False); Assert.That(sp.HasAttachments(), Is.False);
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));

View File

@ -66,11 +66,11 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
scene.RegisterModuleInterface<IAvatarFactoryModule>(this); scene.RegisterModuleInterface<IAvatarFactoryModule>(this);
scene.EventManager.OnNewClient += SubscribeToClientEvents; scene.EventManager.OnNewClient += SubscribeToClientEvents;
IConfig sconfig = config.Configs["Startup"]; IConfig appearanceConfig = config.Configs["Appearance"];
if (sconfig != null) if (appearanceConfig != null)
{ {
m_savetime = Convert.ToInt32(sconfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime)));
m_sendtime = Convert.ToInt32(sconfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime)));
// m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime);
} }

View File

@ -596,9 +596,14 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
} }
break; break;
case "R": case "R":
Font anewFont = new Font(myFont, FontStyle.Regular); // We need to place this newFont inside its own context so that the .NET compiler
// doesn't complain about a redefinition of an existing newFont, even though there is none
// The mono compiler doesn't produce this error.
{
Font newFont = new Font(myFont, FontStyle.Regular);
myFont.Dispose(); myFont.Dispose();
myFont = anewFont; myFont = newFont;
}
break; break;
} }
} }

View File

@ -124,7 +124,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
LandData landData = lo.LandData; LandData landData = lo.LandData;
string landDataPath = String.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH, string landDataPath = String.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH,
landData.GlobalID.ToString()); landData.GlobalID.ToString());
m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData)); m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
} }
m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive."); m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");

View File

@ -84,7 +84,7 @@ namespace OpenSim.Region.Framework.Interfaces
/// <param name="AttachmentPt"></param> /// <param name="AttachmentPt"></param>
/// <param name="silent"></param> /// <param name="silent"></param>
/// <returns>true if the object was successfully attached, false otherwise</returns> /// <returns>true if the object was successfully attached, false otherwise</returns>
bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo); bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool temp);
/// <summary> /// <summary>
/// Rez an attachment from user inventory and change inventory status to match. /// Rez an attachment from user inventory and change inventory status to match.

View File

@ -842,7 +842,6 @@ namespace OpenSim.Region.Framework.Scenes
m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences); m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences);
m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain); m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning); m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning);
SendPeriodicAppearanceUpdates = startupConfig.GetBoolean("SendPeriodicAppearanceUpdates", SendPeriodicAppearanceUpdates);
} }
} }
catch (Exception e) catch (Exception e)
@ -850,6 +849,14 @@ namespace OpenSim.Region.Framework.Scenes
m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString()); m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString());
} }
// FIXME: Ultimately this should be in a module.
IConfig appearanceConfig = m_config.Configs["Appearance"];
if (appearanceConfig != null)
{
SendPeriodicAppearanceUpdates
= appearanceConfig.GetBoolean("ResendAppearanceUpdates", SendPeriodicAppearanceUpdates);
}
#endregion Region Config #endregion Region Config
#region Interest Management #region Interest Management
@ -2748,7 +2755,7 @@ namespace OpenSim.Region.Framework.Scenes
RootPrim.RemFlag(PrimFlags.TemporaryOnRez); RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
if (AttachmentsModule != null) if (AttachmentsModule != null)
AttachmentsModule.AttachObject(sp, grp, 0, false, false); AttachmentsModule.AttachObject(sp, grp, 0, false, false, false);
} }
else else
{ {

View File

@ -951,7 +951,7 @@ namespace OpenSim.Region.Framework.Scenes
/// its existing localID and UUID. /// its existing localID and UUID.
/// </summary> /// </summary>
/// <param name='part'>Root part for this scene object.</param> /// <param name='part'>Root part for this scene object.</param>
public SceneObjectGroup(SceneObjectPart part) public SceneObjectGroup(SceneObjectPart part) : this()
{ {
SetRootPart(part); SetRootPart(part);
} }

View File

@ -0,0 +1,126 @@
/*
* 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.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Monitoring;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.OptionalModules.Avatar.Attachments
{
/// <summary>
/// A module that just holds commands for inspecting avatar appearance.
/// </summary>
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "TempAttachmentsModule")]
public class TempAttachmentsModule : INonSharedRegionModule
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene;
public void Initialise(IConfigSource configSource)
{
}
public void AddRegion(Scene scene)
{
m_scene = scene;
IScriptModuleComms comms = scene.RequestModuleInterface<IScriptModuleComms>();
if (comms != null)
{
comms.RegisterScriptInvocation( this, "llAttachToAvatarTemp");
m_log.DebugFormat("[TEMP ATTACHS]: Registered script functions");
}
else
{
m_log.ErrorFormat("[TEMP ATTACHS]: Failed to register script functions");
}
}
public void RemoveRegion(Scene scene)
{
}
public void RegionLoaded(Scene scene)
{
}
public void Close()
{
}
public Type ReplaceableInterface
{
get { return null; }
}
public string Name
{
get { return "TempAttachmentsModule"; }
}
private void llAttachToAvatarTemp(UUID host, UUID script, int attachmentPoint)
{
SceneObjectPart hostPart = m_scene.GetSceneObjectPart(host);
if (hostPart == null)
return;
if (hostPart.ParentGroup.IsAttachment)
return;
IAttachmentsModule attachmentsModule = m_scene.RequestModuleInterface<IAttachmentsModule>();
if (attachmentsModule == null)
return;
TaskInventoryItem item = hostPart.Inventory.GetInventoryItem(script);
if (item == null)
return;
if ((item.PermsMask & 32) == 0) // PERMISSION_ATTACH
return;
ScenePresence target;
if (!m_scene.TryGetScenePresence(item.PermsGranter, out target))
return;
attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true, true);
}
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BS6DofConstraint : BSConstraint
{
// Create a btGeneric6DofConstraint
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 frame1, Quaternion frame1rot,
Vector3 frame2, Quaternion frame2rot )
{
m_world = world;
m_body1 = obj1;
m_body2 = obj2;
m_constraint = new BulletConstraint(
BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
frame1, frame1rot,
frame2, frame2rot,
true /*useLinearReferenceFrameA*/, true /*disableCollisionsBetweenLinkedBodies*/));
m_enabled = true;
}
public bool SetCFMAndERP(float cfm, float erp)
{
bool ret = true;
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
return ret;
}
public bool UseFrameOffset(bool useOffset)
{
bool ret = false;
float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled)
ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
return ret;
}
public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
{
bool ret = false;
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled)
ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
return ret;
}
}
}

View File

@ -40,6 +40,7 @@ public class BSCharacter : PhysicsActor
private static readonly string LogHeader = "[BULLETS CHAR]"; private static readonly string LogHeader = "[BULLETS CHAR]";
private BSScene _scene; private BSScene _scene;
public BSScene Scene { get { return _scene; } }
private String _avName; private String _avName;
// private bool _stopped; // private bool _stopped;
private Vector3 _size; private Vector3 _size;
@ -73,6 +74,12 @@ public class BSCharacter : PhysicsActor
private bool _kinematic; private bool _kinematic;
private float _buoyancy; private float _buoyancy;
private BulletBody m_body;
public BulletBody Body {
get { return m_body; }
set { m_body = value; }
}
private int _subscribedEventsMs = 0; private int _subscribedEventsMs = 0;
private int _nextCollisionOkTime = 0; private int _nextCollisionOkTime = 0;
@ -95,7 +102,9 @@ public class BSCharacter : PhysicsActor
_orientation = Quaternion.Identity; _orientation = Quaternion.Identity;
_velocity = Vector3.Zero; _velocity = Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying); _buoyancy = ComputeBuoyancyFromFlying(isFlying);
_scale = new Vector3(1f, 1f, 1f); // The dimensions of the avatar capsule are kept in the scale.
// Physics creates a unit capsule which is scaled by the physics engine.
_scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z);
_density = _scene.Params.avatarDensity; _density = _scene.Params.avatarDensity;
ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
@ -113,9 +122,13 @@ public class BSCharacter : PhysicsActor
shapeData.Restitution = _scene.Params.avatarRestitution; shapeData.Restitution = _scene.Params.avatarRestitution;
// do actual create at taint time // do actual create at taint time
_scene.TaintedObject(delegate() _scene.TaintedObject("BSCharacter.create", delegate()
{ {
BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData);
m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
// avatars get all collisions no matter what
BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
}); });
return; return;
@ -124,7 +137,8 @@ public class BSCharacter : PhysicsActor
// called when this character is being destroyed and the resources should be released // called when this character is being destroyed and the resources should be released
public void Destroy() public void Destroy()
{ {
_scene.TaintedObject(delegate() // DetailLog("{0},Destroy", LocalID);
_scene.TaintedObject("BSCharacter.destroy", delegate()
{ {
BulletSimAPI.DestroyObject(_scene.WorldID, _localID); BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
}); });
@ -139,8 +153,27 @@ public class BSCharacter : PhysicsActor
get { return false; } get { return false; }
} }
public override Vector3 Size { public override Vector3 Size {
get { return _size; } get
set { _size = value; {
// Avatar capsule size is kept in the scale parameter.
return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
}
set {
// When an avatar's size is set, only the height is changed
// and that really only depends on the radius.
_size = value;
_scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
// TODO: something has to be done with the avatar's vertical position
ComputeAvatarVolumeAndMass();
_scene.TaintedObject("BSCharacter.setSize", delegate()
{
BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true);
});
} }
} }
public override PrimitiveBaseShape Shape { public override PrimitiveBaseShape Shape {
@ -172,12 +205,37 @@ public class BSCharacter : PhysicsActor
} }
set { set {
_position = value; _position = value;
_scene.TaintedObject(delegate() PositionSanityCheck();
_scene.TaintedObject("BSCharacter.setPosition", delegate()
{ {
DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
}); });
} }
} }
// Check that the current position is sane and, if not, modify the position to make it so.
// Check for being below terrain and being out of bounds.
// Returns 'true' of the position was made sane by some action.
private bool PositionSanityCheck()
{
bool ret = false;
// If below the ground, move the avatar up
float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position);
if (_position.Z < terrainHeight)
{
DetailLog("{0},PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation);
_position.Z = terrainHeight + 2.0f;
ret = true;
}
// TODO: check for out of bounds
return ret;
}
public override float Mass { public override float Mass {
get { get {
return _mass; return _mass;
@ -188,9 +246,10 @@ public class BSCharacter : PhysicsActor
set { set {
_force = value; _force = value;
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
_scene.TaintedObject(delegate() Scene.TaintedObject("BSCharacter.SetForce", delegate()
{ {
BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force);
}); });
} }
} }
@ -214,8 +273,9 @@ public class BSCharacter : PhysicsActor
set { set {
_velocity = value; _velocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
_scene.TaintedObject(delegate() _scene.TaintedObject("BSCharacter.setVelocity", delegate()
{ {
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
}); });
} }
@ -239,7 +299,7 @@ public class BSCharacter : PhysicsActor
set { set {
_orientation = value; _orientation = value;
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
_scene.TaintedObject(delegate() _scene.TaintedObject("BSCharacter.setOrientation", delegate()
{ {
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
@ -259,11 +319,14 @@ public class BSCharacter : PhysicsActor
public override bool Flying { public override bool Flying {
get { return _flying; } get { return _flying; }
set { set {
if (_flying != value)
{
_flying = value; _flying = value;
// simulate flying by changing the effect of gravity // simulate flying by changing the effect of gravity
this.Buoyancy = ComputeBuoyancyFromFlying(_flying); this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
} }
} }
}
private float ComputeBuoyancyFromFlying(bool ifFlying) { private float ComputeBuoyancyFromFlying(bool ifFlying) {
return ifFlying ? 1f : 0f; return ifFlying ? 1f : 0f;
} }
@ -303,8 +366,9 @@ public class BSCharacter : PhysicsActor
public override float Buoyancy { public override float Buoyancy {
get { return _buoyancy; } get { return _buoyancy; }
set { _buoyancy = value; set { _buoyancy = value;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSCharacter.setBuoyancy", delegate()
{ {
DetailLog("{0},setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
}); });
} }
@ -349,9 +413,10 @@ public class BSCharacter : PhysicsActor
_force.Y += force.Y; _force.Y += force.Y;
_force.Z += force.Z; _force.Z += force.Z;
// m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
_scene.TaintedObject(delegate() _scene.TaintedObject("BSCharacter.AddForce", delegate()
{ {
BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); DetailLog("{0},setAddForce,taint,addedForce={1}", LocalID, _force);
BulletSimAPI.AddObjectForce2(Body.Ptr, _force);
}); });
} }
else else
@ -369,11 +434,25 @@ public class BSCharacter : PhysicsActor
// Turn on collision events at a rate no faster than one every the given milliseconds // Turn on collision events at a rate no faster than one every the given milliseconds
public override void SubscribeEvents(int ms) { public override void SubscribeEvents(int ms) {
_subscribedEventsMs = ms; _subscribedEventsMs = ms;
_nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen if (ms > 0)
{
// make sure first collision happens
_nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate()
{
BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
} }
// Stop collision events // Stop collision events
public override void UnSubscribeEvents() { public override void UnSubscribeEvents() {
_subscribedEventsMs = 0; _subscribedEventsMs = 0;
// Avatars get all their collision events
// Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate()
// {
// BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
// });
} }
// Return 'true' if someone has subscribed to events // Return 'true' if someone has subscribed to events
public override bool SubscribedEvents() { public override bool SubscribedEvents() {
@ -385,9 +464,15 @@ public class BSCharacter : PhysicsActor
{ {
_avatarVolume = (float)( _avatarVolume = (float)(
Math.PI Math.PI
* _scene.Params.avatarCapsuleRadius * _scale.X * _scale.X
* _scene.Params.avatarCapsuleRadius * _scale.Y * _scale.Y // the area of capsule cylinder
* _scene.Params.avatarCapsuleHeight * _scale.Z); * _scale.Z // times height of capsule cylinder
+ 1.33333333f
* Math.PI
* _scale.X
* Math.Min(_scale.X, _scale.Y)
* _scale.Y // plus the volume of the capsule end caps
);
_mass = _density * _avatarVolume; _mass = _density * _avatarVolume;
} }
@ -395,43 +480,17 @@ public class BSCharacter : PhysicsActor
// the world that things have changed. // the world that things have changed.
public void UpdateProperties(EntityProperties entprop) public void UpdateProperties(EntityProperties entprop)
{ {
/*
bool changed = false;
// we assign to the local variables so the normal set action does not happen
if (_position != entprop.Position) {
_position = entprop.Position;
changed = true;
}
if (_orientation != entprop.Rotation) {
_orientation = entprop.Rotation;
changed = true;
}
if (_velocity != entprop.Velocity) {
_velocity = entprop.Velocity;
changed = true;
}
if (_acceleration != entprop.Acceleration) {
_acceleration = entprop.Acceleration;
changed = true;
}
if (_rotationalVelocity != entprop.RotationalVelocity) {
_rotationalVelocity = entprop.RotationalVelocity;
changed = true;
}
if (changed) {
// m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
// Avatar movement is not done by generating this event. There is code in the heartbeat
// loop that updates avatars.
// base.RequestPhysicsterseUpdate();
}
*/
_position = entprop.Position; _position = entprop.Position;
_orientation = entprop.Rotation; _orientation = entprop.Rotation;
_velocity = entprop.Velocity; _velocity = entprop.Velocity;
_acceleration = entprop.Acceleration; _acceleration = entprop.Acceleration;
_rotationalVelocity = entprop.RotationalVelocity; _rotationalVelocity = entprop.RotationalVelocity;
// Avatars don't report theirr changes the usual way. Changes are checked for in the heartbeat loop. // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
// base.RequestPhysicsterseUpdate(); // base.RequestPhysicsterseUpdate();
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity);
} }
// Called by the scene when a collision with this object is reported // Called by the scene when a collision with this object is reported
@ -480,5 +539,10 @@ public class BSCharacter : PhysicsActor
// End kludge // End kludge
} }
// Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args)
{
Scene.PhysicsLogging.Write(msg, args);
}
} }
} }

View File

@ -32,35 +32,26 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSConstraint : IDisposable public abstract class BSConstraint : IDisposable
{ {
private BulletSim m_world; protected BulletSim m_world;
private BulletBody m_body1; protected BulletBody m_body1;
private BulletBody m_body2; protected BulletBody m_body2;
private BulletConstraint m_constraint; protected BulletConstraint m_constraint;
private bool m_enabled = false; protected bool m_enabled = false;
public BSConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, public BSConstraint()
Vector3 frame1, Quaternion frame1rot,
Vector3 frame2, Quaternion frame2rot
)
{ {
m_world = world;
m_body1 = obj1;
m_body2 = obj2;
m_constraint = new BulletConstraint(BulletSimAPI.CreateConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
frame1, frame1rot,
frame2, frame2rot,
true /*useLinearReferenceFrameA*/, true /*disableCollisionsBetweenLinkedBodies*/));
m_enabled = true;
} }
public void Dispose() public virtual void Dispose()
{ {
if (m_enabled) if (m_enabled)
{ {
// BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID); // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr); bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
m_constraint.Ptr = System.IntPtr.Zero;
m_enabled = false; m_enabled = false;
} }
} }
@ -68,7 +59,7 @@ public class BSConstraint : IDisposable
public BulletBody Body1 { get { return m_body1; } } public BulletBody Body1 { get { return m_body1; } }
public BulletBody Body2 { get { return m_body2; } } public BulletBody Body2 { get { return m_body2; } }
public bool SetLinearLimits(Vector3 low, Vector3 high) public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
{ {
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
@ -76,7 +67,7 @@ public class BSConstraint : IDisposable
return ret; return ret;
} }
public bool SetAngularLimits(Vector3 low, Vector3 high) public virtual bool SetAngularLimits(Vector3 low, Vector3 high)
{ {
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
@ -84,34 +75,7 @@ public class BSConstraint : IDisposable
return ret; return ret;
} }
public bool SetCFMAndERP(float cfm, float erp) public virtual bool CalculateTransforms()
{
bool ret = true;
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
return ret;
}
public bool UseFrameOffset(bool useOffset)
{
bool ret = false;
float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled)
ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
return ret;
}
public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
{
bool ret = false;
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled)
ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
return ret;
}
public bool CalculateTransforms()
{ {
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)

View File

@ -63,21 +63,13 @@ public class BSConstraintCollection : IDisposable
m_constraints.Clear(); m_constraints.Clear();
} }
public BSConstraint CreateConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 frame1, Quaternion frame1rot,
Vector3 frame2, Quaternion frame2rot)
{
BSConstraint constrain = new BSConstraint(world, obj1, obj2, frame1, frame1rot, frame2, frame2rot);
this.AddConstraint(constrain);
return constrain;
}
public bool AddConstraint(BSConstraint cons) public bool AddConstraint(BSConstraint cons)
{ {
// There is only one constraint between any bodies. Remove any old just to make sure. // There is only one constraint between any bodies. Remove any old just to make sure.
RemoveAndDestroyConstraint(cons.Body1, cons.Body2); RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
m_world.scene.DetailLog("{0},BSConstraintCollection.AddConstraint,call,body1={1},body2={2}", BSScene.DetailLogZero, cons.Body1.ID, cons.Body2.ID);
m_constraints.Add(cons); m_constraints.Add(cons);
return true; return true;
@ -118,6 +110,7 @@ public class BSConstraintCollection : IDisposable
if (this.TryGetConstraint(body1, body2, out constrain)) if (this.TryGetConstraint(body1, body2, out constrain))
{ {
m_world.scene.DetailLog("{0},BSConstraintCollection.RemoveAndDestroyConstraint,taint,body1={1},body2={2}", BSScene.DetailLogZero, body1.ID, body2.ID);
// remove the constraint from our collection // remove the constraint from our collection
m_constraints.Remove(constrain); m_constraints.Remove(constrain);
// tell the engine that all its structures need to be freed // tell the engine that all its structures need to be freed
@ -158,10 +151,11 @@ public class BSConstraintCollection : IDisposable
public bool RecalculateAllConstraints() public bool RecalculateAllConstraints()
{ {
foreach (BSConstraint constrain in m_constraints) ForEachConstraint(delegate(BSConstraint constrain)
{ {
constrain.CalculateTransforms(); constrain.CalculateTransforms();
} return false;
});
return true; return true;
} }

View File

@ -40,6 +40,7 @@ public class BSLinkset
public BSPrim Root { get { return m_linksetRoot; } } public BSPrim Root { get { return m_linksetRoot; } }
private BSScene m_scene; private BSScene m_scene;
public BSScene Scene { get { return m_scene; } }
private List<BSPrim> m_children; private List<BSPrim> m_children;
@ -80,14 +81,14 @@ public class BSLinkset
// Link to a linkset where the child knows the parent. // Link to a linkset where the child knows the parent.
// Parent changing should not happen so do some sanity checking. // Parent changing should not happen so do some sanity checking.
// We return the parent's linkset so the child can track it's membership. // We return the parent's linkset so the child can track its membership.
public BSLinkset AddMeToLinkset(BSPrim child, BSPrim parent) public BSLinkset AddMeToLinkset(BSPrim child)
{ {
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
parent.Linkset.AddChildToLinkset(child); AddChildToLinkset(child);
} }
return parent.Linkset; return this;
} }
public BSLinkset RemoveMeFromLinkset(BSPrim child) public BSLinkset RemoveMeFromLinkset(BSPrim child)
@ -101,7 +102,7 @@ public class BSLinkset
{ {
// Note that we don't do a foreach because the remove routine // Note that we don't do a foreach because the remove routine
// takes it out of the list. // takes it out of the list.
RemoveChildFromLinkset(m_children[0]); RemoveChildFromOtherLinkset(m_children[0]);
} }
m_children.Clear(); // just to make sure m_children.Clear(); // just to make sure
} }
@ -113,9 +114,10 @@ public class BSLinkset
} }
// The child is down to a linkset of just itself // The child is down to a linkset of just itself
return new BSLinkset(m_scene, child); return new BSLinkset(Scene, child);
} }
/* DEPRECATED: this is really bad in that it trys to unlink other prims.
// An existing linkset had one of its members rebuilt or something. // An existing linkset had one of its members rebuilt or something.
// Go through the linkset and rebuild the pointers to the bodies of the linkset members. // Go through the linkset and rebuild the pointers to the bodies of the linkset members.
public BSLinkset RefreshLinkset(BSPrim requestor) public BSLinkset RefreshLinkset(BSPrim requestor)
@ -124,6 +126,7 @@ public class BSLinkset
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
// The body pointer is refetched in case anything has moved.
System.IntPtr aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, m_linksetRoot.LocalID); System.IntPtr aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, m_linksetRoot.LocalID);
if (aPtr == System.IntPtr.Zero) if (aPtr == System.IntPtr.Zero)
{ {
@ -155,13 +158,14 @@ public class BSLinkset
} }
foreach (BSPrim bsp in toRemove) foreach (BSPrim bsp in toRemove)
{ {
RemoveChildFromLinkset(bsp); RemoveChildFromOtherLinkset(bsp);
} }
} }
} }
return ret; return ret;
} }
*/
// Return 'true' if the passed object is the root object of this linkset // Return 'true' if the passed object is the root object of this linkset
@ -170,6 +174,8 @@ public class BSLinkset
return (requestor.LocalID == m_linksetRoot.LocalID); return (requestor.LocalID == m_linksetRoot.LocalID);
} }
public int NumberOfChildren { get { return m_children.Count; } }
// Return 'true' if this linkset has any children (more than the root member) // Return 'true' if this linkset has any children (more than the root member)
public bool HasAnyChildren { get { return (m_children.Count > 0); } } public bool HasAnyChildren { get { return (m_children.Count > 0); } }
@ -208,6 +214,7 @@ public class BSLinkset
com += bp.Position * bp.MassRaw; com += bp.Position * bp.MassRaw;
totalMass += bp.MassRaw; totalMass += bp.MassRaw;
} }
if (totalMass != 0f)
com /= totalMass; com /= totalMass;
return com; return com;
@ -221,51 +228,54 @@ public class BSLinkset
{ {
com += bp.Position * bp.MassRaw; com += bp.Position * bp.MassRaw;
} }
com /= m_children.Count + 1; com /= (m_children.Count + 1);
return com; return com;
} }
// I am the root of a linkset and a new child is being added // I am the root of a linkset and a new child is being added
public void AddChildToLinkset(BSPrim pchild) // Called while LinkActivity is locked.
public void AddChildToLinkset(BSPrim child)
{ {
BSPrim child = pchild;
if (!HasChild(child)) if (!HasChild(child))
{ {
m_children.Add(child); m_children.Add(child);
m_scene.TaintedObject(delegate() BSPrim root = Root; // capture the root as of now
m_scene.TaintedObject("AddChildToLinkset", delegate()
{ {
DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID);
DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID); DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
PhysicallyLinkAChildToRoot(pchild); // build the physical binding between me and the child PhysicallyLinkAChildToRoot(root, child); // build the physical binding between me and the child
}); });
} }
return; return;
} }
// Forcefully removing a child from a linkset.
// This is not being called by the child so we have to make sure the child doesn't think
// it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
// has to be updated also (like pointer to prim's parent).
public void RemoveChildFromOtherLinkset(BSPrim pchild)
{
pchild.Linkset = new BSLinkset(m_scene, pchild);
RemoveChildFromLinkset(pchild);
}
// I am the root of a linkset and one of my children is being removed. // 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. // Safe to call even if the child is not really in my linkset.
public void RemoveChildFromLinkset(BSPrim pchild) public void RemoveChildFromLinkset(BSPrim child)
{ {
BSPrim child = pchild;
if (m_children.Remove(child)) if (m_children.Remove(child))
{ {
m_scene.TaintedObject(delegate() BSPrim root = Root; // capture the root as of now
m_scene.TaintedObject("RemoveChildFromLinkset", delegate()
{ {
DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID); DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
if (m_children.Count == 0) PhysicallyUnlinkAChildFromRoot(root, child);
{
// if the linkset is empty, make sure all linkages have been removed
PhysicallyUnlinkAllChildrenFromRoot();
}
else
{
PhysicallyUnlinkAChildFromRoot(pchild);
}
}); });
} }
else else
@ -278,14 +288,14 @@ public class BSLinkset
// Create a constraint between me (root of linkset) and the passed prim (the child). // Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time! // Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPrim childPrim) private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim)
{ {
// Zero motion for children so they don't interpolate // Zero motion for children so they don't interpolate
childPrim.ZeroMotion(); childPrim.ZeroMotion();
// relative position normalized to the root prim // relative position normalized to the root prim
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation); OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation; OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
// relative rotation of the child to the parent // relative rotation of the child to the parent
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
@ -293,16 +303,17 @@ public class BSLinkset
// create a constraint that allows no freedom of movement between the two objects // create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
// DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID); DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
BSConstraint constrain = m_scene.Constraints.CreateConstraint( BS6DofConstraint constrain = new BS6DofConstraint(
m_scene.World, m_linksetRoot.Body, childPrim.Body, m_scene.World, rootPrim.Body, childPrim.Body,
// childRelativePosition, childRelativePosition,
// childRelativeRotation, childRelativeRotation,
OMV.Vector3.Zero, OMV.Vector3.Zero,
OMV.Quaternion.Identity, -childRelativeRotation
OMV.Vector3.Zero,
OMV.Quaternion.Identity
); );
m_scene.Constraints.AddConstraint(constrain);
// zero linear and angular limits makes the objects unable to move in relation to each other
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@ -317,28 +328,31 @@ public class BSLinkset
// Remove linkage between myself and a particular child // Remove linkage between myself and a particular child
// Called at taint time! // Called at taint time!
private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim) private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim)
{ {
DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}",
LogHeader, m_linksetRoot.LocalID, childPrim.LocalID); // LogHeader, rootPrim.LocalID, childPrim.LocalID);
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID); DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
// BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body); m_scene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body, childPrim.Body);
// Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.Body.Ptr);
} }
// Remove linkage between myself and any possible children I might have // Remove linkage between myself and any possible children I might have
// Called at taint time! // Called at taint time!
private void PhysicallyUnlinkAllChildrenFromRoot() private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim)
{ {
// DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID); DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body);
// BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID); m_scene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body);
} }
// Invoke the detailed logger and output something if it's enabled. // Invoke the detailed logger and output something if it's enabled.
private void DebugLog(string msg, params Object[] args) private void DebugLog(string msg, params Object[] args)
{ {
if (m_scene.ShouldDebugLog)
m_scene.Logger.DebugFormat(msg, args); m_scene.Logger.DebugFormat(msg, args);
} }

View File

@ -42,7 +42,7 @@ public sealed class BSPrim : PhysicsActor
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 string LogHeader = "[BULLETS PRIM]"; private static readonly string LogHeader = "[BULLETS PRIM]";
private void DebugLog(string mm, params Object[] xx) { if (_scene.shouldDebugLog) m_log.DebugFormat(mm, xx); } private void DebugLog(string mm, params Object[] xx) { if (_scene.ShouldDebugLog) m_log.DebugFormat(mm, xx); }
private IMesh _mesh; private IMesh _mesh;
private PrimitiveBaseShape _pbs; private PrimitiveBaseShape _pbs;
@ -145,7 +145,8 @@ public sealed class BSPrim : PhysicsActor
_vehicle = new BSDynamics(this); // add vehicleness _vehicle = new BSDynamics(this); // add vehicleness
_mass = CalculateMass(); _mass = CalculateMass();
// do the actual object creation at taint time // do the actual object creation at taint time
_scene.TaintedObject(delegate() DetailLog("{0},BSPrim.constructor,call", LocalID);
_scene.TaintedObject("BSPrim.create", delegate()
{ {
RecreateGeomAndObject(); RecreateGeomAndObject();
@ -160,17 +161,22 @@ public sealed class BSPrim : PhysicsActor
public void Destroy() public void Destroy()
{ {
// m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
// DetailLog("{0},Destroy", LocalID);
// Undo any vehicle properties
_vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
_scene.RemoveVehiclePrim(this); // just to make sure
_scene.TaintedObject(delegate()
{
// Undo any links between me and any other object // Undo any links between me and any other object
BSPrim parentBefore = _linkset.Root;
int childrenBefore = _linkset.NumberOfChildren;
_linkset = _linkset.RemoveMeFromLinkset(this); _linkset = _linkset.RemoveMeFromLinkset(this);
DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
LocalID, parentBefore.LocalID, childrenBefore, _linkset.Root.LocalID, _linkset.NumberOfChildren);
// Undo any vehicle properties
this.VehicleType = (int)Vehicle.TYPE_NONE;
_scene.TaintedObject("BSPrim.destroy", delegate()
{
DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
// everything in the C# world will get garbage collected. Tell the C++ world to free stuff. // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
}); });
@ -183,11 +189,11 @@ public sealed class BSPrim : PhysicsActor
get { return _size; } get { return _size; }
set { set {
_size = value; _size = value;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setSize", delegate()
{ {
_mass = CalculateMass(); // changing size changes the mass _mass = CalculateMass(); // changing size changes the mass
BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical); BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
DetailLog("{0}: setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical); // DetailLog("{0}: BSPrim.setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical);
RecreateGeomAndObject(); RecreateGeomAndObject();
}); });
} }
@ -195,7 +201,7 @@ public sealed class BSPrim : PhysicsActor
public override PrimitiveBaseShape Shape { public override PrimitiveBaseShape Shape {
set { set {
_pbs = value; _pbs = value;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setShape", delegate()
{ {
_mass = CalculateMass(); // changing the shape changes the mass _mass = CalculateMass(); // changing the shape changes the mass
RecreateGeomAndObject(); RecreateGeomAndObject();
@ -213,7 +219,7 @@ public sealed class BSPrim : PhysicsActor
public override bool Selected { public override bool Selected {
set { set {
_isSelected = value; _isSelected = value;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setSelected", delegate()
{ {
SetObjectDynamic(); SetObjectDynamic();
}); });
@ -224,10 +230,17 @@ public sealed class BSPrim : PhysicsActor
// link me to the specified parent // link me to the specified parent
public override void link(PhysicsActor obj) { public override void link(PhysicsActor obj) {
BSPrim parent = obj as BSPrim; BSPrim parent = obj as BSPrim;
DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); if (parent != null)
DetailLog("{0},link,parent={1}", LocalID, obj.LocalID); {
DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID);
BSPrim parentBefore = _linkset.Root;
int childrenBefore = _linkset.NumberOfChildren;
_linkset = _linkset.AddMeToLinkset(this, parent); _linkset = parent.Linkset.AddMeToLinkset(this);
DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
LocalID, parentBefore.LocalID, childrenBefore, _linkset.Root.LocalID, _linkset.NumberOfChildren);
}
return; return;
} }
@ -237,9 +250,14 @@ public sealed class BSPrim : PhysicsActor
// Race condition here: if link() and delink() in same simulation tick, the delink will not happen // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
_linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString()); _linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString());
DetailLog("{0},delink,parent={1}", LocalID, _linkset.Root.LocalID.ToString());
_linkset.RemoveMeFromLinkset(this); BSPrim parentBefore = _linkset.Root;
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.Root.LocalID, _linkset.NumberOfChildren);
return; return;
} }
@ -262,7 +280,7 @@ public sealed class BSPrim : PhysicsActor
public override void LockAngularMotion(OMV.Vector3 axis) public override void LockAngularMotion(OMV.Vector3 axis)
{ {
DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis); DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
return; return;
} }
@ -279,9 +297,9 @@ public sealed class BSPrim : PhysicsActor
set { set {
_position = value; _position = value;
// TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setPosition", delegate()
{ {
DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
}); });
} }
@ -316,9 +334,9 @@ public sealed class BSPrim : PhysicsActor
get { return _force; } get { return _force; }
set { set {
_force = value; _force = value;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setForce", delegate()
{ {
DetailLog("{0},SetForce,taint,force={1}", LocalID, _force); DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
// BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
BulletSimAPI.SetObjectForce2(Body.Ptr, _force); BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
}); });
@ -331,53 +349,41 @@ public sealed class BSPrim : PhysicsActor
} }
set { set {
Vehicle type = (Vehicle)value; Vehicle type = (Vehicle)value;
_scene.TaintedObject(delegate() BSPrim vehiclePrim = this;
_scene.TaintedObject("setVehicleType", delegate()
{ {
DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type); // Done at taint time so we're sure the physics engine is not using the variables
// Vehicle code changes the parameters for this vehicle type.
_vehicle.ProcessTypeChange(type); _vehicle.ProcessTypeChange(type);
if (type == Vehicle.TYPE_NONE) // Tell the scene about the vehicle so it will get processing each frame.
{ _scene.VehicleInSceneTypeChanged(this, type);
_scene.RemoveVehiclePrim(this);
}
else
{
_scene.TaintedObject(delegate()
{
// Tell the physics engine to clear state
BulletSimAPI.ClearForces2(this.Body.Ptr);
});
// make it so the scene will call us each tick to do vehicle things
_scene.AddVehiclePrim(this);
}
return;
}); });
} }
} }
public override void VehicleFloatParam(int param, float value) public override void VehicleFloatParam(int param, float value)
{ {
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
{ {
_vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
}); });
} }
public override void VehicleVectorParam(int param, OMV.Vector3 value) public override void VehicleVectorParam(int param, OMV.Vector3 value)
{ {
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
{ {
_vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
}); });
} }
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
{ {
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
{ {
_vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
}); });
} }
public override void VehicleFlags(int param, bool remove) public override void VehicleFlags(int param, bool remove)
{ {
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.VehicleFlags", delegate()
{ {
_vehicle.ProcessVehicleFlags(param, remove); _vehicle.ProcessVehicleFlags(param, remove);
}); });
@ -395,7 +401,7 @@ public sealed class BSPrim : PhysicsActor
public override void SetVolumeDetect(int param) { public override void SetVolumeDetect(int param) {
bool newValue = (param != 0); bool newValue = (param != 0);
_isVolumeDetect = newValue; _isVolumeDetect = newValue;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
{ {
SetObjectDynamic(); SetObjectDynamic();
}); });
@ -406,9 +412,9 @@ public sealed class BSPrim : PhysicsActor
get { return _velocity; } get { return _velocity; }
set { set {
_velocity = value; _velocity = value;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setVelocity", delegate()
{ {
DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity); DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
}); });
} }
@ -416,7 +422,7 @@ public sealed class BSPrim : PhysicsActor
public override OMV.Vector3 Torque { public override OMV.Vector3 Torque {
get { return _torque; } get { return _torque; }
set { _torque = value; set { _torque = value;
DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque); DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
} }
} }
public override float CollisionScore { public override float CollisionScore {
@ -440,10 +446,10 @@ public sealed class BSPrim : PhysicsActor
set { set {
_orientation = value; _orientation = value;
// TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setOrientation", delegate()
{ {
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
DetailLog("{0},SetOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
}); });
} }
@ -457,7 +463,7 @@ public sealed class BSPrim : PhysicsActor
get { return _isPhysical; } get { return _isPhysical; }
set { set {
_isPhysical = value; _isPhysical = value;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setIsPhysical", delegate()
{ {
SetObjectDynamic(); SetObjectDynamic();
}); });
@ -478,7 +484,6 @@ public sealed class BSPrim : PhysicsActor
// Make gravity work if the object is physical and not selected // Make gravity work if the object is physical and not selected
// No locking here because only called when it is safe // No locking here because only called when it is safe
// Only called at taint time so it is save to call into Bullet.
private void SetObjectDynamic() private void SetObjectDynamic()
{ {
// RA: remove this for the moment. // RA: remove this for the moment.
@ -487,13 +492,13 @@ public sealed class BSPrim : PhysicsActor
// Maybe a VerifyCorrectPhysicalShape() routine? // Maybe a VerifyCorrectPhysicalShape() routine?
// RecreateGeomAndObject(); // RecreateGeomAndObject();
float mass = _mass; // Bullet wants static objects to have a mass of zero
// Bullet wants static objects have a mass of zero float mass = IsStatic ? 0f : _mass;
if (IsStatic)
mass = 0f;
DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, mass);
BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr);
DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf);
} }
// prims don't fly // prims don't fly
@ -548,9 +553,9 @@ public sealed class BSPrim : PhysicsActor
set { set {
_rotationalVelocity = value; _rotationalVelocity = value;
// m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
{ {
DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
}); });
} }
@ -565,9 +570,9 @@ public sealed class BSPrim : PhysicsActor
get { return _buoyancy; } get { return _buoyancy; }
set { set {
_buoyancy = value; _buoyancy = value;
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.setBuoyancy", delegate()
{ {
DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
}); });
} }
@ -607,6 +612,7 @@ public sealed class BSPrim : PhysicsActor
private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
public override void AddForce(OMV.Vector3 force, bool pushforce) { public override void AddForce(OMV.Vector3 force, bool pushforce) {
// for an object, doesn't matter if force is a pushforce or not
if (force.IsFinite()) if (force.IsFinite())
{ {
// _force += force; // _force += force;
@ -618,40 +624,48 @@ public sealed class BSPrim : PhysicsActor
m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
return; return;
} }
_scene.TaintedObject(delegate() _scene.TaintedObject("BSPrim.AddForce", delegate()
{
lock (m_accumulatedForces)
{
if (m_accumulatedForces.Count > 0)
{ {
OMV.Vector3 fSum = OMV.Vector3.Zero; OMV.Vector3 fSum = OMV.Vector3.Zero;
lock (m_accumulatedForces)
{
foreach (OMV.Vector3 v in m_accumulatedForces) foreach (OMV.Vector3 v in m_accumulatedForces)
{ {
fSum += v; fSum += v;
} }
m_accumulatedForces.Clear(); m_accumulatedForces.Clear();
DetailLog("{0},SetObjectForce,taint,force={1}", LocalID, fSum);
BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, fSum);
}
} }
DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force);
BulletSimAPI.AddObjectForce2(Body.Ptr, fSum);
}); });
} }
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
// m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
} }
public override void SetMomentum(OMV.Vector3 momentum) { public override void SetMomentum(OMV.Vector3 momentum) {
DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum); DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
} }
public override void SubscribeEvents(int ms) { public override void SubscribeEvents(int ms) {
_subscribedEventsMs = ms; _subscribedEventsMs = ms;
if (ms > 0)
{
// make sure first collision happens // make sure first collision happens
_nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
Scene.TaintedObject("BSPrim.SubscribeEvents", delegate()
{
BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
} }
public override void UnSubscribeEvents() { public override void UnSubscribeEvents() {
_subscribedEventsMs = 0; _subscribedEventsMs = 0;
Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate()
{
BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
} }
public override bool SubscribedEvents() { public override bool SubscribedEvents() {
return (_subscribedEventsMs > 0); return (_subscribedEventsMs > 0);
@ -970,26 +984,26 @@ public sealed class BSPrim : PhysicsActor
{ {
if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
{ {
if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) // if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
{ // {
// m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
{ {
DetailLog("{0},CreateGeom,sphere", LocalID); DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
// Bullet native objects are scaled by the Bullet engine so pass the size in // Bullet native objects are scaled by the Bullet engine so pass the size in
_scale = _size; _scale = _size;
// TODO: do we need to check for and destroy a mesh or hull that might have been left from before? // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
ret = true; ret = true;
} }
} // }
} }
else else
{ {
// m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size); // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX)) if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX))
{ {
DetailLog("{0},CreateGeom,box", LocalID); DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
_scale = _size; _scale = _size;
// TODO: do we need to check for and destroy a mesh or hull that might have been left from before? // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
@ -1032,12 +1046,12 @@ public sealed class BSPrim : PhysicsActor
// if this new shape is the same as last time, don't recreate the mesh // if this new shape is the same as last time, don't recreate the mesh
if (_meshKey == newMeshKey) return; if (_meshKey == newMeshKey) return;
DetailLog("{0},CreateGeomMesh,create,key={1}", LocalID, _meshKey); DetailLog("{0},BSPrim.CreateGeomMesh,create,key={1}", LocalID, newMeshKey);
// Since we're recreating new, get rid of any previously generated shape // Since we're recreating new, get rid of any previously generated shape
if (_meshKey != 0) if (_meshKey != 0)
{ {
// m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
DetailLog("{0},CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey); DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
_mesh = null; _mesh = null;
_meshKey = 0; _meshKey = 0;
@ -1067,7 +1081,7 @@ public sealed class BSPrim : PhysicsActor
_shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
// meshes are already scaled by the meshmerizer // meshes are already scaled by the meshmerizer
_scale = new OMV.Vector3(1f, 1f, 1f); _scale = new OMV.Vector3(1f, 1f, 1f);
DetailLog("{0},CreateGeomMesh,done", LocalID); DetailLog("{0},BSPrim.CreateGeomMesh,done", LocalID);
return; return;
} }
@ -1081,17 +1095,17 @@ public sealed class BSPrim : PhysicsActor
// if the hull hasn't changed, don't rebuild it // if the hull hasn't changed, don't rebuild it
if (newHullKey == _hullKey) return; if (newHullKey == _hullKey) return;
DetailLog("{0},CreateGeomHull,create,key={1}", LocalID, _meshKey); DetailLog("{0},BSPrim.CreateGeomHull,create,key={1}", LocalID, _meshKey);
// Since we're recreating new, get rid of any previously generated shape // Since we're recreating new, get rid of any previously generated shape
if (_hullKey != 0) if (_hullKey != 0)
{ {
// m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
DetailLog("{0},CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey); DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey);
BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
_hullKey = 0; _hullKey = 0;
_hulls.Clear(); _hulls.Clear();
DetailLog("{0},CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey); DetailLog("{0},BSPrim.CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey);
BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
_mesh = null; // the mesh cannot match either _mesh = null; // the mesh cannot match either
_meshKey = 0; _meshKey = 0;
@ -1188,7 +1202,7 @@ public sealed class BSPrim : PhysicsActor
_shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
// meshes are already scaled by the meshmerizer // meshes are already scaled by the meshmerizer
_scale = new OMV.Vector3(1f, 1f, 1f); _scale = new OMV.Vector3(1f, 1f, 1f);
DetailLog("{0},CreateGeomHull,done", LocalID); DetailLog("{0},BSPrim.CreateGeomHull,done", LocalID);
return; return;
} }
@ -1214,7 +1228,7 @@ public sealed class BSPrim : PhysicsActor
bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape); bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape);
// the CreateObject() may have recreated the rigid body. Make sure we have the latest. // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
m_body.Ptr = BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID); Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
return ret; return ret;
} }
@ -1326,20 +1340,18 @@ public sealed class BSPrim : PhysicsActor
// m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
// LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
DetailLog("{0},UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
base.RequestPhysicsterseUpdate(); base.RequestPhysicsterseUpdate();
} }
/*
else else
{ {
// For debugging, we also report the movement of children // For debugging, we also report the movement of children
DetailLog("{0},UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity); entprop.Acceleration, entprop.RotationalVelocity);
} }
*/
} }
// I've collided with something // I've collided with something

View File

@ -73,7 +73,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS SCENE]"; private static readonly string LogHeader = "[BULLETS SCENE]";
public void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); } public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); }
public string BulletSimVersion = "?"; public string BulletSimVersion = "?";
@ -162,14 +162,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
public delegate void TaintCallback(); public delegate void TaintCallback();
private List<TaintCallback> _taintedObjects; private struct TaintCallbackEntry
{
public String ident;
public TaintCallback callback;
public TaintCallbackEntry(string i, TaintCallback c)
{
ident = i;
callback = c;
}
}
private List<TaintCallbackEntry> _taintedObjects;
private Object _taintLock = new Object(); private Object _taintLock = new Object();
// A pointer to an instance if this structure is passed to the C++ code // A pointer to an instance if this structure is passed to the C++ code
ConfigurationParameters[] m_params; ConfigurationParameters[] m_params;
GCHandle m_paramsHandle; GCHandle m_paramsHandle;
public bool shouldDebugLog { get; private set; } public bool ShouldDebugLog { get; private set; }
private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
@ -232,7 +242,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
} }
_taintedObjects = new List<TaintCallback>(); _taintedObjects = new List<TaintCallbackEntry>();
mesher = meshmerizer; mesher = meshmerizer;
// The bounding box for the simulated world // The bounding box for the simulated world
@ -245,7 +255,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Initialization to support the transition to a new API which puts most of the logic // Initialization to support the transition to a new API which puts most of the logic
// into the C# code so it is easier to modify and add to. // into the C# code so it is easier to modify and add to.
m_worldSim = new BulletSim(m_worldID, BulletSimAPI.GetSimHandle2(m_worldID)); m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID));
m_constraintCollection = new BSConstraintCollection(World); m_constraintCollection = new BSConstraintCollection(World);
m_initialized = true; m_initialized = true;
@ -352,7 +362,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
BSPrim bsprim = prim as BSPrim; BSPrim bsprim = prim as BSPrim;
if (bsprim != null) if (bsprim != null)
{ {
m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); DetailLog("{0},RemovePrim,call", bsprim.LocalID);
// m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
try try
{ {
lock (m_prims) m_prims.Remove(bsprim.LocalID); lock (m_prims) m_prims.Remove(bsprim.LocalID);
@ -377,6 +388,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
if (!m_initialized) return null; if (!m_initialized) return null;
DetailLog("{0},AddPrimShape,call", localID);
BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
lock (m_prims) m_prims.Add(localID, prim); lock (m_prims) m_prims.Add(localID, prim);
return prim; return prim;
@ -416,12 +429,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{ {
numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", "0000000000", numSubSteps, updatedEntityCount, collidersCount); DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount);
} }
catch (Exception e) catch (Exception e)
{ {
m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e);
DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", "0000000000", numSubSteps, updatedEntityCount, collidersCount); DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount);
// updatedEntityCount = 0; // updatedEntityCount = 0;
collidersCount = 0; collidersCount = 0;
} }
@ -535,7 +548,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public override void SetTerrain(float[] heightMap) { public override void SetTerrain(float[] heightMap) {
m_heightMap = heightMap; m_heightMap = heightMap;
this.TaintedObject(delegate() this.TaintedObject("BSScene.SetTerrain", delegate()
{ {
BulletSimAPI.SetHeightmap(m_worldID, m_heightMap); BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
}); });
@ -727,12 +740,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Calls to the PhysicsActors can't directly call into the physics engine // Calls to the PhysicsActors can't directly call into the physics engine
// because it might be busy. We delay changes to a known time. // because it might be busy. We delay changes to a known time.
// We rely on C#'s closure to save and restore the context for the delegate. // We rely on C#'s closure to save and restore the context for the delegate.
public void TaintedObject(TaintCallback callback) public void TaintedObject(String ident, TaintCallback callback)
{ {
if (!m_initialized) return; if (!m_initialized) return;
lock (_taintLock) lock (_taintLock)
_taintedObjects.Add(callback); _taintedObjects.Add(new TaintCallbackEntry(ident, callback));
return; return;
} }
@ -744,22 +757,22 @@ public class BSScene : PhysicsScene, IPhysicsParameters
if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
{ {
// swizzle a new list into the list location so we can process what's there // swizzle a new list into the list location so we can process what's there
List<TaintCallback> oldList; List<TaintCallbackEntry> oldList;
lock (_taintLock) lock (_taintLock)
{ {
oldList = _taintedObjects; oldList = _taintedObjects;
_taintedObjects = new List<TaintCallback>(); _taintedObjects = new List<TaintCallbackEntry>();
} }
foreach (TaintCallback callback in oldList) foreach (TaintCallbackEntry tcbe in oldList)
{ {
try try
{ {
callback(); tcbe.callback();
} }
catch (Exception e) catch (Exception e)
{ {
m_log.ErrorFormat("{0}: ProcessTaints: Exception: {1}", LogHeader, e); m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
} }
} }
oldList.Clear(); oldList.Clear();
@ -767,6 +780,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
#region Vehicles #region Vehicles
public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
{
if (newType == Vehicle.TYPE_NONE)
{
RemoveVehiclePrim(vehic);
}
else
{
// make it so the scene will call us each tick to do vehicle things
AddVehiclePrim(vehic);
}
}
// Make so the scene will call this prim for vehicle actions each tick. // Make so the scene will call this prim for vehicle actions each tick.
// Safe to call if prim is already in the vehicle list. // Safe to call if prim is already in the vehicle list.
public void AddVehiclePrim(BSPrim vehicle) public void AddVehiclePrim(BSPrim vehicle)
@ -812,12 +839,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private struct ParameterDefn private struct ParameterDefn
{ {
public string name; public string name; // string name of the parameter
public string desc; public string desc; // a short description of what the parameter means
public float defaultValue; public float defaultValue; // default value if not specified anywhere else
public ParamUser userParam; public ParamUser userParam; // get the value from the configuration file
public ParamGet getter; public ParamGet getter; // return the current value stored for this parameter
public ParamSet setter; public ParamSet setter; // set the current value for this parameter
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
{ {
name = n; name = n;
@ -834,7 +861,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// To add a new externally referencable/settable parameter, add the paramter storage // To add a new externally referencable/settable parameter, add the paramter storage
// location somewhere in the program and make an entry in this table with the // location somewhere in the program and make an entry in this table with the
// getters and setters. // getters and setters.
// To add a new variable, it is easiest to find an existing definition and copy it. // It is easiest to find an existing definition and copy it.
// Parameter values are floats. Booleans are converted to a floating value. // Parameter values are floats. Booleans are converted to a floating value.
// //
// A ParameterDefn() takes the following parameters: // A ParameterDefn() takes the following parameters:
@ -870,7 +897,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return (float)s.m_meshLOD; }, (s) => { return (float)s.m_meshLOD; },
(s,p,l,v) => { s.m_meshLOD = (int)v; } ), (s,p,l,v) => { s.m_meshLOD = (int)v; } ),
new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
32, 32f,
(s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_sculptLOD; }, (s) => { return (float)s.m_sculptLOD; },
(s,p,l,v) => { s.m_sculptLOD = (int)v; } ), (s,p,l,v) => { s.m_sculptLOD = (int)v; } ),
@ -1027,14 +1054,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)", new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
0f, // zero to disable 0f, // zero to disable
(s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
(s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
0f, // zero to disable
(s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
(s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
ConfigurationParameters.numericTrue, ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, (s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; }, (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
(s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ), (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
@ -1101,9 +1133,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ),
new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements", new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
ConfigurationParameters.numericFalse, ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.shouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); }, (s,cf,p,v) => { s.ShouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.shouldDebugLog); }, (s) => { return s.NumericBool(s.ShouldDebugLog); },
(s,p,l,v) => { s.shouldDebugLog = s.BoolNumeric(v); } ), (s,p,l,v) => { s.ShouldDebugLog = s.BoolNumeric(v); } ),
}; };
@ -1243,7 +1275,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
List<uint> objectIDs = lIDs; List<uint> objectIDs = lIDs;
string xparm = parm.ToLower(); string xparm = parm.ToLower();
float xval = val; float xval = val;
TaintedObject(delegate() { TaintedObject("BSScene.UpdateParameterSet", delegate() {
foreach (uint lID in objectIDs) foreach (uint lID in objectIDs)
{ {
BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval); BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval);
@ -1263,7 +1295,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
uint xlocalID = localID; uint xlocalID = localID;
string xparm = parm.ToLower(); string xparm = parm.ToLower();
float xval = val; float xval = val;
TaintedObject(delegate() { TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval);
}); });
} }
@ -1289,10 +1321,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
#endregion Runtime settable parameters #endregion Runtime settable parameters
// Invoke the detailed logger and output something if it's enabled. // Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args) public void DetailLog(string msg, params Object[] args)
{ {
PhysicsLogging.Write(msg, args); PhysicsLogging.Write(msg, args);
} }
// used to fill in the LocalID when there isn't one
public const string DetailLogZero = "0000000000";
} }
} }

View File

@ -35,9 +35,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin {
// Classes to allow some type checking for the API // Classes to allow some type checking for the API
public struct BulletSim public struct BulletSim
{ {
public BulletSim(uint id, IntPtr xx) { ID = id; Ptr = xx; } public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; }
public IntPtr Ptr;
public uint ID; public uint ID;
// The scene is only in here so very low level routines have a handle to print debug/error messages
public BSScene scene;
public IntPtr Ptr;
} }
public struct BulletBody public struct BulletBody
@ -158,6 +160,7 @@ public struct ConfigurationParameters
public float avatarContactProcessingThreshold; public float avatarContactProcessingThreshold;
public float maxPersistantManifoldPoolSize; public float maxPersistantManifoldPoolSize;
public float maxCollisionAlgorithmPoolSize;
public float shouldDisableContactPoolDynamicAllocation; public float shouldDisableContactPoolDynamicAllocation;
public float shouldForceUpdateAllAabbs; public float shouldForceUpdateAllAabbs;
public float shouldRandomizeSolverOrder; public float shouldRandomizeSolverOrder;
@ -179,17 +182,18 @@ public struct ConfigurationParameters
// Values used by Bullet and BulletSim to control collisions // Values used by Bullet and BulletSim to control collisions
public enum CollisionFlags : uint public enum CollisionFlags : uint
{ {
STATIC_OBJECT = 1 << 0, CF_STATIC_OBJECT = 1 << 0,
KINEMATIC_OBJECT = 1 << 1, CF_KINEMATIC_OBJECT = 1 << 1,
NO_CONTACT_RESPONSE = 1 << 2, CF_NO_CONTACT_RESPONSE = 1 << 2,
CUSTOM_MATERIAL_CALLBACK = 1 << 3, CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
CHARACTER_OBJECT = 1 << 4, CF_CHARACTER_OBJECT = 1 << 4,
DISABLE_VISUALIZE_OBJECT = 1 << 5, CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
DISABLE_SPU_COLLISION_PROCESS = 1 << 6, CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
// Following used by BulletSim to control collisions // Following used by BulletSim to control collisions
VOLUME_DETECT_OBJECT = 1 << 10, BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
PHANTOM_OBJECT = 1 << 11, BS_VOLUME_DETECT_OBJECT = 1 << 11,
PHYSICAL_OBJECT = 1 << 12, BS_PHANTOM_OBJECT = 1 << 12,
BS_PHYSICAL_OBJECT = 1 << 13,
}; };
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@ -361,7 +365,7 @@ public static extern IntPtr GetSimHandle2(uint worldID);
public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id); public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr GetBodyHandle2(IntPtr sim, uint id); public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
// =============================================================================== // ===============================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@ -370,40 +374,43 @@ public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
int maxUpdates, IntPtr updateArray); int maxUpdates, IntPtr updateArray);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool UpdateParameter2(IntPtr sim, uint localID, String parm, float value); public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetHeightmap2(IntPtr sim, float[] heightmap); public static extern void SetHeightmap2(IntPtr world, float[] heightmap);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void Shutdown2(IntPtr sim); public static extern void Shutdown2(IntPtr sim);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern int PhysicsStep2(IntPtr sim, float timeStep, int maxSubSteps, float fixedTimeStep, public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
out int updatedEntityCount, out int updatedEntityCount,
out IntPtr updatedEntitiesPtr, out IntPtr updatedEntitiesPtr,
out int collidersCount, out int collidersCount,
out IntPtr collidersPtr); out IntPtr collidersPtr);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool PushUpdate2(IntPtr obj);
/* /*
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateMesh2(IntPtr sim, int indicesCount, int* indices, int verticesCount, float* vertices ); public static extern IntPtr CreateMesh2(IntPtr world, int indicesCount, int* indices, int verticesCount, float* vertices );
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool BuildHull2(IntPtr sim, IntPtr mesh); public static extern bool BuildHull2(IntPtr world, IntPtr mesh);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ReleaseHull2(IntPtr sim, IntPtr mesh); public static extern bool ReleaseHull2(IntPtr world, IntPtr mesh);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyMesh2(IntPtr sim, IntPtr mesh); public static extern bool DestroyMesh2(IntPtr world, IntPtr mesh);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateObject2(IntPtr sim, ShapeData shapeData); public static extern IntPtr CreateObject2(IntPtr world, ShapeData shapeData);
*/ */
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateConstraint2(IntPtr sim, IntPtr obj1, IntPtr obj2, public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
Vector3 frame1loc, Quaternion frame1rot, Vector3 frame1loc, Quaternion frame1rot,
Vector3 frame2loc, Quaternion frame2rot, Vector3 frame2loc, Quaternion frame2rot,
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
@ -427,7 +434,13 @@ public static extern bool CalculateTransforms2(IntPtr constrain);
public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyConstraint2(IntPtr sim, IntPtr constrain); public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetPosition2(IntPtr obj); public static extern Vector3 GetPosition2(IntPtr obj);
@ -447,6 +460,9 @@ public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocit
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectForce2(IntPtr obj, Vector3 force); public static extern bool SetObjectForce2(IntPtr obj, Vector3 force);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool AddObjectForce2(IntPtr obj, Vector3 force);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val); public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val);
@ -478,13 +494,16 @@ public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val);
public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang); public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr SetCollisionFlags2(IntPtr obj, uint flags); public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr AddToCollisionFlags2(IntPtr obj, uint flags); public static extern IntPtr SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, uint flags); public static extern IntPtr AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia); public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
@ -504,12 +523,6 @@ public static extern bool SetMargin2(IntPtr obj, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyObject2(IntPtr world, uint id); public static extern bool DestroyObject2(IntPtr world, uint id);

View File

@ -3346,7 +3346,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
if (attachmentsModule != null) if (attachmentsModule != null)
return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true); return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, false);
else else
return false; return false;
} }
@ -5375,12 +5375,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{ {
return 0; return 0;
} }
// Vectors & Rotations always return zero in SL, but
// keys don't always return zero, it seems to be a bit complex.
else if (src.Data[index] is LSL_Vector ||
src.Data[index] is LSL_Rotation)
{
return 0;
}
try try
{ {
if (src.Data[index] is LSL_Integer) if (src.Data[index] is LSL_Integer)
return (LSL_Integer) src.Data[index]; return (LSL_Integer)src.Data[index];
else if (src.Data[index] is LSL_Float) else if (src.Data[index] is LSL_Float)
return Convert.ToInt32(((LSL_Float) src.Data[index]).value); return Convert.ToInt32(((LSL_Float)src.Data[index]).value);
return new LSL_Integer(src.Data[index].ToString()); return new LSL_Integer(src.Data[index].ToString());
} }
catch (FormatException) catch (FormatException)
@ -5400,12 +5409,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{ {
return 0.0; return 0.0;
} }
// Vectors & Rotations always return zero in SL
else if (src.Data[index] is LSL_Vector ||
src.Data[index] is LSL_Rotation)
{
return 0;
}
// valid keys seem to get parsed as integers then converted to floats
else
{
UUID uuidt;
if (src.Data[index] is LSL_Key && UUID.TryParse(src.Data[index].ToString(), out uuidt))
{
return Convert.ToDouble(new LSL_Integer(src.Data[index].ToString()).value);
}
}
try try
{ {
if (src.Data[index] is LSL_Integer) if (src.Data[index] is LSL_Integer)
return Convert.ToDouble(((LSL_Integer) src.Data[index]).value); return Convert.ToDouble(((LSL_Integer)src.Data[index]).value);
else if (src.Data[index] is LSL_Float) else if (src.Data[index] is LSL_Float)
return Convert.ToDouble(((LSL_Float) src.Data[index]).value); return Convert.ToDouble(((LSL_Float)src.Data[index]).value);
else if (src.Data[index] is LSL_String) else if (src.Data[index] is LSL_String)
{ {
string str = ((LSL_String) src.Data[index]).m_string; string str = ((LSL_String) src.Data[index]).m_string;
@ -5443,17 +5468,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return src.Data[index].ToString(); return src.Data[index].ToString();
} }
public LSL_String llList2Key(LSL_List src, int index) public LSL_Key llList2Key(LSL_List src, int index)
{ {
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
if (index < 0) if (index < 0)
{ {
index = src.Length + index; index = src.Length + index;
} }
if (index >= src.Length || index < 0) if (index >= src.Length || index < 0)
{ {
return ""; return "";
} }
// SL spits out an empty string for types other than key & string
// At the time of patching, LSL_Key is currently LSL_String,
// so the OR check may be a little redundant, but it's being done
// for completion and should LSL_Key ever be implemented
// as it's own struct
else if (!(src.Data[index] is LSL_String ||
src.Data[index] is LSL_Key))
{
return "";
}
return src.Data[index].ToString(); return src.Data[index].ToString();
} }
@ -5472,6 +5510,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{ {
return (LSL_Vector)src.Data[index]; return (LSL_Vector)src.Data[index];
} }
// SL spits always out ZERO_VECTOR for anything other than
// strings or vectors. Although keys always return ZERO_VECTOR,
// it is currently difficult to make the distinction between
// a string, a key as string and a string that by coincidence
// is a string, so we're going to leave that up to the
// LSL_Vector constructor.
else if (!(src.Data[index] is LSL_String ||
src.Data[index] is LSL_Vector))
{
return new LSL_Vector(0, 0, 0);
}
else else
{ {
return new LSL_Vector(src.Data[index].ToString()); return new LSL_Vector(src.Data[index].ToString());
@ -5489,7 +5539,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{ {
return new LSL_Rotation(0, 0, 0, 1); return new LSL_Rotation(0, 0, 0, 1);
} }
if (src.Data[index].GetType() == typeof(LSL_Rotation))
// SL spits always out ZERO_ROTATION for anything other than
// strings or vectors. Although keys always return ZERO_ROTATION,
// it is currently difficult to make the distinction between
// a string, a key as string and a string that by coincidence
// is a string, so we're going to leave that up to the
// LSL_Rotation constructor.
else if (!(src.Data[index] is LSL_String ||
src.Data[index] is LSL_Rotation))
{
return new LSL_Rotation(0, 0, 0, 1);
}
else if (src.Data[index].GetType() == typeof(LSL_Rotation))
{ {
return (LSL_Rotation)src.Data[index]; return (LSL_Rotation)src.Data[index];
} }

View File

@ -182,6 +182,7 @@ namespace OpenSim.Services.Interfaces
List<AvatarAttachment> attachments = appearance.GetAttachments(); List<AvatarAttachment> attachments = appearance.GetAttachments();
foreach (AvatarAttachment attach in attachments) foreach (AvatarAttachment attach in attachments)
{ {
if (attach.ItemID != UUID.Zero)
Data["_ap_" + attach.AttachPoint] = attach.ItemID.ToString(); Data["_ap_" + attach.AttachPoint] = attach.ItemID.ToString();
} }
} }

View File

@ -181,11 +181,6 @@
; Objects will always be considered for persistance in the next sweep if the first change occurred this number of seconds ago ; Objects will always be considered for persistance in the next sweep if the first change occurred this number of seconds ago
MaximumTimeBeforePersistenceConsidered = 600 MaximumTimeBeforePersistenceConsidered = 600
; Experimental setting to resend appearance updates every 60 seconds.
; These packets are small and this can help with grey avatar syndrome.
; Default is false
SendPeriodicAppearanceUpdates = false
; ## ; ##
; ## PHYSICS ; ## PHYSICS
; ## ; ##
@ -341,27 +336,12 @@
; OpenJPEG if false ; OpenJPEG if false
; UseCSJ2K = true ; UseCSJ2K = true
; Use "Trash" folder for items deleted from the scene ; Use "Trash" folder for items deleted from the scene
; When set to True (the default) items deleted from the scene will be ; When set to True (the default) items deleted from the scene will be
; stored in the user's trash or lost and found folder. When set to ; stored in the user's trash or lost and found folder. When set to
; False items will be removed from the scene permanently ; False items will be removed from the scene permanently
UseTrashOnDelete = True UseTrashOnDelete = True
; Persist avatar baked textures
; Persisting baked textures can speed up login and region border
; crossings especially with large numbers of users, though it
; will store potentially large numbers of textures in your asset
; database
PersistBakedTextures = false
; Control the delay before appearance is sent to other avatars and
; saved in the avatar service. Attempts to limit the impact caused
; by the very chatty dialog that sets appearance when an avatar
; logs in or teleports into a region; values are in seconds
DelayBeforeAppearanceSave = 5
DelayBeforeAppearanceSend = 2
[RegionReady] [RegionReady]
; Enable this module to get notified once all items and scripts in the region have been completely loaded and compiled ; Enable this module to get notified once all items and scripts in the region have been completely loaded and compiled
@ -671,6 +651,28 @@
CoalesceMultipleObjectsToInventory = true CoalesceMultipleObjectsToInventory = true
[Appearance]
; Persist avatar baked textures
; Persisting baked textures can speed up login and region border
; crossings especially with large numbers of users, though it
; will store potentially large numbers of textures in your asset
; database
PersistBakedTextures = false
; Control the delay before appearance is sent to other avatars and
; saved in the avatar service. Attempts to limit the impact caused
; by the very chatty dialog that sets appearance when an avatar
; logs in or teleports into a region; values are in seconds
DelayBeforeAppearanceSave = 5
DelayBeforeAppearanceSend = 2
; If true, avatar appearance information is resent to other avatars in the simulator every 60 seconds.
; This may help with some situations where avatars are persistently grey, though it will not help
; in other situations (e.g. appearance baking failures where the avatar only appears as a cloud to others).
; This setting is experimental.
ResendAppearanceUpdates = false
[Attachments] [Attachments]
; Controls whether avatar attachments are enabled. ; Controls whether avatar attachments are enabled.
; Defaults to true - only set to false for debugging purposes ; Defaults to true - only set to false for debugging purposes
@ -937,7 +939,7 @@
FixedTimeStep = .01667 FixedTimeStep = .01667
MaxCollisionsPerFrame = 2048 MaxCollisionsPerFrame = 2048
MaxUpdatesPerFrame = 2048 MaxUpdatesPerFrame = 8192
[RemoteAdmin] [RemoteAdmin]
enabled = false enabled = false

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.