Merge branch 'master' into careminster
commit
6ad8d3c43f
|
@ -28,6 +28,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
|
@ -495,42 +496,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
|||
|
||||
protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
|
||||
{
|
||||
foreach (FriendInfo friend in friendList)
|
||||
List<string> friendStringIds = friendList.ConvertAll<string>(friend => friend.Friend);
|
||||
List<string> remoteFriendStringIds = new List<string>();
|
||||
foreach (string friendStringId in friendStringIds)
|
||||
{
|
||||
UUID friendID;
|
||||
if (UUID.TryParse(friend.Friend, out friendID))
|
||||
UUID friendUuid;
|
||||
if (UUID.TryParse(friendStringId, out friendUuid))
|
||||
{
|
||||
// Try local
|
||||
if (LocalStatusNotification(userID, friendID, online))
|
||||
if (LocalStatusNotification(userID, friendUuid, online))
|
||||
continue;
|
||||
|
||||
// The friend is not here [as root]. Let's forward.
|
||||
PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
|
||||
if (friendSessions != null && friendSessions.Length > 0)
|
||||
{
|
||||
PresenceInfo friendSession = null;
|
||||
foreach (PresenceInfo pinfo in friendSessions)
|
||||
{
|
||||
if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad
|
||||
{
|
||||
friendSession = pinfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (friendSession != null)
|
||||
{
|
||||
GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
|
||||
//m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
|
||||
m_FriendsSimConnector.StatusNotify(region, userID, friendID, online);
|
||||
}
|
||||
}
|
||||
|
||||
// Friend is not online. Ignore.
|
||||
remoteFriendStringIds.Add(friendStringId);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friend.Friend);
|
||||
m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friendStringId);
|
||||
}
|
||||
}
|
||||
|
||||
// We do this regrouping so that we can efficiently send a single request rather than one for each
|
||||
// friend in what may be a very large friends list.
|
||||
PresenceInfo[] friendSessions = PresenceService.GetAgents(remoteFriendStringIds.ToArray());
|
||||
|
||||
foreach (PresenceInfo friendSession in friendSessions)
|
||||
{
|
||||
// let's guard against sessions-gone-bad
|
||||
if (friendSession.RegionID != UUID.Zero)
|
||||
{
|
||||
GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
|
||||
//m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
|
||||
m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
|||
{
|
||||
public class DynamicTextureModule : IRegionModule, IDynamicTextureManager
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private const int ALL_SIDES = -1;
|
||||
|
||||
|
|
|
@ -290,7 +290,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
|||
|
||||
foreach (DearchiveContext sceneContext in sceneContexts.Values)
|
||||
{
|
||||
m_log.InfoFormat("[ARCHIVER:] Loading region {0}", sceneContext.Scene.RegionInfo.RegionName);
|
||||
m_log.InfoFormat("[ARCHIVER]: Loading region {0}", sceneContext.Scene.RegionInfo.RegionName);
|
||||
|
||||
if (!m_merge)
|
||||
{
|
||||
|
@ -324,7 +324,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
|||
Util.FireAndForget(delegate(object o)
|
||||
{
|
||||
Thread.Sleep(15000);
|
||||
m_log.Info("Starting scripts in scene objects");
|
||||
m_log.Info("[ARCHIVER]: Starting scripts in scene objects");
|
||||
|
||||
foreach (DearchiveContext sceneContext in sceneContexts.Values)
|
||||
{
|
||||
|
|
|
@ -66,9 +66,9 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
// /// </summary>
|
||||
// private bool m_waitingForObjectAsset;
|
||||
|
||||
public UuidGatherer(IAssetService assetCache)
|
||||
public UuidGatherer(IAssetService assetService)
|
||||
{
|
||||
m_assetService = assetCache;
|
||||
m_assetService = assetService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -146,7 +146,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
|
|||
sb.AppendFormat("Attachments for {0}\n", sp.Name);
|
||||
|
||||
ConsoleDisplayTable ct = new ConsoleDisplayTable() { Indent = 2 };
|
||||
ct.Columns.Add(new ConsoleDisplayTableColumn("Attachment Name", 36));
|
||||
ct.Columns.Add(new ConsoleDisplayTableColumn("Attachment Name", 50));
|
||||
ct.Columns.Add(new ConsoleDisplayTableColumn("Local ID", 10));
|
||||
ct.Columns.Add(new ConsoleDisplayTableColumn("Item ID", 36));
|
||||
ct.Columns.Add(new ConsoleDisplayTableColumn("Attach Point", 14));
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using Mono.Addins;
|
||||
|
@ -36,6 +37,8 @@ using OpenMetaverse.StructuredData;
|
|||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
|
||||
|
||||
namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||
{
|
||||
|
@ -45,6 +48,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
|||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private List<Scene> m_sceneList = new List<Scene>();
|
||||
private IPresenceService m_presenceService;
|
||||
|
||||
private IMessageTransferModule m_msgTransferModule = null;
|
||||
|
||||
|
@ -54,6 +58,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
|||
private bool m_groupMessagingEnabled = false;
|
||||
private bool m_debugEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, module only tries to send group IMs to online users by querying cached presence information.
|
||||
/// </summary>
|
||||
private bool m_messageOnlineAgentsOnly;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for online users.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Group ID is key, presence information for online members is value.
|
||||
/// Will only be non-null if m_messageOnlineAgentsOnly = true
|
||||
/// We cache here so that group messages don't constantly have to re-request the online user list to avoid
|
||||
/// attempted expensive sending of messages to offline users.
|
||||
/// The tradeoff is that a user that comes online will not receive messages consistently from all other users
|
||||
/// until caches have updated.
|
||||
/// Therefore, we set the cache expiry to just 20 seconds.
|
||||
/// </remarks>
|
||||
private ExpiringCache<UUID, PresenceInfo[]> m_usersOnlineCache;
|
||||
|
||||
private int m_usersOnlineCacheExpirySeconds = 20;
|
||||
|
||||
#region IRegionModuleBase Members
|
||||
|
||||
public void Initialise(IConfigSource config)
|
||||
|
@ -83,10 +108,17 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
|||
return;
|
||||
}
|
||||
|
||||
m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false);
|
||||
|
||||
if (m_messageOnlineAgentsOnly)
|
||||
m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>();
|
||||
|
||||
m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true);
|
||||
}
|
||||
|
||||
m_log.Info("[GROUPS-MESSAGING]: GroupsMessagingModule starting up");
|
||||
m_log.InfoFormat(
|
||||
"[GROUPS-MESSAGING]: GroupsMessagingModule enabled with MessageOnlineOnly = {0}, DebugEnabled = {1}",
|
||||
m_messageOnlineAgentsOnly, m_debugEnabled);
|
||||
}
|
||||
|
||||
public void AddRegion(Scene scene)
|
||||
|
@ -126,6 +158,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_presenceService == null)
|
||||
m_presenceService = scene.PresenceService;
|
||||
|
||||
m_sceneList.Add(scene);
|
||||
|
||||
|
@ -207,11 +241,41 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
|||
public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
|
||||
{
|
||||
List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID);
|
||||
int groupMembersCount = groupMembers.Count;
|
||||
|
||||
if (m_messageOnlineAgentsOnly)
|
||||
{
|
||||
string[] t1 = groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()).ToArray();
|
||||
|
||||
// We cache in order not to overwhlem the presence service on large grids with many groups. This does
|
||||
// mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed.
|
||||
// (assuming this is the same across all grid simulators).
|
||||
PresenceInfo[] onlineAgents;
|
||||
if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents))
|
||||
{
|
||||
onlineAgents = m_presenceService.GetAgents(t1);
|
||||
m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds);
|
||||
}
|
||||
|
||||
HashSet<string> onlineAgentsUuidSet = new HashSet<string>();
|
||||
Array.ForEach<PresenceInfo>(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID));
|
||||
|
||||
groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList();
|
||||
|
||||
// if (m_debugEnabled)
|
||||
// m_log.DebugFormat(
|
||||
// "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members, {2} online",
|
||||
// groupID, groupMembersCount, groupMembers.Count());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_debugEnabled)
|
||||
m_log.DebugFormat(
|
||||
"[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members",
|
||||
groupID, groupMembers.Count);
|
||||
}
|
||||
|
||||
int requestStartTick = Environment.TickCount;
|
||||
|
||||
foreach (GroupMembersData member in groupMembers)
|
||||
{
|
||||
|
@ -254,6 +318,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
|||
ProcessMessageFromGroupSession(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary for assessing how long it still takes to send messages to large online groups.
|
||||
if (m_messageOnlineAgentsOnly)
|
||||
m_log.DebugFormat(
|
||||
"[GROUPS-MESSAGING]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms",
|
||||
groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick);
|
||||
}
|
||||
|
||||
#region SimGridEventHandlers
|
||||
|
|
|
@ -123,7 +123,36 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
|||
public void AddRegion(Scene scene)
|
||||
{
|
||||
if (m_groupsEnabled)
|
||||
{
|
||||
scene.RegisterModuleInterface<IGroupsModule>(this);
|
||||
scene.AddCommand(
|
||||
"debug",
|
||||
this,
|
||||
"debug groups verbose",
|
||||
"debug groups verbose <true|false>",
|
||||
"This setting turns on very verbose groups debugging",
|
||||
HandleDebugGroupsVerbose);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDebugGroupsVerbose(object modules, string[] args)
|
||||
{
|
||||
if (args.Length < 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
|
||||
return;
|
||||
}
|
||||
|
||||
bool verbose = false;
|
||||
if (!bool.TryParse(args[3], out verbose))
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug groups verbose <true|false>");
|
||||
return;
|
||||
}
|
||||
|
||||
m_debugEnabled = verbose;
|
||||
|
||||
MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled);
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene scene)
|
||||
|
|
|
@ -41,8 +41,6 @@ public class BSCharacter : BSPhysObject
|
|||
|
||||
// private bool _stopped;
|
||||
private OMV.Vector3 _size;
|
||||
private OMV.Vector3 _scale;
|
||||
private PrimitiveBaseShape _pbs;
|
||||
private bool _grabbed;
|
||||
private bool _selected;
|
||||
private OMV.Vector3 _position;
|
||||
|
@ -67,6 +65,10 @@ public class BSCharacter : BSPhysObject
|
|||
private bool _kinematic;
|
||||
private float _buoyancy;
|
||||
|
||||
// The friction and velocity of the avatar is modified depending on whether walking or not.
|
||||
private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
|
||||
private float _currentFriction; // the friction currently being used (changed by setVelocity).
|
||||
|
||||
private OMV.Vector3 _PIDTarget;
|
||||
private bool _usePID;
|
||||
private float _PIDTau;
|
||||
|
@ -84,14 +86,18 @@ public class BSCharacter : BSPhysObject
|
|||
_flying = isFlying;
|
||||
_orientation = OMV.Quaternion.Identity;
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
_appliedVelocity = OMV.Vector3.Zero;
|
||||
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
||||
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
||||
_avatarDensity = PhysicsScene.Params.avatarDensity;
|
||||
|
||||
// The dimensions of the avatar capsule are kept in the scale.
|
||||
// Physics creates a unit capsule which is scaled by the physics engine.
|
||||
ComputeAvatarScale(_size);
|
||||
_avatarDensity = PhysicsScene.Params.avatarDensity;
|
||||
// set _avatarVolume and _mass based on capsule size, _density and _scale
|
||||
// set _avatarVolume and _mass based on capsule size, _density and Scale
|
||||
ComputeAvatarVolumeAndMass();
|
||||
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
||||
LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw);
|
||||
|
||||
ShapeData shapeData = new ShapeData();
|
||||
shapeData.ID = LocalID;
|
||||
|
@ -99,28 +105,22 @@ public class BSCharacter : BSPhysObject
|
|||
shapeData.Position = _position;
|
||||
shapeData.Rotation = _orientation;
|
||||
shapeData.Velocity = _velocity;
|
||||
shapeData.Scale = _scale;
|
||||
shapeData.Size = Scale;
|
||||
shapeData.Scale = Scale;
|
||||
shapeData.Mass = _mass;
|
||||
shapeData.Buoyancy = _buoyancy;
|
||||
shapeData.Static = ShapeData.numericFalse;
|
||||
shapeData.Friction = PhysicsScene.Params.avatarFriction;
|
||||
shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
|
||||
shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
|
||||
|
||||
// do actual create at taint time
|
||||
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.create,taint", LocalID);
|
||||
BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);
|
||||
// New body and shape into BSBody and BSShape
|
||||
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null);
|
||||
|
||||
// Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
|
||||
// If not set at creation, the avatar will stop flying when created after crossing a region boundry.
|
||||
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
|
||||
|
||||
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));
|
||||
|
||||
// This works here because CreateObject has already put the character into the physical world.
|
||||
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
|
||||
(uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
|
||||
SetPhysicalProperties();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -131,53 +131,85 @@ public class BSCharacter : BSPhysObject
|
|||
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
||||
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
|
||||
{
|
||||
BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
|
||||
PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
|
||||
PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetPhysicalProperties()
|
||||
{
|
||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||
|
||||
ZeroMotion();
|
||||
ForcePosition = _position;
|
||||
// Set the velocity and compute the proper friction
|
||||
ForceVelocity = _velocity;
|
||||
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
|
||||
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
|
||||
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
}
|
||||
|
||||
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
|
||||
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
|
||||
|
||||
BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
|
||||
|
||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||
|
||||
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
|
||||
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||
|
||||
// Do this after the object has been added to the world
|
||||
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
|
||||
(uint)CollisionFilterGroups.AvatarFilter,
|
||||
(uint)CollisionFilterGroups.AvatarMask);
|
||||
}
|
||||
|
||||
public override void RequestPhysicsterseUpdate()
|
||||
{
|
||||
base.RequestPhysicsterseUpdate();
|
||||
}
|
||||
// No one calls this method so I don't know what it could possibly mean
|
||||
public override bool Stopped {
|
||||
get { return false; }
|
||||
}
|
||||
public override bool Stopped { get { return false; } }
|
||||
public override OMV.Vector3 Size {
|
||||
get
|
||||
{
|
||||
// Avatar capsule size is kept in the scale parameter.
|
||||
return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
|
||||
return _size;
|
||||
}
|
||||
|
||||
set {
|
||||
// When an avatar's size is set, only the height is changed
|
||||
// and that really only depends on the radius.
|
||||
// When an avatar's size is set, only the height is changed.
|
||||
_size = value;
|
||||
ComputeAvatarScale(_size);
|
||||
|
||||
// TODO: something has to be done with the avatar's vertical position
|
||||
|
||||
ComputeAvatarVolumeAndMass();
|
||||
DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
|
||||
LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw);
|
||||
|
||||
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
|
||||
{
|
||||
BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true);
|
||||
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
|
||||
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
|
||||
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
public override PrimitiveBaseShape Shape {
|
||||
set { _pbs = value;
|
||||
}
|
||||
public override OMV.Vector3 Scale { get; set; }
|
||||
public override PrimitiveBaseShape Shape
|
||||
{
|
||||
set { BaseShape = value; }
|
||||
}
|
||||
|
||||
public override bool Grabbed {
|
||||
set { _grabbed = value;
|
||||
}
|
||||
set { _grabbed = value; }
|
||||
}
|
||||
public override bool Selected {
|
||||
set { _selected = value;
|
||||
}
|
||||
set { _selected = value; }
|
||||
}
|
||||
public override void CrossingFailure() { return; }
|
||||
public override void link(PhysicsActor obj) { return; }
|
||||
|
@ -204,7 +236,7 @@ public class BSCharacter : BSPhysObject
|
|||
|
||||
public override OMV.Vector3 Position {
|
||||
get {
|
||||
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
||||
// _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
|
||||
return _position;
|
||||
}
|
||||
set {
|
||||
|
@ -214,7 +246,7 @@ public class BSCharacter : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -263,7 +295,7 @@ public class BSCharacter : BSPhysObject
|
|||
// A version of the sanity check that also makes sure a new position value is
|
||||
// pushed back to the physics engine. This routine would be used by anyone
|
||||
// who is not already pushing the value.
|
||||
private bool PositionSanityCheck2(bool inTaintTime)
|
||||
private bool PositionSanityCheck(bool inTaintTime)
|
||||
{
|
||||
bool ret = false;
|
||||
if (PositionSanityCheck())
|
||||
|
@ -273,7 +305,7 @@ public class BSCharacter : BSPhysObject
|
|||
BSScene.TaintCallback sanityOperation = delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
||||
};
|
||||
if (inTaintTime)
|
||||
sanityOperation();
|
||||
|
@ -284,11 +316,7 @@ public class BSCharacter : BSPhysObject
|
|||
return ret;
|
||||
}
|
||||
|
||||
public override float Mass {
|
||||
get {
|
||||
return _mass;
|
||||
}
|
||||
}
|
||||
public override float Mass { get { return _mass; } }
|
||||
|
||||
// used when we only want this prim's mass and not the linkset thing
|
||||
public override float MassRaw { get {return _mass; } }
|
||||
|
@ -301,15 +329,13 @@ public class BSCharacter : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
||||
BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
|
||||
BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override int VehicleType {
|
||||
get { return 0; }
|
||||
set { return; }
|
||||
}
|
||||
// Avatars don't do vehicles
|
||||
public override int VehicleType { get { return 0; } set { return; } }
|
||||
public override void VehicleFloatParam(int param, float value) { }
|
||||
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
|
||||
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
|
||||
|
@ -328,15 +354,37 @@ public class BSCharacter : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
||||
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
|
||||
ForceVelocity = _velocity;
|
||||
});
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 ForceVelocity {
|
||||
get { return _velocity; }
|
||||
set {
|
||||
// Depending on whether the avatar is moving or not, change the friction
|
||||
// to keep the avatar from slipping around
|
||||
if (_velocity.Length() == 0)
|
||||
{
|
||||
if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
|
||||
{
|
||||
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
||||
BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentFriction != PhysicsScene.Params.avatarFriction)
|
||||
{
|
||||
_currentFriction = PhysicsScene.Params.avatarFriction;
|
||||
BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
|
||||
}
|
||||
}
|
||||
_velocity = value;
|
||||
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
|
||||
// Remember the set velocity so we can suppress the reduction by friction, ...
|
||||
_appliedVelocity = value;
|
||||
|
||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
|
||||
BulletSimAPI.Activate2(BSBody.ptr, true);
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 Torque {
|
||||
|
@ -360,8 +408,8 @@ public class BSCharacter : BSPhysObject
|
|||
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
|
||||
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
||||
{
|
||||
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
|
||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -389,12 +437,18 @@ public class BSCharacter : BSPhysObject
|
|||
set { _isPhysical = value;
|
||||
}
|
||||
}
|
||||
public override bool IsSolid {
|
||||
get { return true; }
|
||||
}
|
||||
public override bool IsStatic {
|
||||
get { return false; }
|
||||
}
|
||||
public override bool Flying {
|
||||
get { return _flying; }
|
||||
set {
|
||||
_flying = value;
|
||||
// simulate flying by changing the effect of gravity
|
||||
this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
|
||||
Buoyancy = ComputeBuoyancyFromFlying(_flying);
|
||||
}
|
||||
}
|
||||
// Flying is implimented by changing the avatar's buoyancy.
|
||||
|
@ -454,10 +508,19 @@ public class BSCharacter : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
|
||||
ForceBuoyancy = _buoyancy;
|
||||
});
|
||||
}
|
||||
}
|
||||
public override float ForceBuoyancy {
|
||||
get { return _buoyancy; }
|
||||
set { _buoyancy = value;
|
||||
DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||
// Buoyancy is faked by changing the gravity applied to the object
|
||||
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
|
||||
BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
|
||||
}
|
||||
}
|
||||
|
||||
// Used for MoveTo
|
||||
public override OMV.Vector3 PIDTarget {
|
||||
|
@ -518,27 +581,32 @@ public class BSCharacter : BSPhysObject
|
|||
|
||||
private void ComputeAvatarScale(OMV.Vector3 size)
|
||||
{
|
||||
_scale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
||||
_scale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
||||
// The 'size' given by the simulator is the mid-point of the avatar
|
||||
// and X and Y are unspecified.
|
||||
|
||||
// The 1.15 came from ODE but it seems to cause the avatar to float off the ground
|
||||
// _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
|
||||
_scale.Z = (_size.Z) - (_scale.X + _scale.Y);
|
||||
OMV.Vector3 newScale = OMV.Vector3.Zero;
|
||||
newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
||||
newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
||||
|
||||
// From the total height, remote the capsule half spheres that are at each end
|
||||
newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y);
|
||||
// newScale.Z = (size.Z * 2f);
|
||||
Scale = newScale;
|
||||
}
|
||||
|
||||
// set _avatarVolume and _mass based on capsule size, _density and _scale
|
||||
// set _avatarVolume and _mass based on capsule size, _density and Scale
|
||||
private void ComputeAvatarVolumeAndMass()
|
||||
{
|
||||
_avatarVolume = (float)(
|
||||
Math.PI
|
||||
* _scale.X
|
||||
* _scale.Y // the area of capsule cylinder
|
||||
* _scale.Z // times height of capsule cylinder
|
||||
* Scale.X
|
||||
* Scale.Y // the area of capsule cylinder
|
||||
* Scale.Z // times height of capsule cylinder
|
||||
+ 1.33333333f
|
||||
* Math.PI
|
||||
* _scale.X
|
||||
* Math.Min(_scale.X, _scale.Y)
|
||||
* _scale.Y // plus the volume of the capsule end caps
|
||||
* Scale.X
|
||||
* Math.Min(Scale.X, Scale.Y)
|
||||
* Scale.Y // plus the volume of the capsule end caps
|
||||
);
|
||||
_mass = _avatarDensity * _avatarVolume;
|
||||
}
|
||||
|
@ -553,7 +621,23 @@ public class BSCharacter : BSPhysObject
|
|||
_acceleration = entprop.Acceleration;
|
||||
_rotationalVelocity = entprop.RotationalVelocity;
|
||||
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
||||
PositionSanityCheck2(true);
|
||||
PositionSanityCheck(true);
|
||||
|
||||
// remember the current and last set values
|
||||
LastEntityProperties = CurrentEntityProperties;
|
||||
CurrentEntityProperties = entprop;
|
||||
|
||||
if (entprop.Velocity != LastEntityProperties.Velocity)
|
||||
{
|
||||
// Changes in the velocity are suppressed in avatars.
|
||||
// That's just the way they are defined.
|
||||
OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
|
||||
_velocity = avVel;
|
||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
|
||||
}
|
||||
|
||||
// Tell the linkset about this
|
||||
Linkset.UpdateProperties(this);
|
||||
|
||||
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
||||
// base.RequestPhysicsterseUpdate();
|
||||
|
|
|
@ -47,6 +47,7 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
TypeName = typeName;
|
||||
|
||||
Linkset = new BSLinkset(PhysicsScene, this);
|
||||
LastAssetBuildFailed = false;
|
||||
|
||||
CollisionCollection = new CollisionEventUpdate();
|
||||
SubscribedEventsMs = 0;
|
||||
|
@ -69,6 +70,23 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
// Reference to the physical shape (btCollisionShape) of this object
|
||||
public BulletShape BSShape;
|
||||
|
||||
// 'true' if the mesh's underlying asset failed to build.
|
||||
// This will keep us from looping after the first time the build failed.
|
||||
public bool LastAssetBuildFailed { get; set; }
|
||||
|
||||
// The objects base shape information. Null if not a prim type shape.
|
||||
public PrimitiveBaseShape BaseShape { get; protected set; }
|
||||
|
||||
// When the physical properties are updated, an EntityProperty holds the update values.
|
||||
// Keep the current and last EntityProperties to enable computation of differences
|
||||
// between the current update and the previous values.
|
||||
public EntityProperties CurrentEntityProperties { get; set; }
|
||||
public EntityProperties LastEntityProperties { get; set; }
|
||||
|
||||
public abstract OMV.Vector3 Scale { get; set; }
|
||||
public abstract bool IsSolid { get; }
|
||||
public abstract bool IsStatic { get; }
|
||||
|
||||
// Stop all physical motion.
|
||||
public abstract void ZeroMotion();
|
||||
|
||||
|
@ -89,6 +107,10 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
|
||||
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
|
||||
|
||||
public abstract float ForceBuoyancy { get; set; }
|
||||
|
||||
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
|
||||
|
||||
#region Collisions
|
||||
|
||||
// Requested number of milliseconds between collision events. Zero means disabled.
|
||||
|
@ -129,30 +151,28 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
// if someone has subscribed for collision events....
|
||||
if (SubscribedEvents()) {
|
||||
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
||||
// DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
||||
// LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
||||
DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
||||
LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
||||
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Routine to send the collected collisions into the simulator.
|
||||
// Also handles removal of this from the collection of objects with collisions if
|
||||
// there are no collisions from this object. Mechanism is create one last
|
||||
// collision event to make collision_end work.
|
||||
// Send the collected collisions into the simulator.
|
||||
// Called at taint time from within the Step() function thus no locking problems
|
||||
// with CollisionCollection and ObjectsWithNoMoreCollisions.
|
||||
// Return 'true' if there were some actual collisions passed up
|
||||
public virtual bool SendCollisions()
|
||||
{
|
||||
bool ret = true;
|
||||
// If the 'no collision' call, force it to happen right now so quick collision_end
|
||||
bool force = CollisionCollection.Count == 0;
|
||||
|
||||
// throttle the collisions to the number of milliseconds specified in the subscription
|
||||
int nowTime = PhysicsScene.SimulationNowTime;
|
||||
if (nowTime >= NextCollisionOkTime)
|
||||
if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
|
||||
{
|
||||
NextCollisionOkTime = nowTime + SubscribedEventsMs;
|
||||
NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
|
||||
|
||||
// We are called if we previously had collisions. If there are no collisions
|
||||
// this time, send up one last empty event so OpenSim can sense collision end.
|
||||
|
|
|
@ -46,12 +46,10 @@ public sealed class BSPrim : BSPhysObject
|
|||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly string LogHeader = "[BULLETS PRIM]";
|
||||
|
||||
private PrimitiveBaseShape _pbs;
|
||||
|
||||
// _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
|
||||
// Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
|
||||
// _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
|
||||
// Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
|
||||
private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
|
||||
private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
|
||||
// private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
|
||||
|
||||
private bool _grabbed;
|
||||
private bool _isSelected;
|
||||
|
@ -98,12 +96,12 @@ public sealed class BSPrim : BSPhysObject
|
|||
_physicsActorType = (int)ActorTypes.Prim;
|
||||
_position = pos;
|
||||
_size = size;
|
||||
_scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
|
||||
Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
|
||||
_orientation = rotation;
|
||||
_buoyancy = 1f;
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
_rotationalVelocity = OMV.Vector3.Zero;
|
||||
_pbs = pbs;
|
||||
BaseShape = pbs;
|
||||
_isPhysical = pisPhysical;
|
||||
_isVolumeDetect = false;
|
||||
_friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
|
||||
|
@ -160,32 +158,31 @@ public sealed class BSPrim : BSPhysObject
|
|||
get { return _size; }
|
||||
set {
|
||||
_size = value;
|
||||
PhysicsScene.TaintedObject("BSPrim.setSize", delegate()
|
||||
{
|
||||
_mass = CalculateMass(); // changing size changes the mass
|
||||
// Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
|
||||
// scale and margins are set.
|
||||
CreateGeomAndObject(true);
|
||||
// DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
|
||||
});
|
||||
ForceBodyShapeRebuild(false);
|
||||
}
|
||||
}
|
||||
// Scale is what we set in the physics engine. It is different than 'size' in that
|
||||
// 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
|
||||
public OMV.Vector3 Scale
|
||||
{
|
||||
get { return _scale; }
|
||||
set { _scale = value; }
|
||||
}
|
||||
public override OMV.Vector3 Scale { get; set; }
|
||||
|
||||
public override PrimitiveBaseShape Shape {
|
||||
set {
|
||||
_pbs = value;
|
||||
PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
|
||||
BaseShape = value;
|
||||
ForceBodyShapeRebuild(false);
|
||||
}
|
||||
}
|
||||
public override bool ForceBodyShapeRebuild(bool inTaintTime)
|
||||
{
|
||||
BSScene.TaintCallback rebuildOperation = delegate()
|
||||
{
|
||||
_mass = CalculateMass(); // changing the shape changes the mass
|
||||
CreateGeomAndObject(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
if (inTaintTime)
|
||||
rebuildOperation();
|
||||
else
|
||||
PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
|
||||
return true;
|
||||
}
|
||||
public override bool Grabbed {
|
||||
set { _grabbed = value;
|
||||
|
@ -325,9 +322,9 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
|
||||
// A version of the sanity check that also makes sure a new position value is
|
||||
// pushed back to the physics engine. This routine would be used by anyone
|
||||
// pushed to the physics engine. This routine would be used by anyone
|
||||
// who is not already pushing the value.
|
||||
private bool PositionSanityCheck2(bool inTaintTime)
|
||||
private bool PositionSanityCheck(bool inTaintTime)
|
||||
{
|
||||
bool ret = false;
|
||||
if (PositionSanityCheck())
|
||||
|
@ -337,7 +334,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
BSScene.TaintCallback sanityOperation = delegate()
|
||||
{
|
||||
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||
ForcePosition = _position;
|
||||
};
|
||||
if (inTaintTime)
|
||||
sanityOperation();
|
||||
|
@ -547,13 +544,13 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
|
||||
// An object is static (does not move) if selected or not physical
|
||||
private bool IsStatic
|
||||
public override bool IsStatic
|
||||
{
|
||||
get { return _isSelected || !IsPhysical; }
|
||||
}
|
||||
|
||||
// An object is solid if it's not phantom and if it's not doing VolumeDetect
|
||||
public bool IsSolid
|
||||
public override bool IsSolid
|
||||
{
|
||||
get { return !IsPhantom && !_isVolumeDetect; }
|
||||
}
|
||||
|
@ -631,6 +628,12 @@ public sealed class BSPrim : BSPhysObject
|
|||
BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
|
||||
// There is no inertia in a static object
|
||||
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
|
||||
// Set collision detection parameters
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
}
|
||||
// There can be special things needed for implementing linksets
|
||||
Linkset.MakeStatic(this);
|
||||
// The activation state is 'disabled' so Bullet will not try to act on it.
|
||||
|
@ -662,6 +665,13 @@ public sealed class BSPrim : BSPhysObject
|
|||
BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
|
||||
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
|
||||
|
||||
// Set collision detection parameters
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
}
|
||||
|
||||
// Various values for simulation limits
|
||||
BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
|
||||
BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
|
||||
|
@ -813,11 +823,18 @@ public sealed class BSPrim : BSPhysObject
|
|||
_buoyancy = value;
|
||||
PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
|
||||
{
|
||||
// DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||
ForceBuoyancy = _buoyancy;
|
||||
});
|
||||
}
|
||||
}
|
||||
public override float ForceBuoyancy {
|
||||
get { return _buoyancy; }
|
||||
set {
|
||||
_buoyancy = value;
|
||||
// DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||
// Buoyancy is faked by changing the gravity applied to the object
|
||||
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
|
||||
BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -907,19 +924,19 @@ public sealed class BSPrim : BSPhysObject
|
|||
float tmp;
|
||||
|
||||
float returnMass = 0;
|
||||
float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
|
||||
float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
|
||||
float hollowVolume = hollowAmount * hollowAmount;
|
||||
|
||||
switch (_pbs.ProfileShape)
|
||||
switch (BaseShape.ProfileShape)
|
||||
{
|
||||
case ProfileShape.Square:
|
||||
// default box
|
||||
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||
{
|
||||
if (hollowAmount > 0.0)
|
||||
{
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Square:
|
||||
case HollowShape.Same:
|
||||
|
@ -943,19 +960,19 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
}
|
||||
|
||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||
else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||
{
|
||||
//a tube
|
||||
|
||||
volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
|
||||
tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
|
||||
volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
|
||||
tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
|
||||
volume -= volume*tmp*tmp;
|
||||
|
||||
if (hollowAmount > 0.0)
|
||||
{
|
||||
hollowVolume *= hollowAmount;
|
||||
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Square:
|
||||
case HollowShape.Same:
|
||||
|
@ -980,13 +997,13 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
case ProfileShape.Circle:
|
||||
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||
{
|
||||
volume *= 0.78539816339f; // elipse base
|
||||
|
||||
if (hollowAmount > 0.0)
|
||||
{
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Same:
|
||||
case HollowShape.Circle:
|
||||
|
@ -1008,10 +1025,10 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
}
|
||||
|
||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||
else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||
{
|
||||
volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
|
||||
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
||||
volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
|
||||
tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
|
||||
volume *= (1.0f - tmp * tmp);
|
||||
|
||||
if (hollowAmount > 0.0)
|
||||
|
@ -1020,7 +1037,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
// calculate the hollow volume by it's shape compared to the prim shape
|
||||
hollowVolume *= hollowAmount;
|
||||
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Same:
|
||||
case HollowShape.Circle:
|
||||
|
@ -1044,7 +1061,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
break;
|
||||
|
||||
case ProfileShape.HalfCircle:
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||
{
|
||||
volume *= 0.52359877559829887307710723054658f;
|
||||
}
|
||||
|
@ -1052,7 +1069,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
case ProfileShape.EquilateralTriangle:
|
||||
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||
{
|
||||
volume *= 0.32475953f;
|
||||
|
||||
|
@ -1060,7 +1077,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
{
|
||||
|
||||
// calculate the hollow volume by it's shape compared to the prim shape
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Same:
|
||||
case HollowShape.Triangle:
|
||||
|
@ -1085,11 +1102,11 @@ public sealed class BSPrim : BSPhysObject
|
|||
volume *= (1.0f - hollowVolume);
|
||||
}
|
||||
}
|
||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||
else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||
{
|
||||
volume *= 0.32475953f;
|
||||
volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
|
||||
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
||||
volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
|
||||
tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
|
||||
volume *= (1.0f - tmp * tmp);
|
||||
|
||||
if (hollowAmount > 0.0)
|
||||
|
@ -1097,7 +1114,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
hollowVolume *= hollowAmount;
|
||||
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Same:
|
||||
case HollowShape.Triangle:
|
||||
|
@ -1137,26 +1154,26 @@ public sealed class BSPrim : BSPhysObject
|
|||
float profileBegin;
|
||||
float profileEnd;
|
||||
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
|
||||
{
|
||||
taperX1 = _pbs.PathScaleX * 0.01f;
|
||||
taperX1 = BaseShape.PathScaleX * 0.01f;
|
||||
if (taperX1 > 1.0f)
|
||||
taperX1 = 2.0f - taperX1;
|
||||
taperX = 1.0f - taperX1;
|
||||
|
||||
taperY1 = _pbs.PathScaleY * 0.01f;
|
||||
taperY1 = BaseShape.PathScaleY * 0.01f;
|
||||
if (taperY1 > 1.0f)
|
||||
taperY1 = 2.0f - taperY1;
|
||||
taperY = 1.0f - taperY1;
|
||||
}
|
||||
else
|
||||
{
|
||||
taperX = _pbs.PathTaperX * 0.01f;
|
||||
taperX = BaseShape.PathTaperX * 0.01f;
|
||||
if (taperX < 0.0f)
|
||||
taperX = -taperX;
|
||||
taperX1 = 1.0f - taperX;
|
||||
|
||||
taperY = _pbs.PathTaperY * 0.01f;
|
||||
taperY = BaseShape.PathTaperY * 0.01f;
|
||||
if (taperY < 0.0f)
|
||||
taperY = -taperY;
|
||||
taperY1 = 1.0f - taperY;
|
||||
|
@ -1166,13 +1183,13 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
|
||||
|
||||
pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
|
||||
pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
|
||||
pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
|
||||
pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
|
||||
volume *= (pathEnd - pathBegin);
|
||||
|
||||
// this is crude aproximation
|
||||
profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
|
||||
profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
|
||||
profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
|
||||
profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
|
||||
volume *= (profileEnd - profileBegin);
|
||||
|
||||
returnMass = _density * volume;
|
||||
|
@ -1207,7 +1224,8 @@ public sealed class BSPrim : BSPhysObject
|
|||
shape.Position = _position;
|
||||
shape.Rotation = _orientation;
|
||||
shape.Velocity = _velocity;
|
||||
shape.Scale = _scale;
|
||||
shape.Size = _size;
|
||||
shape.Scale = Scale;
|
||||
shape.Mass = _isPhysical ? _mass : 0f;
|
||||
shape.Buoyancy = _buoyancy;
|
||||
shape.HullKey = 0;
|
||||
|
@ -1217,7 +1235,6 @@ public sealed class BSPrim : BSPhysObject
|
|||
shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
|
||||
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
|
||||
shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
|
||||
shape.Size = _size;
|
||||
}
|
||||
// Rebuild the geometry and object.
|
||||
// This is called when the shape changes so we need to recreate the mesh/hull.
|
||||
|
@ -1234,7 +1251,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
// Create the correct physical representation for this type of object.
|
||||
// Updates BSBody and BSShape with the new information.
|
||||
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
|
||||
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, _pbs,
|
||||
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
|
||||
null, delegate(BulletBody dBody)
|
||||
{
|
||||
// Called if the current prim body is about to be destroyed.
|
||||
|
@ -1328,9 +1345,11 @@ public sealed class BSPrim : BSPhysObject
|
|||
_acceleration = entprop.Acceleration;
|
||||
_rotationalVelocity = entprop.RotationalVelocity;
|
||||
|
||||
PositionSanityCheck2(true);
|
||||
// remember the current and last set values
|
||||
LastEntityProperties = CurrentEntityProperties;
|
||||
CurrentEntityProperties = entprop;
|
||||
|
||||
Linkset.UpdateProperties(this);
|
||||
PositionSanityCheck(true);
|
||||
|
||||
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
||||
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
|
||||
|
@ -1348,6 +1367,9 @@ public sealed class BSPrim : BSPhysObject
|
|||
entprop.Acceleration, entprop.RotationalVelocity);
|
||||
}
|
||||
*/
|
||||
// The linkset implimentation might want to know about this.
|
||||
|
||||
Linkset.UpdateProperties(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -256,14 +256,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||
|
||||
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
|
||||
WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
|
||||
World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
|
||||
m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
|
||||
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
|
||||
m_DebugLogCallbackHandle);
|
||||
|
||||
// Initialization to support the transition to a new API which puts most of the logic
|
||||
// into the C# code so it is easier to modify and add to.
|
||||
World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
|
||||
m_DebugLogCallbackHandle));
|
||||
|
||||
Constraints = new BSConstraintCollection(World);
|
||||
|
||||
|
@ -360,7 +356,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
|
||||
// Anything left in the unmanaged code should be cleaned out
|
||||
BulletSimAPI.Shutdown(WorldID);
|
||||
BulletSimAPI.Shutdown2(World.ptr);
|
||||
|
||||
// Not logging any more
|
||||
PhysicsLogging.Close();
|
||||
|
@ -498,7 +494,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
{
|
||||
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
|
||||
|
||||
numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
|
||||
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
|
||||
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
|
||||
|
||||
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
|
||||
|
@ -536,19 +532,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
}
|
||||
|
||||
// This is a kludge to get avatar movement updates.
|
||||
// the simulator expects collisions for avatars even if there are have been no collisions. This updates
|
||||
// avatar animations and stuff.
|
||||
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
|
||||
foreach (BSPhysObject bsp in m_avatars)
|
||||
bsp.SendCollisions();
|
||||
|
||||
// The above SendCollision's batch up the collisions on the objects.
|
||||
// Now push the collisions into the simulator.
|
||||
if (ObjectsWithCollisions.Count > 0)
|
||||
{
|
||||
foreach (BSPhysObject bsp in ObjectsWithCollisions)
|
||||
if (!m_avatars.Contains(bsp)) // don't call avatars twice
|
||||
if (!bsp.SendCollisions())
|
||||
{
|
||||
// If the object is done colliding, see that it's removed from the colliding list
|
||||
|
@ -556,6 +544,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
}
|
||||
|
||||
// This is a kludge to get avatar movement updates.
|
||||
// The simulator expects collisions for avatars even if there are have been no collisions.
|
||||
// The event updates avatar animations and stuff.
|
||||
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
|
||||
foreach (BSPhysObject bsp in m_avatars)
|
||||
if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
|
||||
bsp.SendCollisions();
|
||||
|
||||
// Objects that are done colliding are removed from the ObjectsWithCollisions list.
|
||||
// Not done above because it is inside an iteration of ObjectWithCollisions.
|
||||
if (ObjectsWithNoMoreCollisions.Count > 0)
|
||||
|
@ -579,11 +575,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
}
|
||||
|
||||
// This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
|
||||
// Only enable this in a limited test world with few objects.
|
||||
// BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
|
||||
|
||||
// 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.
|
||||
// We multiply by 45 to give a recognizable running rate (45 or less).
|
||||
return numSubSteps * m_fixedTimeStep * 1000 * 45;
|
||||
// return timeStep * 1000 * 45;
|
||||
// We multiply by 55 to give a recognizable running rate (55 or less).
|
||||
return numSubSteps * m_fixedTimeStep * 1000 * 55;
|
||||
// return timeStep * 1000 * 55;
|
||||
}
|
||||
|
||||
// Something has collided
|
||||
|
@ -800,6 +800,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
|
||||
delegate float ParamGet(BSScene scene);
|
||||
delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
|
||||
delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
|
||||
|
||||
private struct ParameterDefn
|
||||
{
|
||||
|
@ -809,6 +810,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
public ParamUser userParam; // get the value from the configuration file
|
||||
public ParamGet getter; // return the current value stored for this parameter
|
||||
public ParamSet setter; // set the current value for this parameter
|
||||
public SetOnObject onObject; // set the value on an object in the physical domain
|
||||
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
|
||||
{
|
||||
name = n;
|
||||
|
@ -817,6 +819,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
userParam = u;
|
||||
getter = g;
|
||||
setter = s;
|
||||
onObject = null;
|
||||
}
|
||||
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
|
||||
{
|
||||
name = n;
|
||||
desc = d;
|
||||
defaultValue = v;
|
||||
userParam = u;
|
||||
getter = g;
|
||||
setter = s;
|
||||
onObject = o;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -838,6 +851,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
//
|
||||
// The single letter parameters for the delegates are:
|
||||
// s = BSScene
|
||||
// o = BSPhysObject
|
||||
// p = string parameter name
|
||||
// l = localID of referenced object
|
||||
// v = float value
|
||||
|
@ -947,70 +961,84 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
-9.80665f,
|
||||
(s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].gravity; },
|
||||
(s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
|
||||
|
||||
|
||||
new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linearDamping; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
|
||||
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].angularDamping; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
|
||||
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
|
||||
0.2f,
|
||||
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].deactivationTime; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.BSBody.ptr, v); } ),
|
||||
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
|
||||
0.8f,
|
||||
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linearSleepingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
|
||||
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
|
||||
1.0f,
|
||||
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].angularSleepingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
|
||||
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
|
||||
0f, // set to zero to disable
|
||||
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].ccdMotionThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.BSBody.ptr, v); } ),
|
||||
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetCcdSweepSphereRadius2(o.BSBody.ptr, v); } ),
|
||||
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
|
||||
0.1f,
|
||||
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].contactProcessingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.BSBody.ptr, v); } ),
|
||||
|
||||
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
|
||||
0.5f,
|
||||
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].terrainFriction; },
|
||||
(s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ),
|
||||
(s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
|
||||
new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
|
||||
0.8f,
|
||||
(s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].terrainHitFraction; },
|
||||
(s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ),
|
||||
(s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
|
||||
new ParameterDefn("TerrainRestitution", "Bouncyness" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].terrainRestitution; },
|
||||
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
|
||||
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
|
||||
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
|
||||
0.2f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarFriction; },
|
||||
(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.",
|
||||
10f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarStandingFriction; },
|
||||
(s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
|
||||
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
|
||||
60f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
|
||||
|
@ -1227,52 +1255,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
return ret;
|
||||
}
|
||||
|
||||
// check to see if we are updating a parameter for a particular or all of the prims
|
||||
protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val)
|
||||
{
|
||||
List<uint> operateOn;
|
||||
lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
|
||||
UpdateParameterSet(operateOn, ref loc, parm, localID, val);
|
||||
}
|
||||
|
||||
// update all the localIDs specified
|
||||
// If the local ID is APPLY_TO_NONE, just change the default value
|
||||
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
|
||||
// If the localID is a specific object, apply the parameter change to only that object
|
||||
protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
|
||||
protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
|
||||
{
|
||||
List<uint> objectIDs = new List<uint>();
|
||||
switch (localID)
|
||||
{
|
||||
case PhysParameterEntry.APPLY_TO_NONE:
|
||||
defaultLoc = val; // setting only the default value
|
||||
// This will cause a call into the physical world if some operation is specified (SetOnObject).
|
||||
objectIDs.Add(TERRAIN_ID);
|
||||
TaintedUpdateParameter(parm, objectIDs, val);
|
||||
break;
|
||||
case PhysParameterEntry.APPLY_TO_ALL:
|
||||
defaultLoc = val; // setting ALL also sets the default value
|
||||
List<uint> objectIDs = lIDs;
|
||||
string xparm = parm.ToLower();
|
||||
float xval = val;
|
||||
TaintedObject("BSScene.UpdateParameterSet", delegate() {
|
||||
foreach (uint lID in objectIDs)
|
||||
{
|
||||
BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
|
||||
}
|
||||
});
|
||||
lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
|
||||
TaintedUpdateParameter(parm, objectIDs, val);
|
||||
break;
|
||||
default:
|
||||
// setting only one localID
|
||||
TaintedUpdateParameter(parm, localID, val);
|
||||
objectIDs.Add(localID);
|
||||
TaintedUpdateParameter(parm, objectIDs, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// schedule the actual updating of the paramter to when the phys engine is not busy
|
||||
protected void TaintedUpdateParameter(string parm, uint localID, float val)
|
||||
protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
|
||||
{
|
||||
uint xlocalID = localID;
|
||||
string xparm = parm.ToLower();
|
||||
float xval = val;
|
||||
TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
|
||||
BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
|
||||
List<uint> xlIDs = lIDs;
|
||||
string xparm = parm;
|
||||
TaintedObject("BSScene.UpdateParameterSet", delegate() {
|
||||
ParameterDefn thisParam;
|
||||
if (TryGetParameter(xparm, out thisParam))
|
||||
{
|
||||
if (thisParam.onObject != null)
|
||||
{
|
||||
foreach (uint lID in xlIDs)
|
||||
{
|
||||
BSPhysObject theObject = null;
|
||||
PhysObjects.TryGetValue(lID, out theObject);
|
||||
thisParam.onObject(this, theObject, xval);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public class BSShapeCollection : IDisposable
|
|||
}
|
||||
|
||||
// Description of a hull.
|
||||
// Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects
|
||||
// Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
|
||||
private struct HullDesc
|
||||
{
|
||||
public IntPtr ptr;
|
||||
|
@ -59,17 +59,9 @@ public class BSShapeCollection : IDisposable
|
|||
public DateTime lastReferenced;
|
||||
}
|
||||
|
||||
private struct BodyDesc
|
||||
{
|
||||
public IntPtr ptr;
|
||||
// Bodies are only used once so reference count is always either one or zero
|
||||
public int referenceCount;
|
||||
public DateTime lastReferenced;
|
||||
}
|
||||
|
||||
// The sharable set of meshes and hulls. Indexed by their shape hash.
|
||||
private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
|
||||
private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
|
||||
private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
|
||||
|
||||
public BSShapeCollection(BSScene physScene)
|
||||
{
|
||||
|
@ -92,8 +84,12 @@ public class BSShapeCollection : IDisposable
|
|||
// First checks the shape and updates that if necessary then makes
|
||||
// sure the body is of the right type.
|
||||
// Return 'true' if either the body or the shape changed.
|
||||
// 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
|
||||
// the current shape or body is destroyed. This allows the caller to remove any
|
||||
// higher level dependencies on the shape or body. Mostly used for LinkSets to
|
||||
// remove the physical constraints before the body is destroyed.
|
||||
// Called at taint-time!!
|
||||
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim,
|
||||
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
|
||||
ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
||||
{
|
||||
|
@ -103,7 +99,8 @@ public class BSShapeCollection : IDisposable
|
|||
lock (m_collectionActivityLock)
|
||||
{
|
||||
// Do we have the correct geometry for this type of object?
|
||||
// Updates prim.BSShape with information/pointers to requested shape
|
||||
// Updates prim.BSShape with information/pointers to shape.
|
||||
// CreateGeom returns 'true' of BSShape as changed to a new shape.
|
||||
bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
|
||||
// If we had to select a new shape geometry for the object,
|
||||
// rebuild the body around it.
|
||||
|
@ -120,31 +117,18 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
// Track another user of a body
|
||||
// We presume the caller has allocated the body.
|
||||
// Bodies only have one user so the reference count is either 1 or 0.
|
||||
// Bodies only have one user so the body is just put into the world if not already there.
|
||||
public void ReferenceBody(BulletBody body, bool inTaintTime)
|
||||
{
|
||||
lock (m_collectionActivityLock)
|
||||
{
|
||||
BodyDesc bodyDesc;
|
||||
if (Bodies.TryGetValue(body.ID, out bodyDesc))
|
||||
{
|
||||
bodyDesc.referenceCount++;
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
// New entry
|
||||
bodyDesc.ptr = body.ptr;
|
||||
bodyDesc.referenceCount = 1;
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
|
||||
body.ID, body, bodyDesc.referenceCount);
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
|
||||
BSScene.TaintCallback createOperation = delegate()
|
||||
{
|
||||
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
||||
{
|
||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}",
|
||||
body.ID, body);
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
|
||||
}
|
||||
};
|
||||
if (inTaintTime)
|
||||
|
@ -152,9 +136,6 @@ public class BSShapeCollection : IDisposable
|
|||
else
|
||||
PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
|
||||
}
|
||||
bodyDesc.lastReferenced = System.DateTime.Now;
|
||||
Bodies[body.ID] = bodyDesc;
|
||||
}
|
||||
}
|
||||
|
||||
// Release the usage of a body.
|
||||
|
@ -166,18 +147,6 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
lock (m_collectionActivityLock)
|
||||
{
|
||||
BodyDesc bodyDesc;
|
||||
if (Bodies.TryGetValue(body.ID, out bodyDesc))
|
||||
{
|
||||
bodyDesc.referenceCount--;
|
||||
bodyDesc.lastReferenced = System.DateTime.Now;
|
||||
Bodies[body.ID] = bodyDesc;
|
||||
DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
|
||||
|
||||
// If body is no longer being used, free it -- bodies can never be shared.
|
||||
if (bodyDesc.referenceCount == 0)
|
||||
{
|
||||
Bodies.Remove(body.ID);
|
||||
BSScene.TaintCallback removeOperation = delegate()
|
||||
{
|
||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
|
||||
|
@ -199,12 +168,6 @@ public class BSShapeCollection : IDisposable
|
|||
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Track the datastructures and use count for a shape.
|
||||
// When creating a hull, this is called first to reference the mesh
|
||||
|
@ -271,13 +234,24 @@ public class BSShapeCollection : IDisposable
|
|||
}
|
||||
|
||||
// Release the usage of a shape.
|
||||
// The collisionObject is released since it is a copy of the real collision shape.
|
||||
public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
if (shape.ptr == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
BSScene.TaintCallback dereferenceOperation = delegate()
|
||||
{
|
||||
if (shape.ptr != IntPtr.Zero)
|
||||
{
|
||||
if (shape.isNativeShape)
|
||||
{
|
||||
// Native shapes are not tracked and are released immediately
|
||||
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
||||
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
||||
if (shapeCallback != null) shapeCallback(shape);
|
||||
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (shape.type)
|
||||
{
|
||||
|
@ -290,16 +264,10 @@ public class BSShapeCollection : IDisposable
|
|||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||
break;
|
||||
default:
|
||||
// Native shapes are not tracked and are released immediately
|
||||
if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
|
||||
{
|
||||
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
||||
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
||||
if (shapeCallback != null) shapeCallback(shape);
|
||||
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (inTaintTime)
|
||||
{
|
||||
|
@ -351,19 +319,31 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
// Create the geometry information in Bullet for later use.
|
||||
// The objects needs a hull if it's physical otherwise a mesh is enough.
|
||||
// No locking here because this is done when we know physics is not simulating.
|
||||
// if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
|
||||
// if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
|
||||
// shared geometries will be used. If the parameters of the existing shape are the same
|
||||
// as this request, the shape is not rebuilt.
|
||||
// Info in prim.BSShape is updated to the new shape.
|
||||
// Returns 'true' if the geometry was rebuilt.
|
||||
// Called at taint-time!
|
||||
private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData,
|
||||
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
|
||||
PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
bool ret = false;
|
||||
bool haveShape = false;
|
||||
bool nativeShapePossible = true;
|
||||
|
||||
if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
||||
{
|
||||
// an avatar capsule is close to a native shape (it is not shared)
|
||||
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
|
||||
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
|
||||
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
|
||||
haveShape = true;
|
||||
}
|
||||
// If the prim attributes are simple, this could be a simple Bullet native shape
|
||||
if (nativeShapePossible
|
||||
if (!haveShape
|
||||
&& pbs != null
|
||||
&& nativeShapePossible
|
||||
&& ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
|
||||
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
||||
&& pbs.ProfileHollow == 0
|
||||
|
@ -406,7 +386,7 @@ public class BSShapeCollection : IDisposable
|
|||
// If a simple shape is not happening, create a mesh and possibly a hull.
|
||||
// Note that if it's a native shape, the check for physical/non-physical is not
|
||||
// made. Native shapes are best used in either case.
|
||||
if (!haveShape)
|
||||
if (!haveShape && pbs != null)
|
||||
{
|
||||
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
|
||||
{
|
||||
|
@ -425,12 +405,12 @@ public class BSShapeCollection : IDisposable
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Creates a native shape and assignes it to prim.BSShape
|
||||
private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
|
||||
// Creates a native shape and assignes it to prim.BSShape.
|
||||
// "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
|
||||
private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData,
|
||||
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
||||
ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
||||
shapeData.Type = shapeType;
|
||||
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||
|
@ -440,23 +420,42 @@ public class BSShapeCollection : IDisposable
|
|||
// release any previous shape
|
||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
// Native shapes are always built independently.
|
||||
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
|
||||
newShape.shapeKey = (System.UInt64)shapeKey;
|
||||
newShape.isNativeShape = true;
|
||||
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
|
||||
|
||||
// Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
|
||||
// DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
|
||||
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
||||
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
|
||||
shapeData.ID, newShape, shapeData.Scale);
|
||||
|
||||
prim.BSShape = newShape;
|
||||
return true;
|
||||
}
|
||||
|
||||
private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
|
||||
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
||||
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
||||
{
|
||||
newShape = new BulletShape(
|
||||
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
|
||||
shapeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
|
||||
}
|
||||
newShape.shapeKey = (System.UInt64)shapeKey;
|
||||
newShape.isNativeShape = true;
|
||||
|
||||
return newShape;
|
||||
}
|
||||
|
||||
// Builds a mesh shape in the physical world and updates prim.BSShape.
|
||||
// Dereferences previous shape in BSShape and adds a reference for this new shape.
|
||||
// Returns 'true' of a mesh was actually built. Otherwise .
|
||||
// Called at taint-time!
|
||||
private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
||||
|
@ -475,6 +474,8 @@ public class BSShapeCollection : IDisposable
|
|||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
|
||||
// Take evasive action if the mesh was not constructed.
|
||||
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
||||
|
||||
ReferenceShape(newShape);
|
||||
|
||||
|
@ -488,7 +489,7 @@ public class BSShapeCollection : IDisposable
|
|||
private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||
{
|
||||
IMesh meshData = null;
|
||||
IntPtr meshPtr;
|
||||
IntPtr meshPtr = IntPtr.Zero;
|
||||
MeshDesc meshDesc;
|
||||
if (Meshes.TryGetValue(newMeshKey, out meshDesc))
|
||||
{
|
||||
|
@ -500,6 +501,8 @@ public class BSShapeCollection : IDisposable
|
|||
// 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, false);
|
||||
|
||||
if (meshData != null)
|
||||
{
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
||||
|
@ -518,6 +521,7 @@ public class BSShapeCollection : IDisposable
|
|||
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
||||
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||
}
|
||||
}
|
||||
BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
|
||||
newShape.shapeKey = newMeshKey;
|
||||
|
||||
|
@ -526,7 +530,7 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
// See that hull shape exists in the physical world and update prim.BSShape.
|
||||
// We could be creating the hull because scale changed or whatever.
|
||||
private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
@ -545,6 +549,7 @@ public class BSShapeCollection : IDisposable
|
|||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
|
||||
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
||||
|
||||
ReferenceShape(newShape);
|
||||
|
||||
|
@ -558,7 +563,7 @@ public class BSShapeCollection : IDisposable
|
|||
private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||
{
|
||||
|
||||
IntPtr hullPtr;
|
||||
IntPtr hullPtr = IntPtr.Zero;
|
||||
HullDesc hullDesc;
|
||||
if (Hulls.TryGetValue(newHullKey, out hullDesc))
|
||||
{
|
||||
|
@ -570,6 +575,8 @@ public class BSShapeCollection : IDisposable
|
|||
// 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
|
||||
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||
if (meshData != null)
|
||||
{
|
||||
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
@ -651,6 +658,7 @@ public class BSShapeCollection : IDisposable
|
|||
// create the hull data structure in Bullet
|
||||
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
|
||||
}
|
||||
}
|
||||
|
||||
BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
|
||||
newShape.shapeKey = newHullKey;
|
||||
|
@ -690,11 +698,55 @@ public class BSShapeCollection : IDisposable
|
|||
return ComputeShapeKey(shapeData, pbs, out lod);
|
||||
}
|
||||
|
||||
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||
{
|
||||
// If the shape was successfully created, nothing more to do
|
||||
if (newShape.ptr != IntPtr.Zero)
|
||||
return newShape;
|
||||
|
||||
// The most common reason for failure is that an underlying asset is not available
|
||||
|
||||
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
|
||||
if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
|
||||
{
|
||||
prim.LastAssetBuildFailed = true;
|
||||
BSPhysObject xprim = prim;
|
||||
Util.FireAndForget(delegate
|
||||
{
|
||||
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
|
||||
if (assetProvider != null)
|
||||
{
|
||||
BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
|
||||
assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
|
||||
{
|
||||
if (!yprim.BaseShape.SculptEntry)
|
||||
return;
|
||||
if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
|
||||
return;
|
||||
|
||||
yprim.BaseShape.SculptData = new byte[asset.Data.Length];
|
||||
asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
|
||||
// This will cause the prim to see that the filler shape is not the right
|
||||
// one and try again to build the object.
|
||||
yprim.ForceBodyShapeRebuild(false);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// While we figure out the real problem, stick a simple native shape on the object.
|
||||
BulletShape fillinShape =
|
||||
BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE);
|
||||
|
||||
return fillinShape;
|
||||
}
|
||||
|
||||
// Create a body object in Bullet.
|
||||
// Updates prim.BSBody with the information about the new body if one is created.
|
||||
// Returns 'true' if an object was actually created.
|
||||
// Called at taint-time.
|
||||
private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape,
|
||||
private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
|
||||
ShapeData shapeData, BodyDestructionCallback bodyCallback)
|
||||
{
|
||||
bool ret = false;
|
||||
|
|
|
@ -114,6 +114,7 @@ public class BSTerrainManager
|
|||
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
|
||||
Vector3.Zero, Quaternion.Identity));
|
||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
||||
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
||||
// Ground plane does not move
|
||||
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
|
||||
// Everything collides with the ground plane.
|
||||
|
@ -334,7 +335,8 @@ public class BSTerrainManager
|
|||
|
||||
// Make sure the new shape is processed.
|
||||
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
|
||||
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
|
||||
// BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||
|
||||
m_terrainModified = true;
|
||||
};
|
||||
|
|
|
@ -223,6 +223,7 @@ public struct ShapeData
|
|||
KEY_SPHERE = 2,
|
||||
KEY_CONE = 3,
|
||||
KEY_CYLINDER = 4,
|
||||
KEY_CAPSULE = 5,
|
||||
}
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
@ -282,6 +283,7 @@ public struct ConfigurationParameters
|
|||
public float terrainHitFraction;
|
||||
public float terrainRestitution;
|
||||
public float avatarFriction;
|
||||
public float avatarStandingFriction;
|
||||
public float avatarDensity;
|
||||
public float avatarRestitution;
|
||||
public float avatarCapsuleRadius;
|
||||
|
@ -388,7 +390,7 @@ public enum CollisionFilterGroups : uint
|
|||
VolumeDetectMask = ~BSensorTrigger,
|
||||
TerrainFilter = BTerrainFilter,
|
||||
TerrainMask = BAllFilter & ~BStaticFilter,
|
||||
GroundPlaneFilter = BAllFilter,
|
||||
GroundPlaneFilter = BGroundPlaneFilter,
|
||||
GroundPlaneMask = BAllFilter
|
||||
|
||||
};
|
||||
|
@ -428,6 +430,7 @@ public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg
|
|||
[return: MarshalAs(UnmanagedType.LPStr)]
|
||||
public static extern string GetVersion();
|
||||
|
||||
/* Remove the linkage to the old api methods
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
|
||||
int maxCollisions, IntPtr collisionArray,
|
||||
|
@ -531,7 +534,7 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
|
|||
// ===============================================================================
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern void DumpBulletStatistics();
|
||||
|
||||
*/
|
||||
// Log a debug message
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern void SetDebugLogCallback(DebugLogCallback callback);
|
||||
|
@ -562,7 +565,8 @@ public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
|
|||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
|
||||
int maxCollisions, IntPtr collisionArray,
|
||||
int maxUpdates, IntPtr updateArray);
|
||||
int maxUpdates, IntPtr updateArray,
|
||||
DebugLogCallback logRoutine);
|
||||
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
|
||||
|
@ -603,6 +607,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
|
|||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern bool IsNativeShape2(IntPtr shape);
|
||||
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
|
||||
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern IntPtr CreateCompoundShape2(IntPtr sim);
|
||||
|
||||
|
|
|
@ -4125,6 +4125,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the child prim or seated avatar matching the
|
||||
/// specified link number.
|
||||
/// </summary>
|
||||
/// <param name="linknum">
|
||||
/// The number of a link in the linkset or a link-related constant.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The name determined to match the specified link number.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The rules governing the returned name are not simple. The only
|
||||
/// time a blank name is returned is if the target prim has a blank
|
||||
/// name. If no prim with the given link number can be found then
|
||||
|
@ -4152,10 +4162,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
/// Mentions NULL_KEY being returned
|
||||
/// http://wiki.secondlife.com/wiki/LlGetLinkName
|
||||
/// Mentions using the LINK_* constants, some of which are negative
|
||||
/// </summary>
|
||||
/// </remarks>
|
||||
public LSL_String llGetLinkName(int linknum)
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
// simplest case, this prims link number
|
||||
if (linknum == m_host.LinkNum || linknum == ScriptBaseClass.LINK_THIS)
|
||||
return m_host.Name;
|
||||
|
||||
// parse for sitting avatare-names
|
||||
List<String> nametable = new List<String>();
|
||||
World.ForEachRootScenePresence(delegate(ScenePresence presence)
|
||||
|
@ -4179,10 +4193,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
return nametable[totalprims - linknum];
|
||||
}
|
||||
|
||||
// simplest case, this prims link number
|
||||
if (m_host.LinkNum == linknum)
|
||||
return m_host.Name;
|
||||
|
||||
// Single prim
|
||||
if (m_host.LinkNum == 0)
|
||||
{
|
||||
|
|
|
@ -128,7 +128,7 @@ namespace OpenSim.Services.Connectors.Friends
|
|||
return Call(region, sendData);
|
||||
}
|
||||
|
||||
public bool StatusNotify(GridRegion region, UUID userID, UUID friendID, bool online)
|
||||
public bool StatusNotify(GridRegion region, UUID userID, string friendID, bool online)
|
||||
{
|
||||
Dictionary<string, object> sendData = new Dictionary<string, object>();
|
||||
//sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
|
||||
|
@ -136,7 +136,7 @@ namespace OpenSim.Services.Connectors.Friends
|
|||
sendData["METHOD"] = "status";
|
||||
|
||||
sendData["FromID"] = userID.ToString();
|
||||
sendData["ToID"] = friendID.ToString();
|
||||
sendData["ToID"] = friendID;
|
||||
sendData["Online"] = online.ToString();
|
||||
|
||||
return Call(region, sendData);
|
||||
|
|
|
@ -397,7 +397,7 @@ namespace OpenSim.Services.HypergridService
|
|||
if (region != null)
|
||||
{
|
||||
m_log.DebugFormat("[HGFRIENDS SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline"));
|
||||
m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID, online);
|
||||
m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID.ToString(), online);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -502,7 +502,7 @@ namespace OpenSim.Services.HypergridService
|
|||
if (region != null)
|
||||
{
|
||||
m_log.DebugFormat("[USER AGENT SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline"));
|
||||
m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID, online);
|
||||
m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID.ToString(), online);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,13 +61,49 @@ namespace OpenSim.Services.Interfaces
|
|||
|
||||
public interface IPresenceService
|
||||
{
|
||||
/// <summary>
|
||||
/// Store session information.
|
||||
/// </summary>
|
||||
/// <returns>/returns>
|
||||
/// <param name='userID'></param>
|
||||
/// <param name='sessionID'></param>
|
||||
/// <param name='secureSessionID'></param>
|
||||
bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID);
|
||||
|
||||
/// <summary>
|
||||
/// Remove session information.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name='sessionID'></param>
|
||||
bool LogoutAgent(UUID sessionID);
|
||||
|
||||
/// <summary>
|
||||
/// Remove session information for all agents in the given region.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name='regionID'></param>
|
||||
bool LogoutRegionAgents(UUID regionID);
|
||||
|
||||
/// <summary>
|
||||
/// Update data for an existing session.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name='sessionID'></param>
|
||||
/// <param name='regionID'></param>
|
||||
bool ReportAgent(UUID sessionID, UUID regionID);
|
||||
|
||||
/// <summary>
|
||||
/// Get session information for a given session ID.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name='sessionID'></param>
|
||||
PresenceInfo GetAgent(UUID sessionID);
|
||||
|
||||
/// <summary>
|
||||
/// Get session information for a collection of users.
|
||||
/// </summary>
|
||||
/// <returns>Session information for the users.</returns>
|
||||
/// <param name='userIDs'></param>
|
||||
PresenceInfo[] GetAgents(string[] userIDs);
|
||||
}
|
||||
}
|
|
@ -1573,6 +1573,11 @@
|
|||
;MessagingModule = GroupsMessagingModule
|
||||
;MessagingEnabled = true
|
||||
|
||||
; Experimental option to only message cached online users rather than all users
|
||||
; Should make large group with few online members messaging faster, as the expense of more calls to ROBUST presence service
|
||||
; This currently only applies to the Flotsam XmlRpc backend
|
||||
MessageOnlineUsersOnly = false
|
||||
|
||||
; Service connectors to the Groups Service. Select one depending on whether you're using a Flotsam XmlRpc backend or a SimianGrid backend
|
||||
|
||||
; SimianGrid Service for Groups
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue