Merge branch 'master' into connector_plugin

0.7.5-pf-bulletsim
BlueWall 2012-12-07 15:36:43 -05:00
commit 0b455d2882
54 changed files with 2186 additions and 807 deletions

View File

@ -246,6 +246,11 @@ namespace OpenSim.Capabilities.Handlers
} }
else else
{ {
// Handle the case where no second range value was given. This is equivalent to requesting
// the rest of the entity.
if (end == -1)
end = int.MaxValue;
end = Utils.Clamp(end, 0, texture.Data.Length - 1); end = Utils.Clamp(end, 0, texture.Data.Length - 1);
start = Utils.Clamp(start, 0, end); start = Utils.Clamp(start, 0, end);
int len = end - start + 1; int len = end - start + 1;
@ -299,16 +304,44 @@ namespace OpenSim.Capabilities.Handlers
// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); // texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
} }
/// <summary>
/// Parse a range header.
/// </summary>
/// <remarks>
/// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
/// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
/// Where there is no value, -1 is returned.
/// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
/// for start.</remarks>
/// <returns></returns>
/// <param name='header'></param>
/// <param name='start'>Start of the range. Undefined if this was not a number.</param>
/// <param name='end'>End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number.</param>
private bool TryParseRange(string header, out int start, out int end) private bool TryParseRange(string header, out int start, out int end)
{ {
start = end = 0;
if (header.StartsWith("bytes=")) if (header.StartsWith("bytes="))
{ {
string[] rangeValues = header.Substring(6).Split('-'); string[] rangeValues = header.Substring(6).Split('-');
if (rangeValues.Length == 2) if (rangeValues.Length == 2)
{ {
if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) if (!Int32.TryParse(rangeValues[0], out start))
return false;
string rawEnd = rangeValues[1];
if (rawEnd == "")
{
end = -1;
return true; return true;
} }
else if (Int32.TryParse(rawEnd, out end))
{
return true;
}
}
} }
start = end = 0; start = end = 0;

View File

@ -44,9 +44,15 @@ namespace OpenSim.Data.Tests
/// <summary>This is a base class for testing any Data service for any DBMS. /// <summary>This is a base class for testing any Data service for any DBMS.
/// Requires NUnit 2.5 or better (to support the generics). /// Requires NUnit 2.5 or better (to support the generics).
/// </summary> /// </summary>
/// <remarks>
/// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with
/// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
/// and similar on EstateTests, InventoryTests and RegionTests.
/// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts.
/// </remarks>
/// <typeparam name="TConn"></typeparam> /// <typeparam name="TConn"></typeparam>
/// <typeparam name="TService"></typeparam> /// <typeparam name="TService"></typeparam>
public class BasicDataServiceTest<TConn, TService> : OpenSimTestCase public class BasicDataServiceTest<TConn, TService>
where TConn : DbConnection, new() where TConn : DbConnection, new()
where TService : class, new() where TService : class, new()
{ {

View File

@ -0,0 +1,508 @@
/*
* Copyright (c) 2008, openmetaverse.org, http://opensimulator.org/
* All rights reserved.
*
* - 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.
* - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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.Threading;
using System.Collections.Generic;
namespace OpenSim.Framework
{
/// <summary>
/// A double dictionary that is thread abort safe.
/// </summary>
/// <remarks>
/// This adapts OpenMetaverse.DoubleDictionary to be thread-abort safe by acquiring ReaderWriterLockSlim within
/// a finally section (which can't be interrupted by Thread.Abort()).
/// </remarks>
public class DoubleDictionaryThreadAbortSafe<TKey1, TKey2, TValue>
{
Dictionary<TKey1, TValue> Dictionary1;
Dictionary<TKey2, TValue> Dictionary2;
ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
public DoubleDictionaryThreadAbortSafe()
{
Dictionary1 = new Dictionary<TKey1,TValue>();
Dictionary2 = new Dictionary<TKey2,TValue>();
}
public DoubleDictionaryThreadAbortSafe(int capacity)
{
Dictionary1 = new Dictionary<TKey1, TValue>(capacity);
Dictionary2 = new Dictionary<TKey2, TValue>(capacity);
}
public void Add(TKey1 key1, TKey2 key2, TValue value)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
if (Dictionary1.ContainsKey(key1))
{
if (!Dictionary2.ContainsKey(key2))
throw new ArgumentException("key1 exists in the dictionary but not key2");
}
else if (Dictionary2.ContainsKey(key2))
{
if (!Dictionary1.ContainsKey(key1))
throw new ArgumentException("key2 exists in the dictionary but not key1");
}
Dictionary1[key1] = value;
Dictionary2[key2] = value;
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
}
public bool Remove(TKey1 key1, TKey2 key2)
{
bool success;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
Dictionary1.Remove(key1);
success = Dictionary2.Remove(key2);
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
return success;
}
public bool Remove(TKey1 key1)
{
bool found = false;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
// This is an O(n) operation!
TValue value;
if (Dictionary1.TryGetValue(key1, out value))
{
foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
{
if (kvp.Value.Equals(value))
{
Dictionary1.Remove(key1);
Dictionary2.Remove(kvp.Key);
found = true;
break;
}
}
}
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
return found;
}
public bool Remove(TKey2 key2)
{
bool found = false;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
// This is an O(n) operation!
TValue value;
if (Dictionary2.TryGetValue(key2, out value))
{
foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
{
if (kvp.Value.Equals(value))
{
Dictionary2.Remove(key2);
Dictionary1.Remove(kvp.Key);
found = true;
break;
}
}
}
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
return found;
}
public void Clear()
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterWriteLock();
gotLock = true;
}
Dictionary1.Clear();
Dictionary2.Clear();
}
finally
{
if (gotLock)
rwLock.ExitWriteLock();
}
}
public int Count
{
get { return Dictionary1.Count; }
}
public bool ContainsKey(TKey1 key)
{
return Dictionary1.ContainsKey(key);
}
public bool ContainsKey(TKey2 key)
{
return Dictionary2.ContainsKey(key);
}
public bool TryGetValue(TKey1 key, out TValue value)
{
bool success;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
success = Dictionary1.TryGetValue(key, out value);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
return success;
}
public bool TryGetValue(TKey2 key, out TValue value)
{
bool success;
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
success = Dictionary2.TryGetValue(key, out value);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
return success;
}
public void ForEach(Action<TValue> action)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (TValue value in Dictionary1.Values)
action(value);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
}
public void ForEach(Action<KeyValuePair<TKey1, TValue>> action)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (KeyValuePair<TKey1, TValue> entry in Dictionary1)
action(entry);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
}
public void ForEach(Action<KeyValuePair<TKey2, TValue>> action)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (KeyValuePair<TKey2, TValue> entry in Dictionary2)
action(entry);
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
}
public TValue FindValue(Predicate<TValue> predicate)
{
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (TValue value in Dictionary1.Values)
{
if (predicate(value))
return value;
}
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
return default(TValue);
}
public IList<TValue> FindAll(Predicate<TValue> predicate)
{
IList<TValue> list = new List<TValue>();
bool gotLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterReadLock();
gotLock = true;
}
foreach (TValue value in Dictionary1.Values)
{
if (predicate(value))
list.Add(value);
}
}
finally
{
if (gotLock)
rwLock.ExitReadLock();
}
return list;
}
public int RemoveAll(Predicate<TValue> predicate)
{
IList<TKey1> list = new List<TKey1>();
bool gotUpgradeableLock = false;
try
{
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
try {}
finally
{
rwLock.EnterUpgradeableReadLock();
gotUpgradeableLock = true;
}
foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
{
if (predicate(kvp.Value))
list.Add(kvp.Key);
}
IList<TKey2> list2 = new List<TKey2>(list.Count);
foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
{
if (predicate(kvp.Value))
list2.Add(kvp.Key);
}
bool gotWriteLock = false;
try
{
try {}
finally
{
rwLock.EnterUpgradeableReadLock();
gotWriteLock = true;
}
for (int i = 0; i < list.Count; i++)
Dictionary1.Remove(list[i]);
for (int i = 0; i < list2.Count; i++)
Dictionary2.Remove(list2[i]);
}
finally
{
if (gotWriteLock)
rwLock.ExitWriteLock();
}
}
finally
{
if (gotUpgradeableLock)
rwLock.ExitUpgradeableReadLock();
}
return list.Count;
}
}
}

View File

@ -192,18 +192,7 @@ namespace OpenSim.Framework
public PrimitiveBaseShape() public PrimitiveBaseShape()
{ {
PCode = (byte) PCodeEnum.Primitive;
ExtraParams = new byte[1];
m_textureEntry = DEFAULT_TEXTURE;
}
public PrimitiveBaseShape(bool noShape)
{
if (noShape)
return;
PCode = (byte)PCodeEnum.Primitive; PCode = (byte)PCodeEnum.Primitive;
ExtraParams = new byte[1];
m_textureEntry = DEFAULT_TEXTURE; m_textureEntry = DEFAULT_TEXTURE;
} }
@ -216,7 +205,6 @@ namespace OpenSim.Framework
// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID); // m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID);
PCode = (byte)prim.PrimData.PCode; PCode = (byte)prim.PrimData.PCode;
ExtraParams = new byte[1];
State = prim.PrimData.State; State = prim.PrimData.State;
PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
@ -248,7 +236,10 @@ namespace OpenSim.Framework
SculptTexture = prim.Sculpt.SculptTexture; SculptTexture = prim.Sculpt.SculptTexture;
SculptType = (byte)prim.Sculpt.Type; SculptType = (byte)prim.Sculpt.Type;
} }
else SculptType = (byte)OpenMetaverse.SculptType.None; else
{
SculptType = (byte)OpenMetaverse.SculptType.None;
}
} }
[XmlIgnore] [XmlIgnore]
@ -340,9 +331,9 @@ namespace OpenSim.Framework
_scale = new Vector3(side, side, side); _scale = new Vector3(side, side, side);
} }
public void SetHeigth(float heigth) public void SetHeigth(float height)
{ {
_scale.Z = heigth; _scale.Z = height;
} }
public void SetRadius(float radius) public void SetRadius(float radius)

View File

@ -436,7 +436,7 @@ namespace OpenSim.Framework.Servers.HttpServer
// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); // reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
//m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); Culture.SetCurrentCulture();
// // This is the REST agent interface. We require an agent to properly identify // // This is the REST agent interface. We require an agent to properly identify
// // itself. If the REST handler recognizes the prefix it will attempt to // // itself. If the REST handler recognizes the prefix it will attempt to

View File

@ -304,9 +304,5 @@ namespace OpenSim.Framework.Tests
Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US"); Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US");
} }
} }
} }

View File

@ -53,8 +53,10 @@ namespace OpenSim.Region.CoreModules.Asset.Tests
protected FlotsamAssetCache m_cache; protected FlotsamAssetCache m_cache;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
IConfigSource config = new IniConfigSource(); IConfigSource config = new IniConfigSource();
config.AddConfig("Modules"); config.AddConfig("Modules");

View File

@ -81,8 +81,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
} }
if (groupsConfig.GetString("Module", "Default") != "Default") if (groupsConfig.GetString("Module", "Default") != "Default")
{
m_Enabled = false;
return; return;
} }
}
} }

View File

@ -146,7 +146,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
if (sp != null && !sp.IsChildAgent) if (sp != null && !sp.IsChildAgent)
{ {
// Local message // Local message
m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID);
sp.ControllingClient.SendInstantMessage(im); sp.ControllingClient.SendInstantMessage(im);
@ -159,14 +159,14 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
// try child avatar second // try child avatar second
foreach (Scene scene in m_Scenes) foreach (Scene scene in m_Scenes)
{ {
m_log.DebugFormat( // m_log.DebugFormat(
"[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); // "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
ScenePresence sp = scene.GetScenePresence(toAgentID); ScenePresence sp = scene.GetScenePresence(toAgentID);
if (sp != null) if (sp != null)
{ {
// Local message // Local message
m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID);
sp.ControllingClient.SendInstantMessage(im); sp.ControllingClient.SendInstantMessage(im);
@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
} }
} }
m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
SendGridInstantMessageViaXMLRPC(im, result); SendGridInstantMessageViaXMLRPC(im, result);
} }

View File

@ -186,8 +186,11 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
foreach (GridInstantMessage im in msglist) foreach (GridInstantMessage im in msglist)
{ {
// client.SendInstantMessage(im); if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
// send it directly or else the item will be given twice
client.SendInstantMessage(im);
else
{
// Send through scene event manager so all modules get a chance // Send through scene event manager so all modules get a chance
// to look at this message before it gets delivered. // to look at this message before it gets delivered.
// //
@ -200,6 +203,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
} }
} }
} }
}
private void UndeliveredMessage(GridInstantMessage im) private void UndeliveredMessage(GridInstantMessage im)
{ {
@ -215,7 +219,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
if (!m_ForwardOfflineGroupMessages) if (!m_ForwardOfflineGroupMessages)
{ {
if (im.dialog == (byte)InstantMessageDialog.GroupNotice || if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
im.dialog != (byte)InstantMessageDialog.GroupInvitation) im.dialog == (byte)InstantMessageDialog.GroupInvitation)
return; return;
} }

View File

@ -57,8 +57,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
protected TestClient m_tc; protected TestClient m_tc;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
m_iam = new BasicInventoryAccessModule(); m_iam = new BasicInventoryAccessModule();
IConfigSource config = new IniConfigSource(); IConfigSource config = new IniConfigSource();

View File

@ -46,8 +46,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests
public class PresenceConnectorsTests : OpenSimTestCase public class PresenceConnectorsTests : OpenSimTestCase
{ {
LocalPresenceServicesConnector m_LocalConnector; LocalPresenceServicesConnector m_LocalConnector;
private void SetUp()
public override void SetUp()
{ {
base.SetUp();
IConfigSource config = new IniConfigSource(); IConfigSource config = new IniConfigSource();
config.AddConfig("Modules"); config.AddConfig("Modules");
config.AddConfig("PresenceService"); config.AddConfig("PresenceService");

View File

@ -60,8 +60,10 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests
protected ILandObject m_lo2; protected ILandObject m_lo2;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
m_pcm = new PrimCountModule(); m_pcm = new PrimCountModule();
LandManagementModule lmm = new LandManagementModule(); LandManagementModule lmm = new LandManagementModule();
m_scene = new SceneHelpers().SetupScene(); m_scene = new SceneHelpers().SetupScene();

View File

@ -50,8 +50,10 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests
protected MoapModule m_module; protected MoapModule m_module;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
m_module = new MoapModule(); m_module = new MoapModule();
m_scene = new SceneHelpers().SetupScene(); m_scene = new SceneHelpers().SetupScene();
SceneHelpers.SetupSceneModules(m_scene, m_module); SceneHelpers.SetupSceneModules(m_scene, m_module);

View File

@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4) if (mainParams.Count < 4)
{ {
m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); //m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
m_console.OutputFormat("Usage: show part id <UUID-or-localID>");
return; return;
} }
@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 5) if (mainParams.Count < 5)
{ {
//m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>");
m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
return; return;
} }
@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4) if (mainParams.Count < 4)
{ {
m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); m_console.OutputFormat("Usage: show part name [--regex] <name>");
//m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
return; return;
} }
@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
cdl.AddRow("Link number", sop.LinkNum); cdl.AddRow("Link number", sop.LinkNum);
cdl.AddRow("Flags", sop.Flags); cdl.AddRow("Flags", sop.Flags);
if (showFull)
{
PrimitiveBaseShape s = sop.Shape;
cdl.AddRow("FlexiDrag", s.FlexiDrag);
cdl.AddRow("FlexiEntry", s.FlexiEntry);
cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ));
cdl.AddRow("FlexiGravity", s.FlexiGravity);
cdl.AddRow("FlexiSoftness", s.FlexiSoftness);
cdl.AddRow("HollowShape", s.HollowShape);
cdl.AddRow(
"LightColor",
string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
cdl.AddRow("FlexiDrag", s.LightCutoff);
cdl.AddRow("FlexiDrag", s.LightEntry);
cdl.AddRow("FlexiDrag", s.LightFalloff);
cdl.AddRow("FlexiDrag", s.LightIntensity);
cdl.AddRow("FlexiDrag", s.LightRadius);
cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
cdl.AddRow("PathBegin", s.PathBegin);
cdl.AddRow("PathEnd", s.PathEnd);
cdl.AddRow("PathCurve", s.PathCurve);
cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset);
cdl.AddRow("PathRevolutions", s.PathRevolutions);
cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY));
cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY));
cdl.AddRow("FlexiDrag", s.PathSkew);
cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY));
cdl.AddRow("PathTwist", s.PathTwist);
cdl.AddRow("PathTwistBegin", s.PathTwistBegin);
cdl.AddRow("PCode", s.PCode);
cdl.AddRow("ProfileBegin", s.ProfileBegin);
cdl.AddRow("ProfileEnd", s.ProfileEnd);
cdl.AddRow("ProfileHollow", s.ProfileHollow);
cdl.AddRow("ProfileShape", s.ProfileShape);
cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance);
cdl.AddRow("ProjectionEntry", s.ProjectionEntry);
cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
cdl.AddRow("Scale", s.Scale);
cdl.AddRow(
"SculptData",
string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a"));
cdl.AddRow("SculptEntry", s.SculptEntry);
cdl.AddRow("SculptTexture", s.SculptTexture);
cdl.AddRow("SculptType", s.SculptType);
cdl.AddRow("State", s.State);
// TODO, unpack and display texture entries
//cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
}
object itemsOutput; object itemsOutput;
if (showFull) if (showFull)
{ {
@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
itemsOutput = sop.Inventory.Count; itemsOutput = sop.Inventory.Count;
} }
cdl.AddRow("Items", itemsOutput); cdl.AddRow("Items", itemsOutput);
return sb.Append(cdl.ToString()); return sb.Append(cdl.ToString());

View File

@ -34,5 +34,6 @@ namespace OpenSim.Region.Framework.Interfaces
void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url); void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url);
void ScriptRemoved(UUID itemID); void ScriptRemoved(UUID itemID);
void ObjectRemoved(UUID objectID); void ObjectRemoved(UUID objectID);
void UnRegisterReceiver(string channelID, UUID itemID);
} }
} }

View File

@ -31,6 +31,7 @@ using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using log4net; using log4net;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework;
namespace OpenSim.Region.Framework.Scenes namespace OpenSim.Region.Framework.Scenes
{ {
@ -38,7 +39,8 @@ namespace OpenSim.Region.Framework.Scenes
{ {
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private readonly DoubleDictionary<UUID, uint, EntityBase> m_entities = new DoubleDictionary<UUID, uint, EntityBase>(); private readonly DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase> m_entities
= new DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase>();
public int Count public int Count
{ {

View File

@ -5638,10 +5638,17 @@ namespace OpenSim.Region.Framework.Scenes
return m_SpawnPoint - 1; return m_SpawnPoint - 1;
} }
// Wrappers to get physics modules retrieve assets. Has to be done this way /// <summary>
// because we can't assign the asset service to physics directly - at the /// Wrappers to get physics modules retrieve assets.
// time physics are instantiated it's not registered but it will be by /// </summary>
// the time the first prim exists. /// <remarks>
/// Has to be done this way
/// because we can't assign the asset service to physics directly - at the
/// time physics are instantiated it's not registered but it will be by
/// the time the first prim exists.
/// </remarks>
/// <param name="assetID"></param>
/// <param name="callback"></param>
public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
{ {
AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);

View File

@ -46,6 +46,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
{ {
public class XmlRpcInfo public class XmlRpcInfo
{ {
public UUID item;
public UUID channel; public UUID channel;
public string uri; public string uri;
} }
@ -88,6 +89,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
return; return;
scene.RegisterModuleInterface<IXmlRpcRouter>(this); scene.RegisterModuleInterface<IXmlRpcRouter>(this);
IScriptModule scriptEngine = scene.RequestModuleInterface<IScriptModule>();
if ( scriptEngine != null )
{
scriptEngine.OnScriptRemoved += this.ScriptRemoved;
scriptEngine.OnObjectRemoved += this.ObjectRemoved;
}
} }
public void RegionLoaded(Scene scene) public void RegionLoaded(Scene scene)
@ -120,11 +129,16 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri)
{ {
if (!m_Channels.ContainsKey(itemID)) if (!m_Enabled)
{ return;
m_log.InfoFormat("[XMLRPC GRID ROUTER]: New receiver Obj: {0} Ch: {1} ID: {2} URI: {3}",
objectID.ToString(), channel.ToString(), itemID.ToString(), uri);
XmlRpcInfo info = new XmlRpcInfo(); XmlRpcInfo info = new XmlRpcInfo();
info.channel = channel; info.channel = channel;
info.uri = uri; info.uri = uri;
info.item = itemID;
bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>(
"POST", m_ServerURI+"/RegisterChannel/", info); "POST", m_ServerURI+"/RegisterChannel/", info);
@ -135,7 +149,16 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
} }
m_Channels[itemID] = channel; m_Channels[itemID] = channel;
} }
public void UnRegisterReceiver(string channelID, UUID itemID)
{
if (!m_Enabled)
return;
RemoveChannel(itemID);
} }
public void ScriptRemoved(UUID itemID) public void ScriptRemoved(UUID itemID)
@ -143,10 +166,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
if (!m_Enabled) if (!m_Enabled)
return; return;
if (m_Channels.ContainsKey(itemID)) RemoveChannel(itemID);
}
public void ObjectRemoved(UUID objectID)
{ {
bool success = SynchronousRestObjectRequester.MakeRequest<UUID, bool>( // m_log.InfoFormat("[XMLRPC GRID ROUTER]: Object Removed {0}",objectID.ToString());
"POST", m_ServerURI+"/RemoveChannel/", m_Channels[itemID]); }
private bool RemoveChannel(UUID itemID)
{
if(!m_Channels.ContainsKey(itemID))
{
m_log.InfoFormat("[XMLRPC GRID ROUTER]: Attempted to unregister non-existing Item: {0}", itemID.ToString());
return false;
}
XmlRpcInfo info = new XmlRpcInfo();
info.channel = m_Channels[itemID];
info.item = itemID;
info.uri = "http://0.0.0.0:00";
if (info != null)
{
bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>(
"POST", m_ServerURI+"/RemoveChannel/", info);
if (!success) if (!success)
{ {
@ -154,11 +200,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
} }
m_Channels.Remove(itemID); m_Channels.Remove(itemID);
return true;
} }
} return false;
public void ObjectRemoved(UUID objectID)
{
} }
} }
} }

View File

@ -101,12 +101,18 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule
scriptEngine.PostScriptEvent(itemID, "xmlrpc_uri", new Object[] {uri}); scriptEngine.PostScriptEvent(itemID, "xmlrpc_uri", new Object[] {uri});
} }
public void UnRegisterReceiver(string channelID, UUID itemID)
{
}
public void ScriptRemoved(UUID itemID) public void ScriptRemoved(UUID itemID)
{ {
System.Console.WriteLine("TEST Script Removed!");
} }
public void ObjectRemoved(UUID objectID) public void ObjectRemoved(UUID objectID)
{ {
System.Console.WriteLine("TEST Obj Removed!");
} }
} }
} }

View File

@ -165,8 +165,8 @@ public sealed class BSCharacter : BSPhysObject
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
// Do this after the object has been added to the world // Do this after the object has been added to the world
BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr,
(uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarGroup,
(uint)CollisionFilterGroups.AvatarMask); (uint)CollisionFilterGroups.AvatarMask);
} }
@ -307,7 +307,7 @@ public sealed class BSCharacter : BSPhysObject
} }
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
{ {
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
if (Position.Z < waterHeight) if (Position.Z < waterHeight)
{ {
_position.Z = waterHeight; _position.Z = waterHeight;

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
@ -53,24 +53,19 @@ public struct MaterialAttributes
// Names must be in the order of the above enum. // Names must be in the order of the above enum.
public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
"Flesh", "Plastic", "Rubber", "Light", "Avatar" }; "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
public static string[] MaterialAttribs = { "Density", "Friction", "Restitution", public static string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
"ccdMotionThreshold", "ccdSweptSphereRadius" };
public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS) public MaterialAttributes(string t, float d, float f, float r)
{ {
type = t; type = t;
density = d; density = d;
friction = f; friction = f;
restitution = r; restitution = r;
ccdMotionThreshold = ccdM;
ccdSweptSphereRadius = ccdS;
} }
public string type; public string type;
public float density; public float density;
public float friction; public float friction;
public float restitution; public float restitution;
public float ccdMotionThreshold;
public float ccdSweptSphereRadius;
} }
public static class BSMaterials public static class BSMaterials
@ -86,50 +81,49 @@ public static class BSMaterials
// This is where all the default material attributes are defined. // This is where all the default material attributes are defined.
public static void InitializeFromDefaults(ConfigurationParameters parms) public static void InitializeFromDefaults(ConfigurationParameters parms)
{ {
// Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
// public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
// "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; // "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
float dFriction = parms.defaultFriction; float dFriction = parms.defaultFriction;
float dRestitution = parms.defaultRestitution; float dRestitution = parms.defaultRestitution;
float dDensity = parms.defaultDensity; float dDensity = parms.defaultDensity;
float dCcdM = parms.ccdMotionThreshold;
float dCcdS = parms.ccdSweptSphereRadius;
Attributes[(int)MaterialAttributes.Material.Stone] = Attributes[(int)MaterialAttributes.Material.Stone] =
new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
Attributes[(int)MaterialAttributes.Material.Metal] = Attributes[(int)MaterialAttributes.Material.Metal] =
new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
Attributes[(int)MaterialAttributes.Material.Glass] = Attributes[(int)MaterialAttributes.Material.Glass] =
new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
Attributes[(int)MaterialAttributes.Material.Wood] = Attributes[(int)MaterialAttributes.Material.Wood] =
new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
Attributes[(int)MaterialAttributes.Material.Flesh] = Attributes[(int)MaterialAttributes.Material.Flesh] =
new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
Attributes[(int)MaterialAttributes.Material.Plastic] = Attributes[(int)MaterialAttributes.Material.Plastic] =
new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
Attributes[(int)MaterialAttributes.Material.Rubber] = Attributes[(int)MaterialAttributes.Material.Rubber] =
new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
Attributes[(int)MaterialAttributes.Material.Light] = Attributes[(int)MaterialAttributes.Material.Light] =
new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("light",dDensity, dFriction, dRestitution);
Attributes[(int)MaterialAttributes.Material.Avatar] = Attributes[(int)MaterialAttributes.Material.Avatar] =
new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("avatar",60f, 0.2f, 0f);
Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f);
Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f);
Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f);
Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f);
Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f);
Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f);
Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f);
} }
// Under the [BulletSim] section, one can change the individual material // Under the [BulletSim] section, one can change the individual material

View File

@ -1,3 +1,30 @@
/*
* 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@ -7,6 +34,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public abstract class BSMotor public abstract class BSMotor
{ {
// Timescales and other things can be turned off by setting them to 'infinite'.
public const float Infinite = 12345f;
public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
public BSMotor(string useName) public BSMotor(string useName)
{ {
UseName = useName; UseName = useName;
@ -15,7 +46,9 @@ public abstract class BSMotor
public virtual void Reset() { } public virtual void Reset() { }
public virtual void Zero() { } public virtual void Zero() { }
// A name passed at motor creation for easily identifyable debugging messages.
public string UseName { get; private set; } public string UseName { get; private set; }
// Used only for outputting debug information. Might not be set so check for null. // Used only for outputting debug information. Might not be set so check for null.
public BSScene PhysicsScene { get; set; } public BSScene PhysicsScene { get; set; }
protected void MDetailLog(string msg, params Object[] parms) protected void MDetailLog(string msg, params Object[] parms)
@ -30,10 +63,23 @@ public abstract class BSMotor
} }
} }
// Can all the incremental stepping be replaced with motor classes? // Can all the incremental stepping be replaced with motor classes?
// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
// The TargetValue is decays in TargetValueDecayTimeScale and
// the CurrentValue will be held back by FrictionTimeScale.
// TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay.
// For instance, if something is moving at speed X and the desired speed is Y,
// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
// values of CurrentValue are returned that approach the TargetValue.
// The feature of decaying TargetValue is so vehicles will eventually
// come to a stop rather than run forever. This can be disabled by
// setting TargetValueDecayTimescale to 'infinite'.
// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
public class BSVMotor : BSMotor public class BSVMotor : BSMotor
{ {
public Vector3 FrameOfReference { get; set; } // public Vector3 FrameOfReference { get; set; }
public Vector3 Offset { get; set; } // public Vector3 Offset { get; set; }
public float TimeScale { get; set; } public float TimeScale { get; set; }
public float TargetValueDecayTimeScale { get; set; } public float TargetValueDecayTimeScale { get; set; }
@ -46,8 +92,9 @@ public class BSVMotor : BSMotor
public BSVMotor(string useName) public BSVMotor(string useName)
: base(useName) : base(useName)
{ {
TimeScale = TargetValueDecayTimeScale = Efficiency = 1f; TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
FrictionTimescale = Vector3.Zero; Efficiency = 1f;
FrictionTimescale = BSMotor.InfiniteVector;
CurrentValue = TargetValue = Vector3.Zero; CurrentValue = TargetValue = Vector3.Zero;
} }
public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
@ -67,6 +114,14 @@ public class BSVMotor : BSMotor
{ {
TargetValue = target; TargetValue = target;
} }
// A form of stepping that does not take the time quantum into account.
// The caller must do the right thing later.
public Vector3 Step()
{
return Step(1f);
}
public Vector3 Step(float timeStep) public Vector3 Step(float timeStep)
{ {
Vector3 returnCurrent = Vector3.Zero; Vector3 returnCurrent = Vector3.Zero;
@ -78,23 +133,36 @@ public class BSVMotor : BSMotor
// Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
CurrentValue += addAmount; CurrentValue += addAmount;
returnCurrent = CurrentValue; returnCurrent = CurrentValue;
// The desired value reduces to zero when also reduces the difference with current. // The desired value reduces to zero which also reduces the difference with current.
float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; // If the decay time is infinite, don't decay at all.
float decayFactor = 0f;
if (TargetValueDecayTimeScale != BSMotor.Infinite)
{
decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
TargetValue *= (1f - decayFactor); TargetValue *= (1f - decayFactor);
}
Vector3 frictionFactor = Vector3.Zero; Vector3 frictionFactor = Vector3.Zero;
frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; if (FrictionTimescale != BSMotor.InfiniteVector)
{
// frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
// Individual friction components can be 'infinite' so compute each separately.
frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
CurrentValue *= (Vector3.One - frictionFactor); CurrentValue *= (Vector3.One - frictionFactor);
}
MDetailLog("{0},BSVMotor.Step,nonZero,{1},origTarget={2},origCurr={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}", MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
BSScene.DetailLogZero, UseName, origTarget, origCurrVal, BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
timeStep, TimeScale, addAmount, timeStep, TimeScale, addAmount,
TargetValueDecayTimeScale, decayFactor, TargetValueDecayTimeScale, decayFactor,
FrictionTimescale, frictionFactor); FrictionTimescale, frictionFactor);
MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", MDetailLog("{0}, BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
addAmount, decayFactor, frictionFactor, returnCurrent); addAmount, decayFactor, frictionFactor, returnCurrent);
} }
else else
@ -103,7 +171,7 @@ public class BSVMotor : BSMotor
CurrentValue = Vector3.Zero; CurrentValue = Vector3.Zero;
TargetValue = Vector3.Zero; TargetValue = Vector3.Zero;
MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", MDetailLog("{0}, BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
} }

View File

@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject
// Zero some other properties in the physics engine // Zero some other properties in the physics engine
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
{ {
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
}); });
} }
@ -329,7 +330,7 @@ public sealed class BSPrim : BSPhysObject
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
{ {
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
// TODO: a floating motor so object will bob in the water // TODO: a floating motor so object will bob in the water
if (Math.Abs(Position.Z - waterHeight) > 0.1f) if (Math.Abs(Position.Z - waterHeight) > 0.1f)
{ {
@ -347,7 +348,9 @@ public sealed class BSPrim : BSPhysObject
if (ret) if (ret)
{ {
// Apply upforce and overcome gravity. // Apply upforce and overcome gravity.
AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime); OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
AddForce(correctionForce, false, inTaintTime);
} }
return ret; return ret;
} }
@ -643,9 +646,13 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
// Collision filter can be set only when the object is in the world // Collision filter can be set only when the object is in the world
if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) if (PhysBody.collisionGroup != 0 || PhysBody.collisionMask != 0)
{ {
BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); if (!BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, (uint)PhysBody.collisionGroup, (uint)PhysBody.collisionMask))
{
PhysicsScene.Logger.ErrorFormat("{0} Failure setting prim collision mask. localID={1}, grp={2:X}, mask={3:X}",
LogHeader, LocalID, PhysBody.collisionGroup, PhysBody.collisionMask);
}
} }
// Recompute any linkset parameters. // Recompute any linkset parameters.
@ -684,11 +691,11 @@ public sealed class BSPrim : BSPhysObject
// There can be special things needed for implementing linksets // There can be special things needed for implementing linksets
Linkset.MakeStatic(this); Linkset.MakeStatic(this);
// The activation state is 'disabled' so Bullet will not try to act on it. // The activation state is 'disabled' so Bullet will not try to act on it.
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
// Start it out sleeping and physical actions could wake it up. // Start it out sleeping and physical actions could wake it up.
// BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; PhysBody.collisionGroup = CollisionFilterGroups.StaticObjectGroup;
PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
} }
else else
@ -734,7 +741,7 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
// BulletSimAPI.Activate2(BSBody.ptr, true); // BulletSimAPI.Activate2(BSBody.ptr, true);
PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; PhysBody.collisionGroup = CollisionFilterGroups.ObjectGroup;
PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
} }
} }
@ -762,7 +769,7 @@ public sealed class BSPrim : BSPhysObject
m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
} }
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; PhysBody.collisionGroup = CollisionFilterGroups.VolumeDetectGroup;
PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
} }
} }
@ -838,15 +845,6 @@ public sealed class BSPrim : BSPhysObject
} }
public override OMV.Vector3 RotationalVelocity { public override OMV.Vector3 RotationalVelocity {
get { get {
/*
OMV.Vector3 pv = OMV.Vector3.Zero;
// if close to zero, report zero
// This is copied from ODE but I'm not sure why it returns zero but doesn't
// zero the property in the physics engine.
if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
return pv;
*/
return _rotationalVelocity; return _rotationalVelocity;
} }
set { set {
@ -1012,6 +1010,9 @@ public sealed class BSPrim : BSPhysObject
}); });
} }
// A torque impulse. // A torque impulse.
// ApplyTorqueImpulse adds torque directly to the angularVelocity.
// AddAngularForce accumulates the force and applied it to the angular velocity all at once.
// Computed as: angularVelocity += impulse * inertia;
public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
{ {
OMV.Vector3 applyImpulse = impulse; OMV.Vector3 applyImpulse = impulse;
@ -1380,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject
public override void UpdateProperties(EntityProperties entprop) public override void UpdateProperties(EntityProperties entprop)
{ {
/*
UpdatedProperties changed = 0;
// assign to the local variables so the normal set action does not happen
// if (_position != entprop.Position)
if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
{
_position = entprop.Position;
changed |= UpdatedProperties.Position;
}
// if (_orientation != entprop.Rotation)
if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
{
_orientation = entprop.Rotation;
changed |= UpdatedProperties.Rotation;
}
// if (_velocity != entprop.Velocity)
if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
{
_velocity = entprop.Velocity;
changed |= UpdatedProperties.Velocity;
}
// if (_acceleration != entprop.Acceleration)
if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
{
_acceleration = entprop.Acceleration;
changed |= UpdatedProperties.Acceleration;
}
// if (_rotationalVelocity != entprop.RotationalVelocity)
if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
{
_rotationalVelocity = entprop.RotationalVelocity;
changed |= UpdatedProperties.RotationalVel;
}
if (changed != 0)
{
// Only update the position of single objects and linkset roots
if (Linkset.IsRoot(this))
{
base.RequestPhysicsterseUpdate();
}
}
*/
// Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
// Updates only for individual prims and for the root object of a linkset. // Updates only for individual prims and for the root object of a linkset.
if (Linkset.IsRoot(this)) if (Linkset.IsRoot(this))
{ {
// A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
// TODO: handle physics introduced by Bullet with computed vehicle physics.
if (_vehicle.IsActive)
{
entprop.RotationalVelocity = OMV.Vector3.Zero;
}
// Assign directly to the local variables so the normal set action does not happen // Assign directly to the local variables so the normal set action does not happen
_position = entprop.Position; _position = entprop.Position;
_orientation = entprop.Rotation; _orientation = entprop.Rotation;
@ -1436,7 +1399,7 @@ public sealed class BSPrim : BSPhysObject
_rotationalVelocity = entprop.RotationalVelocity; _rotationalVelocity = entprop.RotationalVelocity;
// The sanity check can change the velocity and/or position. // The sanity check can change the velocity and/or position.
if (PositionSanityCheck(true)) if (IsPhysical && PositionSanityCheck(true))
{ {
entprop.Position = _position; entprop.Position = _position;
entprop.Velocity = _velocity; entprop.Velocity = _velocity;
@ -1446,12 +1409,10 @@ public sealed class BSPrim : BSPhysObject
LastEntityProperties = CurrentEntityProperties; LastEntityProperties = CurrentEntityProperties;
CurrentEntityProperties = entprop; CurrentEntityProperties = entprop;
OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
// BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
base.RequestPhysicsterseUpdate(); base.RequestPhysicsterseUpdate();
} }
/* /*

View File

@ -96,6 +96,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public long SimulationStep { get { return m_simulationStep; } } public long SimulationStep { get { return m_simulationStep; } }
private int m_taintsToProcessPerStep; private int m_taintsToProcessPerStep;
public delegate void PreStepAction(float timeStep);
public event PreStepAction BeforeStep;
// A value of the time now so all the collision and update routines do not have to get their own // A value of the time now so all the collision and update routines do not have to get their own
// Set to 'now' just before all the prims and actors are called for collisions and updates // Set to 'now' just before all the prims and actors are called for collisions and updates
public int SimulationNowTime { get; private set; } public int SimulationNowTime { get; private set; }
@ -127,7 +130,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public const uint GROUNDPLANE_ID = 1; public const uint GROUNDPLANE_ID = 1;
public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
private float m_waterLevel; public float SimpleWaterLevel { get; set; }
public BSTerrainManager TerrainManager { get; private set; } public BSTerrainManager TerrainManager { get; private set; }
public ConfigurationParameters Params public ConfigurationParameters Params
@ -182,6 +185,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
private string m_physicsLoggingDir; private string m_physicsLoggingDir;
private string m_physicsLoggingPrefix; private string m_physicsLoggingPrefix;
private int m_physicsLoggingFileMinutes; private int m_physicsLoggingFileMinutes;
private bool m_physicsLoggingDoFlush;
// 'true' of the vehicle code is to log lots of details // 'true' of the vehicle code is to log lots of details
public bool VehicleLoggingEnabled { get; private set; } public bool VehicleLoggingEnabled { get; private set; }
@ -290,6 +294,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
// Very detailed logging for vehicle debugging // Very detailed logging for vehicle debugging
VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
@ -485,8 +490,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
ProcessTaints(); ProcessTaints();
// Some of the prims operate with special vehicle properties // Some of the prims operate with special vehicle properties
ProcessVehicles(timeStep); DoPreStepActions(timeStep);
ProcessTaints(); // the vehicles might have added taints
// the prestep actions might have added taints
ProcessTaints();
// step the physical world one interval // step the physical world one interval
m_simulationStep++; m_simulationStep++;
@ -515,9 +522,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
collidersCount = 0; collidersCount = 0;
} }
// Don't have to use the pointers passed back since we know it is the same pinned memory we passed in // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
// Get a value for 'now' so all the collision and update routines don't have to get their own // Get a value for 'now' so all the collision and update routines don't have to get their own.
SimulationNowTime = Util.EnvironmentTickCount(); SimulationNowTime = Util.EnvironmentTickCount();
// If there were collisions, process them by sending the event to the prim. // If there were collisions, process them by sending the event to the prim.
@ -563,6 +570,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
ObjectsWithCollisions.Remove(po); ObjectsWithCollisions.Remove(po);
ObjectsWithNoMoreCollisions.Clear(); ObjectsWithNoMoreCollisions.Clear();
} }
// Done with collisions.
// If any of the objects had updated properties, tell the object it has been changed by the physics engine // If any of the objects had updated properties, tell the object it has been changed by the physics engine
if (updatedEntityCount > 0) if (updatedEntityCount > 0)
@ -586,9 +594,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// The physics engine returns the number of milliseconds it simulated this call. // The physics engine returns the number of milliseconds it simulated this call.
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
// We multiply by 55 to give a recognizable running rate (55 or less). // Multiply by 55 to give a nominal frame rate of 55.
return numSubSteps * m_fixedTimeStep * 1000 * 55; return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
// return timeStep * 1000 * 55;
} }
// Something has collided // Something has collided
@ -634,12 +641,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public override void SetWaterLevel(float baseheight) public override void SetWaterLevel(float baseheight)
{ {
m_waterLevel = baseheight; SimpleWaterLevel = baseheight;
}
// Someday....
public float GetWaterLevelAtXYZ(Vector3 loc)
{
return m_waterLevel;
} }
public override void DeleteTerrain() public override void DeleteTerrain()
@ -910,6 +912,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
} }
} }
private void DoPreStepActions(float timeStep)
{
ProcessVehicles(timeStep);
PreStepAction actions = BeforeStep;
if (actions != null)
actions(timeStep);
}
// Some prims have extra vehicle actions // Some prims have extra vehicle actions
// Called at taint time! // Called at taint time!
private void ProcessVehicles(float timeStep) private void ProcessVehicles(float timeStep)
@ -974,6 +986,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// Should handle fetching the right type from the ini file and converting it. // Should handle fetching the right type from the ini file and converting it.
// -- a delegate for getting the value as a float // -- a delegate for getting the value as a float
// -- a delegate for setting the value from a float // -- a delegate for setting the value from a float
// -- an optional delegate to update the value in the world. Most often used to
// push the new value to an in-world object.
// //
// The single letter parameters for the delegates are: // The single letter parameters for the delegates are:
// s = BSScene // s = BSScene
@ -1172,7 +1186,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].avatarFriction; }, (s) => { return s.m_params[0].avatarFriction; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
0.99f, 10.0f,
(s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarStandingFriction; }, (s) => { return s.m_params[0].avatarStandingFriction; },
(s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
@ -1493,7 +1507,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
{ {
PhysicsLogging.Write(msg, args); PhysicsLogging.Write(msg, args);
// Add the Flush() if debugging crashes. Gets all the messages written out. // Add the Flush() if debugging crashes. Gets all the messages written out.
// PhysicsLogging.Flush(); if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
} }
// Used to fill in the LocalID when there isn't one. It's the correct number of characters. // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
public const string DetailLogZero = "0000000000"; public const string DetailLogZero = "0000000000";

View File

@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable
private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
private bool DDetail = false;
public BSShapeCollection(BSScene physScene) public BSShapeCollection(BSScene physScene)
{ {
PhysicsScene = physScene; PhysicsScene = physScene;
// Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
// While detailed debugging is still active, this is better than commenting out all the
// DetailLog statements. When debugging slows down, this and the protected logging
// statements can be commented/removed.
DDetail = true;
} }
public void Dispose() public void Dispose()
@ -126,13 +133,13 @@ public sealed class BSShapeCollection : IDisposable
{ {
lock (m_collectionActivityLock) lock (m_collectionActivityLock)
{ {
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
{ {
if (!BulletSimAPI.IsInWorld2(body.ptr)) if (!BulletSimAPI.IsInWorld2(body.ptr))
{ {
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
} }
}); });
} }
@ -149,7 +156,7 @@ public sealed class BSShapeCollection : IDisposable
{ {
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
{ {
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
body.ID, body, inTaintTime); body.ID, body, inTaintTime);
// If the caller needs to know the old body is going away, pass the event up. // If the caller needs to know the old body is going away, pass the event up.
if (bodyCallback != null) bodyCallback(body); if (bodyCallback != null) bodyCallback(body);
@ -157,7 +164,7 @@ public sealed class BSShapeCollection : IDisposable
if (BulletSimAPI.IsInWorld2(body.ptr)) if (BulletSimAPI.IsInWorld2(body.ptr))
{ {
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
} }
// Zero any reference to the shape so it is not freed when the body is deleted. // Zero any reference to the shape so it is not freed when the body is deleted.
@ -184,7 +191,7 @@ public sealed class BSShapeCollection : IDisposable
{ {
// There is an existing instance of this mesh. // There is an existing instance of this mesh.
meshDesc.referenceCount++; meshDesc.referenceCount++;
DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
} }
else else
@ -194,7 +201,7 @@ public sealed class BSShapeCollection : IDisposable
meshDesc.shapeKey = shape.shapeKey; meshDesc.shapeKey = shape.shapeKey;
// We keep a reference to the underlying IMesh data so a hull can be built // We keep a reference to the underlying IMesh data so a hull can be built
meshDesc.referenceCount = 1; meshDesc.referenceCount = 1;
DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
ret = true; ret = true;
} }
@ -207,7 +214,7 @@ public sealed class BSShapeCollection : IDisposable
{ {
// There is an existing instance of this hull. // There is an existing instance of this hull.
hullDesc.referenceCount++; hullDesc.referenceCount++;
DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
} }
else else
@ -216,7 +223,7 @@ public sealed class BSShapeCollection : IDisposable
hullDesc.ptr = shape.ptr; hullDesc.ptr = shape.ptr;
hullDesc.shapeKey = shape.shapeKey; hullDesc.shapeKey = shape.shapeKey;
hullDesc.referenceCount = 1; hullDesc.referenceCount = 1;
DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
ret = true; ret = true;
@ -246,7 +253,7 @@ public sealed class BSShapeCollection : IDisposable
if (shape.isNativeShape) if (shape.isNativeShape)
{ {
// Native shapes are not tracked and are released immediately // Native shapes are not tracked and are released immediately
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
if (shapeCallback != null) shapeCallback(shape); if (shapeCallback != null) shapeCallback(shape);
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
@ -286,7 +293,7 @@ public sealed class BSShapeCollection : IDisposable
if (shapeCallback != null) shapeCallback(shape); if (shapeCallback != null) shapeCallback(shape);
meshDesc.lastReferenced = System.DateTime.Now; meshDesc.lastReferenced = System.DateTime.Now;
Meshes[shape.shapeKey] = meshDesc; Meshes[shape.shapeKey] = meshDesc;
DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
BSScene.DetailLogZero, shape, meshDesc.referenceCount); BSScene.DetailLogZero, shape, meshDesc.referenceCount);
} }
@ -307,7 +314,7 @@ public sealed class BSShapeCollection : IDisposable
hullDesc.lastReferenced = System.DateTime.Now; hullDesc.lastReferenced = System.DateTime.Now;
Hulls[shape.shapeKey] = hullDesc; Hulls[shape.shapeKey] = hullDesc;
DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
BSScene.DetailLogZero, shape, hullDesc.referenceCount); BSScene.DetailLogZero, shape, hullDesc.referenceCount);
} }
} }
@ -325,13 +332,13 @@ public sealed class BSShapeCollection : IDisposable
// Failed the sanity check!! // Failed the sanity check!!
PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
LogHeader, shape.type, shape.ptr.ToString("X")); LogHeader, shape.type, shape.ptr.ToString("X"));
DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
return; return;
} }
int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
for (int ii = numChildren - 1; ii >= 0; ii--) for (int ii = numChildren - 1; ii >= 0; ii--)
{ {
@ -379,7 +386,7 @@ public sealed class BSShapeCollection : IDisposable
} }
} }
DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
{ {
@ -410,7 +417,7 @@ public sealed class BSShapeCollection : IDisposable
// an avatar capsule is close to a native shape (it is not shared) // an avatar capsule is close to a native shape (it is not shared)
ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
FixedShapeKey.KEY_CAPSULE, shapeCallback); FixedShapeKey.KEY_CAPSULE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
ret = true; ret = true;
haveShape = true; haveShape = true;
} }
@ -420,7 +427,7 @@ public sealed class BSShapeCollection : IDisposable
if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
{ {
ret = GetReferenceToCompoundShape(prim, shapeCallback); ret = GetReferenceToCompoundShape(prim, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
haveShape = true; haveShape = true;
} }
@ -465,7 +472,7 @@ public sealed class BSShapeCollection : IDisposable
{ {
ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
FixedShapeKey.KEY_SPHERE, shapeCallback); FixedShapeKey.KEY_SPHERE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.PhysShape); prim.LocalID, forceRebuild, prim.PhysShape);
} }
} }
@ -479,7 +486,7 @@ public sealed class BSShapeCollection : IDisposable
{ {
ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
FixedShapeKey.KEY_BOX, shapeCallback); FixedShapeKey.KEY_BOX, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.PhysShape); prim.LocalID, forceRebuild, prim.PhysShape);
} }
} }
@ -504,13 +511,13 @@ public sealed class BSShapeCollection : IDisposable
{ {
// Update prim.BSShape to reference a hull of this shape. // Update prim.BSShape to reference a hull of this shape.
ret = GetReferenceToHull(prim,shapeCallback); ret = GetReferenceToHull(prim,shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
} }
else else
{ {
ret = GetReferenceToMesh(prim, shapeCallback); ret = GetReferenceToMesh(prim, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
} }
return ret; return ret;
@ -528,7 +535,7 @@ public sealed class BSShapeCollection : IDisposable
BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared. // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
prim.LocalID, newShape, prim.Scale); prim.LocalID, newShape, prim.Scale);
prim.PhysShape = newShape; prim.PhysShape = newShape;
@ -554,7 +561,7 @@ public sealed class BSShapeCollection : IDisposable
newShape = new BulletShape( newShape = new BulletShape(
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
, shapeType); , shapeType);
DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
} }
else else
{ {
@ -589,7 +596,7 @@ public sealed class BSShapeCollection : IDisposable
if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
return false; return false;
DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
// Since we're recreating new, get rid of the reference to the previous shape // Since we're recreating new, get rid of the reference to the previous shape
@ -620,8 +627,7 @@ public sealed class BSShapeCollection : IDisposable
} }
else else
{ {
// Pass false for physicalness as this creates some sort of bounding box which we don't need meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
if (meshData != null) if (meshData != null)
{ {
@ -663,7 +669,7 @@ public sealed class BSShapeCollection : IDisposable
if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
return false; return false;
DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
// Remove usage of the previous shape. // Remove usage of the previous shape.
@ -694,8 +700,8 @@ public sealed class BSShapeCollection : IDisposable
else else
{ {
// Build a new hull in the physical world // Build a new hull in the physical world
// Pass false for physicalness as this creates some sort of bounding box which we don't need // Pass true for physicalness as this creates some sort of bounding box which we don't need
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
if (meshData != null) if (meshData != null)
{ {
@ -809,7 +815,7 @@ public sealed class BSShapeCollection : IDisposable
// Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
CreateGeomMeshOrHull(prim, shapeCallback); CreateGeomMeshOrHull(prim, shapeCallback);
BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
prim.LocalID, cShape, prim.PhysShape); prim.LocalID, cShape, prim.PhysShape);
prim.PhysShape = cShape; prim.PhysShape = cShape;
@ -936,13 +942,13 @@ public sealed class BSShapeCollection : IDisposable
{ {
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
prim.LocalID, prim.RawPosition, prim.RawOrientation); prim.LocalID, prim.RawPosition, prim.RawOrientation);
DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
} }
else else
{ {
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
prim.LocalID, prim.RawPosition, prim.RawOrientation); prim.LocalID, prim.RawPosition, prim.RawOrientation);
DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
} }
aBody = new BulletBody(prim.LocalID, bodyPtr); aBody = new BulletBody(prim.LocalID, bodyPtr);

View File

@ -121,8 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
// redo its bounding box now that it is in the world // redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, BulletSimAPI.SetCollisionGroupMask2(m_mapInfo.terrainBody.ptr,
(uint)CollisionFilterGroups.TerrainFilter, (uint)CollisionFilterGroups.TerrainGroup,
(uint)CollisionFilterGroups.TerrainMask); (uint)CollisionFilterGroups.TerrainMask);
// Make it so the terrain will not move or be considered for movement. // Make it so the terrain will not move or be considered for movement.
@ -148,7 +148,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
} }
// The passed position is relative to the base of the region. // The passed position is relative to the base of the region.
public override float GetHeightAtXYZ(Vector3 pos) public override float GetTerrainHeightAtXYZ(Vector3 pos)
{ {
float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
@ -166,5 +166,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
} }
return ret; return ret;
} }
// The passed position is relative to the base of the region.
public override float GetWaterLevelAtXYZ(Vector3 pos)
{
return PhysicsScene.SimpleWaterLevel;
}
} }
} }

View File

@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable
ID = id; ID = id;
} }
public abstract void Dispose(); public abstract void Dispose();
public abstract float GetHeightAtXYZ(Vector3 pos); public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
public abstract float GetWaterLevelAtXYZ(Vector3 pos);
} }
// ========================================================================================== // ==========================================================================================
@ -75,6 +76,7 @@ public sealed class BSTerrainManager
public const float HEIGHT_INITIALIZATION = 24.987f; public const float HEIGHT_INITIALIZATION = 24.987f;
public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
public const float HEIGHT_GETHEIGHT_RET = 24.765f; public const float HEIGHT_GETHEIGHT_RET = 24.765f;
public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
// If the min and max height are equal, we reduce the min by this // If the min and max height are equal, we reduce the min by this
// amount to make sure that a bounding box is built for the terrain. // amount to make sure that a bounding box is built for the terrain.
@ -138,8 +140,8 @@ public sealed class BSTerrainManager
// Ground plane does not move // Ground plane does not move
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
// Everything collides with the ground plane. // Everything collides with the ground plane.
BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, BulletSimAPI.SetCollisionGroupMask2(m_groundPlane.ptr,
(uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); (uint)CollisionFilterGroups.GroundPlaneGroup, (uint)CollisionFilterGroups.GroundPlaneMask);
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
@ -358,7 +360,7 @@ public sealed class BSTerrainManager
BSTerrainPhys physTerrain; BSTerrainPhys physTerrain;
if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
{ {
ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); ret = physTerrain.GetTerrainHeightAtXYZ(loc - terrainBaseXYZ);
} }
else else
{ {
@ -370,6 +372,33 @@ public sealed class BSTerrainManager
return ret; return ret;
} }
public float GetWaterLevelAtXYZ(Vector3 pos)
{
float ret = WATER_HEIGHT_GETHEIGHT_RET;
float tX = pos.X;
float tY = pos.Y;
Vector3 terrainBaseXYZ = Vector3.Zero;
terrainBaseXYZ.X = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
terrainBaseXYZ.Y = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
lock (m_terrains)
{
BSTerrainPhys physTerrain;
if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
{
ret = physTerrain.GetWaterLevelAtXYZ(pos);
}
else
{
PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
LogHeader, PhysicsScene.RegionName, tX, tY);
}
}
return ret;
}
// Although no one seems to check this, I do support combining. // Although no one seems to check this, I do support combining.
public bool SupportsCombining() public bool SupportsCombining()
{ {

View File

@ -88,6 +88,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Something is very messed up and a crash is in our future. // Something is very messed up and a crash is in our future.
return; return;
} }
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
ID, indicesCount, indices.Length, verticesCount, vertices.Length);
m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
indicesCount, indices, verticesCount, vertices), indicesCount, indices, verticesCount, vertices),
@ -122,14 +124,14 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Static objects are not very massive. // Static objects are not very massive.
BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
// Return the new terrain to the world of physical objects // Put the new terrain to the world of physical objects
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
// redo its bounding box now that it is in the world // Redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, BulletSimAPI.SetCollisionGroupMask2(m_terrainBody.ptr,
(uint)CollisionFilterGroups.TerrainFilter, (uint)CollisionFilterGroups.TerrainGroup,
(uint)CollisionFilterGroups.TerrainMask); (uint)CollisionFilterGroups.TerrainMask);
// Make it so the terrain will not move or be considered for movement. // Make it so the terrain will not move or be considered for movement.
@ -146,7 +148,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
} }
} }
public override float GetHeightAtXYZ(Vector3 pos) public override float GetTerrainHeightAtXYZ(Vector3 pos)
{ {
// For the moment use the saved heightmap to get the terrain height. // For the moment use the saved heightmap to get the terrain height.
// TODO: raycast downward to find the true terrain below the position. // TODO: raycast downward to find the true terrain below the position.
@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
return ret; return ret;
} }
// The passed position is relative to the base of the region.
public override float GetWaterLevelAtXYZ(Vector3 pos)
{
return PhysicsScene.SimpleWaterLevel;
}
// Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
// Return 'true' if successfully created. // Return 'true' if successfully created.
public static bool ConvertHeightmapToMesh( public static bool ConvertHeightmapToMesh(
@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Simple mesh creation which assumes magnification == 1. // Simple mesh creation which assumes magnification == 1.
// TODO: do a more general solution that scales, adds new vertices and smoothes the result. // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
// Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
// from zero to <= sizeX). The triangle indices are then generated as two triangles
// per heightmap point. There are sizeX by sizeY of these squares. The extra row and
// column of vertices are used to complete the triangles of the last row and column
// of the heightmap.
try try
{ {
// One vertice per heightmap value plus the vertices off the top and bottom edge. // One vertice per heightmap value plus the vertices off the top and bottom edge.
@ -200,16 +213,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
float magY = (float)sizeY / extentY; float magY = (float)sizeY / extentY;
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
float minHeight = float.MaxValue;
// Note that sizeX+1 vertices are created since there is land between this and the next region. // Note that sizeX+1 vertices are created since there is land between this and the next region.
for (int yy = 0; yy <= sizeY; yy++) for (int yy = 0; yy <= sizeY; yy++)
{ {
for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
{ {
int offset = yy * sizeX + xx; int offset = yy * sizeX + xx;
// Extend the height from the height from the last row or column // Extend the height with the height from the last row or column
if (yy == sizeY) offset -= sizeX; if (yy == sizeY) offset -= sizeX;
if (xx == sizeX) offset -= 1; if (xx == sizeX) offset -= 1;
float height = heightMap[offset]; float height = heightMap[offset];
minHeight = Math.Min(minHeight, height);
vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
vertices[verticesCount + 2] = height + extentBase.Z; vertices[verticesCount + 2] = height + extentBase.Z;
@ -222,7 +237,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
{ {
for (int xx = 0; xx < sizeX; xx++) for (int xx = 0; xx < sizeX; xx++)
{ {
int offset = yy * sizeX + xx; int offset = yy * (sizeX + 1) + xx;
// Each vertices is presumed to be the upper left corner of a box of two triangles // Each vertices is presumed to be the upper left corner of a box of two triangles
indices[indicesCount + 0] = offset; indices[indicesCount + 0] = offset;
indices[indicesCount + 1] = offset + 1; indices[indicesCount + 1] = offset + 1;
@ -233,6 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
indicesCount += 6; indicesCount += 6;
} }
} }
ret = true; ret = true;
} }
catch (Exception e) catch (Exception e)

View File

@ -57,12 +57,12 @@ public struct BulletBody
{ {
ID = id; ID = id;
ptr = xx; ptr = xx;
collisionFilter = 0; collisionGroup = 0;
collisionMask = 0; collisionMask = 0;
} }
public IntPtr ptr; public IntPtr ptr;
public uint ID; public uint ID;
public CollisionFilterGroups collisionFilter; public CollisionFilterGroups collisionGroup;
public CollisionFilterGroups collisionMask; public CollisionFilterGroups collisionMask;
public override string ToString() public override string ToString()
{ {
@ -71,10 +71,10 @@ public struct BulletBody
buff.Append(ID.ToString()); buff.Append(ID.ToString());
buff.Append(",p="); buff.Append(",p=");
buff.Append(ptr.ToString("X")); buff.Append(ptr.ToString("X"));
if (collisionFilter != 0 || collisionMask != 0) if (collisionGroup != 0 || collisionMask != 0)
{ {
buff.Append(",f="); buff.Append(",g=");
buff.Append(collisionFilter.ToString("X")); buff.Append(collisionGroup.ToString("X"));
buff.Append(",m="); buff.Append(",m=");
buff.Append(collisionMask.ToString("X")); buff.Append(collisionMask.ToString("X"));
} }
@ -357,9 +357,10 @@ public enum CollisionFlags : uint
CF_CHARACTER_OBJECT = 1 << 4, CF_CHARACTER_OBJECT = 1 << 4,
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
CF_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 and updates
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
BS_FLOATS_ON_WATER = 1 << 11, BS_FLOATS_ON_WATER = 1 << 11,
BS_VEHICLE_COLLISIONS = 1 << 12,
BS_NONE = 0, BS_NONE = 0,
BS_ALL = 0xFFFFFFFF, BS_ALL = 0xFFFFFFFF,
@ -376,36 +377,36 @@ public enum CollisionFilterGroups : uint
// Don't use the bit definitions!! Define the use in a // Don't use the bit definitions!! Define the use in a
// filter/mask definition below. This way collision interactions // filter/mask definition below. This way collision interactions
// are more easily debugged. // are more easily debugged.
BNoneFilter = 0, BNoneGroup = 0,
BDefaultFilter = 1 << 0, BDefaultGroup = 1 << 0,
BStaticFilter = 1 << 1, BStaticGroup = 1 << 1,
BKinematicFilter = 1 << 2, BKinematicGroup = 1 << 2,
BDebrisFilter = 1 << 3, BDebrisGroup = 1 << 3,
BSensorTrigger = 1 << 4, BSensorTrigger = 1 << 4,
BCharacterFilter = 1 << 5, BCharacterGroup = 1 << 5,
BAllFilter = 0xFFFFFFFF, BAllGroup = 0xFFFFFFFF,
// Filter groups defined by BulletSim // Filter groups defined by BulletSim
BGroundPlaneFilter = 1 << 10, BGroundPlaneGroup = 1 << 10,
BTerrainFilter = 1 << 11, BTerrainGroup = 1 << 11,
BRaycastFilter = 1 << 12, BRaycastGroup = 1 << 12,
BSolidFilter = 1 << 13, BSolidGroup = 1 << 13,
BLinksetFilter = 1 << 14, BLinksetGroup = 1 << 14,
// The collsion filters and masked are defined in one place -- don't want them scattered // The collsion filters and masked are defined in one place -- don't want them scattered
AvatarFilter = BCharacterFilter, AvatarGroup = BCharacterGroup,
AvatarMask = BAllFilter, AvatarMask = BAllGroup,
ObjectFilter = BSolidFilter, ObjectGroup = BSolidGroup,
ObjectMask = BAllFilter, ObjectMask = BAllGroup,
StaticObjectFilter = BStaticFilter, StaticObjectGroup = BStaticGroup,
StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
LinksetFilter = BLinksetFilter, LinksetGroup = BLinksetGroup,
LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other LinksetMask = BAllGroup & ~BLinksetGroup, // linkset objects don't collide with each other
VolumeDetectFilter = BSensorTrigger, VolumeDetectGroup = BSensorTrigger,
VolumeDetectMask = ~BSensorTrigger, VolumeDetectMask = ~BSensorTrigger,
TerrainFilter = BTerrainFilter, TerrainGroup = BTerrainGroup,
TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
GroundPlaneFilter = BGroundPlaneFilter, GroundPlaneGroup = BGroundPlaneGroup,
GroundPlaneMask = BAllFilter GroundPlaneMask = BAllGroup
}; };
@ -945,7 +946,7 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
public static extern int GetNumConstraintRefs2(IntPtr obj); public static extern int GetNumConstraintRefs2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
// ===================================================================================== // =====================================================================================
// btCollisionShape entries // btCollisionShape entries
@ -1006,14 +1007,17 @@ public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpAllInfo2(IntPtr sim); public static extern void DumpActivationInfo2(IntPtr sim);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); public static extern void DumpAllInfo2(IntPtr sim);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpPhysicsStatistics2(IntPtr sim); public static extern void DumpPhysicsStatistics2(IntPtr sim);

View File

@ -0,0 +1,142 @@
CRASHES
=================================================
20121129.1411: editting/moving phys object across region boundries causes crash
getPos-> btRigidBody::upcast -> getBodyType -> BOOM
20121128.1600: mesh object not rezzing (no physics mesh).
Causes many errors. Doesn't stop after first error with box shape.
Eventually crashes when deleting the object.
VEHICLES TODO LIST:
=================================================
Neb car jiggling left and right
Happens on terrain and any other mesh object. Flat cubes are much smoother.
Vehicles (Move smoothly)
Add vehicle collisions so IsColliding is properly reported.
Needed for banking, limitMotorUp, movementLimiting, ...
Some vehicles should not be able to turn if no speed or off ground.
For limitMotorUp, use raycast down to find if vehicle is in the air.
Implement function efficiency for lineaar and angular motion.
Should vehicle angular/linear movement friction happen after all the components
or does it only apply to the basic movement?
After getting off a vehicle, the root prim is phantom (can be walked through)
Need to force a position update for the root prim after compound shape destruction
Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
Implement referenceFrame for all the motion routines.
Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
BULLETSIM TODO LIST:
=================================================
Disable activity of passive linkset children.
Since the linkset is a compound object, the old prims are left lying
around and need to be phantomized so they don't collide, ...
Scenes with hundred of thousands of static objects take a lot of physics CPU time.
BSPrim.Force should set a continious force on the prim. The force should be
applied each tick. Some limits?
Single prim vehicles don't seem to properly vehiclize.
Gun sending shooter flying.
Collision margin (gap between physical objects lying on each other)
Boundry checking (crashes related to crossing boundry)
Add check for border edge position for avatars and objects.
Verify the events are created for border crossings.
Avatar rotation (check out changes to ScenePresence for physical rotation)
Avatar running (what does phys engine need to do?)
Small physical objects do not interact correctly
Create chain of .5x.5x.1 torui and make all but top physical so to hang.
The chain will fall apart and pairs will dance around on ground
Chains of 1x1x.2 will stay connected but will dance.
Chains above 2x2x.4 are move stable and get stablier as torui get larger.
Add material type linkage and input all the material property definitions.
Skeleton classes and table are in the sources but are not filled or used.
Add PID motor for avatar movement (slow to stop, ...)
setForce should set a constant force. Different than AddImpulse.
Implement raycast.
Implement ShapeCollection.Dispose()
Implement water as a plain so raycasting and collisions can happen with same.
Find/remove avatar collision with ID=0.
Test avatar walking up stairs. How does compare with SL.
Radius of the capsule affects ability to climb edges.
Tune terrain/object friction to be closer to SL.
Debounce avatar contact so legs don't keep folding up when standing.
Implement LSL physics controls. Like STATUS_ROTATE_X.
Add border extensions to terrain to help region crossings and objects leaving region.
Speed up creation of large physical linksets
For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
Performance test with lots of avatars. Can BulletSim support a thousand?
Optimize collisions in C++: only send up to the object subscribed to collisions.
Use collision subscription and remove the collsion(A,B) and collision(B,A)
Check whether SimMotionState needs large if statement (see TODO).
Implement 'top colliders' info.
Avatar jump
Performance measurement and changes to make quicker.
Implement detailed physics stats (GetStats()).
Eliminate collisions between objects in a linkset. (LinksetConstraint)
Have UserPointer point to struct with localID and linksetID?
Objects in original linkset still collide with each other?
Measure performance improvement from hulls
Test not using ghost objects for volume detect implementation.
Performance of closures and delegates for taint processing
Are there faster ways?
Is any slowdown introduced by the existing implementation significant?
Is there are more efficient method of implementing pre and post step actions?
See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
Physics Arena central pyramid: why is one side permiable?
INTERNAL IMPROVEMENT/CLEANUP
=================================================
Remove unused fields from ShapeData (not used in API2)
Breakout code for mesh/hull/compound/native into separate BSShape* classes
Standardize access to building and reference code.
The skeleton classes are in the sources but are not complete or linked in.
Generalize Dynamics and PID with standardized motors.
Generalize Linkset and vehicles into PropertyManagers
Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
Possibly generalized a 'pre step action' registration.
Complete implemention of preStepActions
Replace vehicle step call with prestep event.
Is there a need for postStepActions? postStepTaints?
Implement linkset by setting position of children when root updated. (LinksetManual)
Linkset implementation using manual prim movement.
LinkablePrim class? Would that simplify/centralize the linkset logic?
BSScene.UpdateParameterSet() is broken. How to set params on objects?
Remove HeightmapInfo from terrain specification.
Since C++ code does not need terrain height, this structure et al are not needed.
Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
bob at the water level. BSPrim.PositionSanityCheck().
THREADING
=================================================
Do taint action immediately if not actually executing Bullet.
Add lock around Bullet execution and just do taint actions if simulation is not happening.
DONE DONE DONE DONE
=================================================
Cleanup code in BSDynamics by using motors. (Resolution: started)
Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
Would have better and adjustable resolution.
Build terrain mesh so heighmap is height of the center of the square meter.
Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
Terrain as mesh. (Resolution: done)
How are static linksets seen by the physics engine?
Resolution: they are not linked in physics. When moved, all the children are repositioned.
Convert BSCharacter to use all API2 (Resolution: done)
Avatar pushing difficult (too heavy?)
Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
Remove old code in DLL (all non-API2 stuff). (Resolution: done)
Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
Debug Bullet internal stats output (why is timing all wrong?)
Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
Implement meshes or just verify that they work. (Resolution: they do!)
Do prim hash codes work for sculpties and meshes? (Resolution: yes)
Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
Compound shapes will need the LocalID in the shapes and collision
processing to get it from there.
Light cycle falling over when driving (Resolution: implemented VerticalAttractor)
Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
Package Bullet source mods for Bullet internal stats output
(Resolution: move code into WorldData.h rather than relying on patches)

View File

@ -36,6 +36,7 @@ namespace OpenSim.Region.Physics.Manager
{ {
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache);
} }
// Values for level of detail to be passed to the mesher. // Values for level of detail to be passed to the mesher.

View File

@ -64,10 +64,15 @@ namespace OpenSim.Region.Physics.Manager
{ {
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
{ {
return CreateMesh(primName, primShape, size, lod, false); return CreateMesh(primName, primShape, size, lod, false, false);
} }
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
{
return CreateMesh(primName, primShape, size, lod, false, false);
}
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
{ {
// Remove the reference to the encoded JPEG2000 data so it can be GCed // Remove the reference to the encoded JPEG2000 data so it can be GCed
primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; primShape.SculptData = OpenMetaverse.Utils.EmptyBytes;

View File

@ -321,7 +321,10 @@ namespace OpenSim.Region.Physics.Meshing
if (primShape.SculptData.Length <= 0) if (primShape.SculptData.Length <= 0)
{ {
m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
// method twice - once before it has loaded sculpt data from the asset service and once afterwards.
// The first time will always call with unloaded SculptData if this needs to be uploaded.
// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
return false; return false;
} }
@ -699,11 +702,16 @@ namespace OpenSim.Region.Physics.Meshing
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
{ {
return CreateMesh(primName, primShape, size, lod, false); return CreateMesh(primName, primShape, size, lod, false, true);
} }
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
{ {
return CreateMesh(primName, primShape, size, lod, isPhysical, true);
}
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
{
#if SPAM #if SPAM
m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
#endif #endif
@ -713,9 +721,12 @@ namespace OpenSim.Region.Physics.Meshing
// If this mesh has been created already, return it instead of creating another copy // If this mesh has been created already, return it instead of creating another copy
// For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
if (shouldCache)
{
key = primShape.GetMeshKey(size, lod); key = primShape.GetMeshKey(size, lod);
if (m_uniqueMeshes.TryGetValue(key, out mesh)) if (m_uniqueMeshes.TryGetValue(key, out mesh))
return mesh; return mesh;
}
if (size.X < 0.01f) size.X = 0.01f; if (size.X < 0.01f) size.X = 0.01f;
if (size.Y < 0.01f) size.Y = 0.01f; if (size.Y < 0.01f) size.Y = 0.01f;
@ -738,8 +749,11 @@ namespace OpenSim.Region.Physics.Meshing
// trim the vertex and triangle lists to free up memory // trim the vertex and triangle lists to free up memory
mesh.TrimExcess(); mesh.TrimExcess();
if (shouldCache)
{
m_uniqueMeshes.Add(key, mesh); m_uniqueMeshes.Add(key, mesh);
} }
}
return mesh; return mesh;
} }

View File

@ -3361,6 +3361,11 @@ Console.WriteLine(" JointCreateFixed");
_pbs.SculptData = new byte[asset.Data.Length]; _pbs.SculptData = new byte[asset.Data.Length];
asset.Data.CopyTo(_pbs.SculptData, 0); asset.Data.CopyTo(_pbs.SculptData, 0);
// m_assetFailed = false; // m_assetFailed = false;
// m_log.DebugFormat(
// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
m_taintshape = true; m_taintshape = true;
_parent_scene.AddPhysicsActorTaint(this); _parent_scene.AddPhysicsActorTaint(this);
} }

View File

@ -114,6 +114,16 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
UUID AssetID { get; } UUID AssetID { get; }
Queue EventQueue { get; } Queue EventQueue { get; }
/// <summary>
/// Number of events queued for processing.
/// </summary>
long EventsQueued { get; }
/// <summary>
/// Number of events processed by this script instance.
/// </summary>
long EventsProcessed { get; }
void ClearQueue(); void ClearQueue();
int StartParam { get; set; } int StartParam { get; set; }

View File

@ -6856,6 +6856,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public void llCloseRemoteDataChannel(string channel) public void llCloseRemoteDataChannel(string channel)
{ {
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
if (xmlRpcRouter != null)
{
xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID);
}
IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
xmlrpcMod.CloseXMLRPCChannel((UUID)channel); xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
ScriptSleep(1000); ScriptSleep(1000);

View File

@ -173,6 +173,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
public Queue EventQueue { get; private set; } public Queue EventQueue { get; private set; }
public long EventsQueued
{
get
{
lock (EventQueue)
return EventQueue.Count;
}
}
public long EventsProcessed { get; private set; }
public int StartParam { get; set; } public int StartParam { get; set; }
public TaskInventoryItem ScriptTask { get; private set; } public TaskInventoryItem ScriptTask { get; private set; }
@ -774,6 +785,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
ChatTypeEnum.DebugChannel, 2147483647, ChatTypeEnum.DebugChannel, 2147483647,
part.AbsolutePosition, part.AbsolutePosition,
part.Name, part.UUID, false); part.Name, part.UUID, false);
m_log.DebugFormat(
"[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}",
ScriptName,
PrimName,
part.UUID,
part.AbsolutePosition,
part.ParentGroup.Scene.Name,
text.Replace("\n", "\\n"),
e.InnerException);
} }
catch (Exception) catch (Exception)
{ {
@ -808,6 +830,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
// script engine to run the next event. // script engine to run the next event.
lock (EventQueue) lock (EventQueue)
{ {
EventsProcessed++;
if (EventQueue.Count > 0 && Running && !ShuttingDown) if (EventQueue.Count > 0 && Running && !ShuttingDown)
{ {
m_CurrentWorkItem = Engine.QueueEventHandler(this); m_CurrentWorkItem = Engine.QueueEventHandler(this);
@ -1013,7 +1037,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
"({0}): {1}", scriptLine - 1, "({0}): {1}", scriptLine - 1,
e.InnerException.Message); e.InnerException.Message);
System.Console.WriteLine(e.ToString()+"\n");
return message; return message;
} }
} }

View File

@ -57,8 +57,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
protected XEngine.XEngine m_engine; protected XEngine.XEngine m_engine;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
IConfigSource initConfigSource = new IniConfigSource(); IConfigSource initConfigSource = new IniConfigSource();
IConfig config = initConfigSource.AddConfig("XEngine"); IConfig config = initConfigSource.AddConfig("XEngine");
config.Set("Enabled", "true"); config.Set("Enabled", "true");

View File

@ -62,8 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
protected XEngine.XEngine m_engine; protected XEngine.XEngine m_engine;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
IConfigSource initConfigSource = new IniConfigSource(); IConfigSource initConfigSource = new IniConfigSource();
IConfig config = initConfigSource.AddConfig("XEngine"); IConfig config = initConfigSource.AddConfig("XEngine");
config.Set("Enabled", "true"); config.Set("Enabled", "true");

View File

@ -51,8 +51,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
private LSL_Api m_lslApi; private LSL_Api m_lslApi;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
IConfigSource initConfigSource = new IniConfigSource(); IConfigSource initConfigSource = new IniConfigSource();
IConfig config = initConfigSource.AddConfig("XEngine"); IConfig config = initConfigSource.AddConfig("XEngine");
config.Set("Enabled", "true"); config.Set("Enabled", "true");

View File

@ -57,8 +57,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
protected XEngine.XEngine m_engine; protected XEngine.XEngine m_engine;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
IConfigSource initConfigSource = new IniConfigSource(); IConfigSource initConfigSource = new IniConfigSource();
IConfig config = initConfigSource.AddConfig("XEngine"); IConfig config = initConfigSource.AddConfig("XEngine");
config.Set("Enabled", "true"); config.Set("Enabled", "true");

View File

@ -127,12 +127,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
OSSL_Api osslApi = new OSSL_Api(); OSSL_Api osslApi = new OSSL_Api();
osslApi.Initialize(m_engine, so.RootPart, null); osslApi.Initialize(m_engine, so.RootPart, null);
string npcRaw;
bool gotExpectedException = false; bool gotExpectedException = false;
try try
{ {
npcRaw osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
= osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
} }
catch (ScriptException) catch (ScriptException)
{ {

View File

@ -30,6 +30,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Security; using System.Security;
using System.Security.Policy; using System.Security.Policy;
@ -377,8 +378,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
/// </summary> /// </summary>
/// <param name="cmdparams"></param> /// <param name="cmdparams"></param>
/// <param name="instance"></param> /// <param name="instance"></param>
/// <returns>true if we're okay to proceed, false if not.</returns> /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param>
private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action) private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
{
HandleScriptsAction<object>(cmdparams, action, null);
}
/// <summary>
/// Parse the raw item id into a script instance from the command params if it's present.
/// </summary>
/// <param name="cmdparams"></param>
/// <param name="instance"></param>
/// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
private void HandleScriptsAction<TKey>(
string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector)
{ {
if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
return; return;
@ -390,7 +403,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
if (cmdparams.Length == 2) if (cmdparams.Length == 2)
{ {
foreach (IScriptInstance instance in m_Scripts.Values) IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
if (keySelector != null)
scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
foreach (IScriptInstance instance in scripts)
action(instance); action(instance);
return; return;
@ -437,9 +455,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
lock (m_Scripts) long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count);
lock (m_Scripts)
{
scriptsLoaded = m_Scripts.Count;
foreach (IScriptInstance si in m_Scripts.Values)
{
eventsQueued += si.EventsQueued;
eventsProcessed += si.EventsProcessed;
}
}
sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
@ -448,6 +477,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); // sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
sb.AppendFormat("Events queued : {0}\n", eventsQueued);
sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
@ -478,7 +509,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
} }
} }
HandleScriptsAction(cmdparams, HandleShowScript); HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
} }
private void HandleShowScript(IScriptInstance instance) private void HandleShowScript(IScriptInstance instance)
@ -508,10 +539,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
sb.AppendFormat("Script name : {0}\n", instance.ScriptName); sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
sb.AppendFormat("Status : {0}\n", status); sb.AppendFormat("Status : {0}\n", status);
sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
lock (eq) sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
sb.AppendFormat("Queued events : {0}\n", eq.Count);
sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
@ -1018,8 +1047,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
string assembly = ""; string assembly = "";
CultureInfo USCulture = new CultureInfo("en-US"); Culture.SetCurrentCulture();
Thread.CurrentThread.CurrentCulture = USCulture;
Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
@ -1415,8 +1443,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
/// <returns></returns> /// <returns></returns>
private object ProcessEventHandler(object parms) private object ProcessEventHandler(object parms)
{ {
CultureInfo USCulture = new CultureInfo("en-US"); Culture.SetCurrentCulture();
Thread.CurrentThread.CurrentCulture = USCulture;
IScriptInstance instance = (ScriptInstance) parms; IScriptInstance instance = (ScriptInstance) parms;

View File

@ -314,7 +314,7 @@ namespace OpenSim.Services.Connectors.Simulation
try try
{ {
OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 10000, false); OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 30000, false);
bool success = result["success"].AsBoolean(); bool success = result["success"].AsBoolean();
if (result.ContainsKey("_Result")) if (result.ContainsKey("_Result"))
{ {

View File

@ -61,13 +61,13 @@ namespace OpenSim.Services.HypergridService
protected static IGridService m_GridService; protected static IGridService m_GridService;
protected static IPresenceService m_PresenceService; protected static IPresenceService m_PresenceService;
protected static IUserAgentService m_UserAgentService; protected static IUserAgentService m_UserAgentService;
protected static IOfflineIMService m_OfflineIMService;
protected static IInstantMessageSimConnector m_IMSimConnector; protected static IInstantMessageSimConnector m_IMSimConnector;
protected static Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>(); protected static Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>();
private static ExpiringCache<UUID, GridRegion> m_RegionCache; private static ExpiringCache<UUID, GridRegion> m_RegionCache;
private static string m_RestURL;
private static bool m_ForwardOfflineGroupMessages; private static bool m_ForwardOfflineGroupMessages;
private static bool m_InGatekeeper; private static bool m_InGatekeeper;
@ -111,9 +111,14 @@ namespace OpenSim.Services.HypergridService
return; return;
} }
m_RestURL = cnf.GetString("OfflineMessageURL", string.Empty);
m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", false); m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", false);
if (m_InGatekeeper)
{
string offlineIMService = cnf.GetString("OfflineIMService", string.Empty);
if (offlineIMService != string.Empty)
m_OfflineIMService = ServerUtils.LoadPlugin<IOfflineIMService>(offlineIMService, args);
}
} }
} }
@ -329,18 +334,28 @@ namespace OpenSim.Services.HypergridService
private bool UndeliveredMessage(GridInstantMessage im) private bool UndeliveredMessage(GridInstantMessage im)
{ {
if (m_RestURL != string.Empty && (im.offline != 0) if (m_OfflineIMService == null)
&& (!im.fromGroup || (im.fromGroup && m_ForwardOfflineGroupMessages))) return false;
{
// m_log.DebugFormat("[HG IM SERVICE]: Message saved");
return SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
"POST", m_RestURL + "/SaveMessage/", im); im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
} im.dialog != (byte)InstantMessageDialog.GroupNotice &&
else im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
im.dialog != (byte)InstantMessageDialog.InventoryOffered)
{ {
return false; return false;
} }
if (!m_ForwardOfflineGroupMessages)
{
if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
im.dialog == (byte)InstantMessageDialog.GroupInvitation)
return false;
}
// m_log.DebugFormat("[HG IM SERVICE]: Message saved");
string reason = string.Empty;
return m_OfflineIMService.StoreMessage(im, out reason);
} }
} }
} }

View File

@ -0,0 +1,115 @@
/*
* 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 OpenSim.Framework;
using OpenMetaverse;
namespace OpenSim.Services.Interfaces
{
public interface IOfflineIMService
{
List<GridInstantMessage> GetMessages(UUID principalID);
bool StoreMessage(GridInstantMessage im, out string reason);
}
public class OfflineIMDataUtils
{
public static GridInstantMessage GridInstantMessage(Dictionary<string, object> dict)
{
GridInstantMessage im = new GridInstantMessage();
if (dict.ContainsKey("BinaryBucket") && dict["BinaryBucket"] != null)
im.binaryBucket = OpenMetaverse.Utils.HexStringToBytes(dict["BinaryBucket"].ToString(), true);
if (dict.ContainsKey("Dialog") && dict["Dialog"] != null)
im.dialog = byte.Parse(dict["Dialog"].ToString());
if (dict.ContainsKey("FromAgentID") && dict["FromAgentID"] != null)
im.fromAgentID = new Guid(dict["FromAgentID"].ToString());
if (dict.ContainsKey("FromAgentName") && dict["FromAgentName"] != null)
im.fromAgentName = dict["FromAgentName"].ToString();
else
im.fromAgentName = string.Empty;
if (dict.ContainsKey("FromGroup") && dict["FromGroup"] != null)
im.fromGroup = bool.Parse(dict["FromGroup"].ToString());
if (dict.ContainsKey("SessionID") && dict["SessionID"] != null)
im.imSessionID = new Guid(dict["SessionID"].ToString());
if (dict.ContainsKey("Message") && dict["Message"] != null)
im.message = dict["Message"].ToString();
else
im.message = string.Empty;
if (dict.ContainsKey("Offline") && dict["Offline"] != null)
im.offline = byte.Parse(dict["Offline"].ToString());
if (dict.ContainsKey("EstateID") && dict["EstateID"] != null)
im.ParentEstateID = UInt32.Parse(dict["EstateID"].ToString());
if (dict.ContainsKey("Position") && dict["Position"] != null)
im.Position = Vector3.Parse(dict["Position"].ToString());
if (dict.ContainsKey("RegionID") && dict["RegionID"] != null)
im.RegionID = new Guid(dict["RegionID"].ToString());
if (dict.ContainsKey("Timestamp") && dict["Timestamp"] != null)
im.timestamp = UInt32.Parse(dict["Timestamp"].ToString());
if (dict.ContainsKey("ToAgentID") && dict["ToAgentID"] != null)
im.toAgentID = new Guid(dict["ToAgentID"].ToString());
return im;
}
public static Dictionary<string, object> GridInstantMessage(GridInstantMessage im)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["BinaryBucket"] = OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, im.binaryBucket.Length, null);
dict["Dialog"] = im.dialog.ToString();
dict["FromAgentID"] = im.fromAgentID.ToString();
dict["FromAgentName"] = im.fromAgentName == null ? string.Empty : im.fromAgentName;
dict["FromGroup"] = im.fromGroup.ToString();
dict["SessionID"] = im.imSessionID.ToString();
dict["Message"] = im.message == null ? string.Empty : im.message;
dict["Offline"] = im.offline.ToString();
dict["EstateID"] = im.ParentEstateID.ToString();
dict["Position"] = im.Position.ToString();
dict["RegionID"] = im.RegionID.ToString();
dict["Timestamp"] = im.timestamp.ToString();
dict["ToAgentID"] = im.toAgentID.ToString();
return dict;
}
}
}

View File

@ -1,5 +1,5 @@
<configuration> <configuration>
<dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet-2.1.5.0-dotnet-1.dylib" /> <dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet.dylib" />
<dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" /> <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" />
<dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" /> <dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" />
</configuration> </configuration>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2052,7 +2052,7 @@
<Reference name="OpenMetaverseTypes" path="../../../bin/"/> <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/> <Reference name="OpenMetaverse" path="../../../bin/"/>
<Reference name="Nini" path="../../../bin/"/> <Reference name="Nini" path="../../../bin/"/>
<Reference name="Mono.Addins"/> <Reference name="Mono.Addins" path="../../../bin/"/>
<Reference name="log4net" path="../../../bin/"/> <Reference name="log4net" path="../../../bin/"/>
<Files> <Files>
<Match pattern="*.cs" recurse="true"/> <Match pattern="*.cs" recurse="true"/>
@ -2460,7 +2460,7 @@
<Reference name="OpenSim.Framework.Servers.HttpServer"/> <Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Region.Physics.Manager"/> <Reference name="OpenSim.Region.Physics.Manager"/>
<Reference name="Mono.Data.SqliteClient" path="../../../bin/"/> <Reference name="Mono.Data.SqliteClient" path="../../../bin/"/>
<Reference name="Mono.Addins"/> <Reference name="Mono.Addins" path="../../../bin/"/>
<!-- For scripting in funny languages by default --> <!-- For scripting in funny languages by default -->
<Reference name="XMLRPC" path="../../../bin/"/> <Reference name="XMLRPC" path="../../../bin/"/>