Merge branch 'master' into careminster
commit
6ad8d3c43f
|
@ -28,6 +28,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using log4net;
|
using log4net;
|
||||||
|
@ -495,42 +496,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||||
|
|
||||||
protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
|
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;
|
UUID friendUuid;
|
||||||
if (UUID.TryParse(friend.Friend, out friendID))
|
if (UUID.TryParse(friendStringId, out friendUuid))
|
||||||
{
|
{
|
||||||
// Try local
|
if (LocalStatusNotification(userID, friendUuid, online))
|
||||||
if (LocalStatusNotification(userID, friendID, online))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// The friend is not here [as root]. Let's forward.
|
remoteFriendStringIds.Add(friendStringId);
|
||||||
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.
|
|
||||||
}
|
}
|
||||||
else
|
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
|
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;
|
private const int ALL_SIDES = -1;
|
||||||
|
|
||||||
|
|
|
@ -290,7 +290,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
|
|
||||||
foreach (DearchiveContext sceneContext in sceneContexts.Values)
|
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)
|
if (!m_merge)
|
||||||
{
|
{
|
||||||
|
@ -324,7 +324,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
Util.FireAndForget(delegate(object o)
|
Util.FireAndForget(delegate(object o)
|
||||||
{
|
{
|
||||||
Thread.Sleep(15000);
|
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)
|
foreach (DearchiveContext sceneContext in sceneContexts.Values)
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,9 +66,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// /// </summary>
|
// /// </summary>
|
||||||
// private bool m_waitingForObjectAsset;
|
// private bool m_waitingForObjectAsset;
|
||||||
|
|
||||||
public UuidGatherer(IAssetService assetCache)
|
public UuidGatherer(IAssetService assetService)
|
||||||
{
|
{
|
||||||
m_assetService = assetCache;
|
m_assetService = assetService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -146,7 +146,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
|
||||||
sb.AppendFormat("Attachments for {0}\n", sp.Name);
|
sb.AppendFormat("Attachments for {0}\n", sp.Name);
|
||||||
|
|
||||||
ConsoleDisplayTable ct = new ConsoleDisplayTable() { Indent = 2 };
|
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("Local ID", 10));
|
||||||
ct.Columns.Add(new ConsoleDisplayTableColumn("Item ID", 36));
|
ct.Columns.Add(new ConsoleDisplayTableColumn("Item ID", 36));
|
||||||
ct.Columns.Add(new ConsoleDisplayTableColumn("Attach Point", 14));
|
ct.Columns.Add(new ConsoleDisplayTableColumn("Attach Point", 14));
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Mono.Addins;
|
using Mono.Addins;
|
||||||
|
@ -36,6 +37,8 @@ using OpenMetaverse.StructuredData;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
|
||||||
|
|
||||||
namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
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 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private List<Scene> m_sceneList = new List<Scene>();
|
private List<Scene> m_sceneList = new List<Scene>();
|
||||||
|
private IPresenceService m_presenceService;
|
||||||
|
|
||||||
private IMessageTransferModule m_msgTransferModule = null;
|
private IMessageTransferModule m_msgTransferModule = null;
|
||||||
|
|
||||||
|
@ -54,6 +58,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
private bool m_groupMessagingEnabled = false;
|
private bool m_groupMessagingEnabled = false;
|
||||||
private bool m_debugEnabled = true;
|
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
|
#region IRegionModuleBase Members
|
||||||
|
|
||||||
public void Initialise(IConfigSource config)
|
public void Initialise(IConfigSource config)
|
||||||
|
@ -83,10 +108,17 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false);
|
||||||
|
|
||||||
|
if (m_messageOnlineAgentsOnly)
|
||||||
|
m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>();
|
||||||
|
|
||||||
m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true);
|
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)
|
public void AddRegion(Scene scene)
|
||||||
|
@ -126,6 +158,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_presenceService == null)
|
||||||
|
m_presenceService = scene.PresenceService;
|
||||||
|
|
||||||
m_sceneList.Add(scene);
|
m_sceneList.Add(scene);
|
||||||
|
|
||||||
|
@ -207,12 +241,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
|
public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
|
||||||
{
|
{
|
||||||
List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID);
|
List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID);
|
||||||
|
int groupMembersCount = groupMembers.Count;
|
||||||
if (m_debugEnabled)
|
|
||||||
m_log.DebugFormat(
|
if (m_messageOnlineAgentsOnly)
|
||||||
"[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members",
|
{
|
||||||
groupID, groupMembers.Count);
|
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)
|
foreach (GroupMembersData member in groupMembers)
|
||||||
{
|
{
|
||||||
if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID))
|
if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID))
|
||||||
|
@ -254,6 +318,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
ProcessMessageFromGroupSession(msg);
|
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
|
#region SimGridEventHandlers
|
||||||
|
|
|
@ -123,7 +123,36 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
public void AddRegion(Scene scene)
|
public void AddRegion(Scene scene)
|
||||||
{
|
{
|
||||||
if (m_groupsEnabled)
|
if (m_groupsEnabled)
|
||||||
|
{
|
||||||
scene.RegisterModuleInterface<IGroupsModule>(this);
|
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)
|
public void RegionLoaded(Scene scene)
|
||||||
|
|
|
@ -41,8 +41,6 @@ public class BSCharacter : BSPhysObject
|
||||||
|
|
||||||
// private bool _stopped;
|
// private bool _stopped;
|
||||||
private OMV.Vector3 _size;
|
private OMV.Vector3 _size;
|
||||||
private OMV.Vector3 _scale;
|
|
||||||
private PrimitiveBaseShape _pbs;
|
|
||||||
private bool _grabbed;
|
private bool _grabbed;
|
||||||
private bool _selected;
|
private bool _selected;
|
||||||
private OMV.Vector3 _position;
|
private OMV.Vector3 _position;
|
||||||
|
@ -67,6 +65,10 @@ public class BSCharacter : BSPhysObject
|
||||||
private bool _kinematic;
|
private bool _kinematic;
|
||||||
private float _buoyancy;
|
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 OMV.Vector3 _PIDTarget;
|
||||||
private bool _usePID;
|
private bool _usePID;
|
||||||
private float _PIDTau;
|
private float _PIDTau;
|
||||||
|
@ -84,14 +86,18 @@ public class BSCharacter : BSPhysObject
|
||||||
_flying = isFlying;
|
_flying = isFlying;
|
||||||
_orientation = OMV.Quaternion.Identity;
|
_orientation = OMV.Quaternion.Identity;
|
||||||
_velocity = OMV.Vector3.Zero;
|
_velocity = OMV.Vector3.Zero;
|
||||||
|
_appliedVelocity = OMV.Vector3.Zero;
|
||||||
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
||||||
|
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
||||||
|
_avatarDensity = PhysicsScene.Params.avatarDensity;
|
||||||
|
|
||||||
// The dimensions of the avatar capsule are kept in the scale.
|
// The dimensions of the avatar capsule are kept in the scale.
|
||||||
// Physics creates a unit capsule which is scaled by the physics engine.
|
// Physics creates a unit capsule which is scaled by the physics engine.
|
||||||
ComputeAvatarScale(_size);
|
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();
|
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 shapeData = new ShapeData();
|
||||||
shapeData.ID = LocalID;
|
shapeData.ID = LocalID;
|
||||||
|
@ -99,28 +105,22 @@ public class BSCharacter : BSPhysObject
|
||||||
shapeData.Position = _position;
|
shapeData.Position = _position;
|
||||||
shapeData.Rotation = _orientation;
|
shapeData.Rotation = _orientation;
|
||||||
shapeData.Velocity = _velocity;
|
shapeData.Velocity = _velocity;
|
||||||
shapeData.Scale = _scale;
|
shapeData.Size = Scale;
|
||||||
|
shapeData.Scale = Scale;
|
||||||
shapeData.Mass = _mass;
|
shapeData.Mass = _mass;
|
||||||
shapeData.Buoyancy = _buoyancy;
|
shapeData.Buoyancy = _buoyancy;
|
||||||
shapeData.Static = ShapeData.numericFalse;
|
shapeData.Static = ShapeData.numericFalse;
|
||||||
shapeData.Friction = PhysicsScene.Params.avatarFriction;
|
shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
|
||||||
shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
|
shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
|
||||||
|
|
||||||
// do actual create at taint time
|
// do actual create at taint time
|
||||||
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.create,taint", LocalID);
|
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#.
|
SetPhysicalProperties();
|
||||||
// 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);
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -131,53 +131,85 @@ public class BSCharacter : BSPhysObject
|
||||||
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
||||||
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
|
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()
|
public override void RequestPhysicsterseUpdate()
|
||||||
{
|
{
|
||||||
base.RequestPhysicsterseUpdate();
|
base.RequestPhysicsterseUpdate();
|
||||||
}
|
}
|
||||||
// No one calls this method so I don't know what it could possibly mean
|
// No one calls this method so I don't know what it could possibly mean
|
||||||
public override bool Stopped {
|
public override bool Stopped { get { return false; } }
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
public override OMV.Vector3 Size {
|
public override OMV.Vector3 Size {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// Avatar capsule size is kept in the scale parameter.
|
// Avatar capsule size is kept in the scale parameter.
|
||||||
return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
// When an avatar's size is set, only the height is changed
|
// When an avatar's size is set, only the height is changed.
|
||||||
// and that really only depends on the radius.
|
|
||||||
_size = value;
|
_size = value;
|
||||||
ComputeAvatarScale(_size);
|
ComputeAvatarScale(_size);
|
||||||
|
|
||||||
// TODO: something has to be done with the avatar's vertical position
|
|
||||||
|
|
||||||
ComputeAvatarVolumeAndMass();
|
ComputeAvatarVolumeAndMass();
|
||||||
|
DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
|
||||||
|
LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw);
|
||||||
|
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
|
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 {
|
public override OMV.Vector3 Scale { get; set; }
|
||||||
set { _pbs = value;
|
public override PrimitiveBaseShape Shape
|
||||||
}
|
{
|
||||||
|
set { BaseShape = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Grabbed {
|
public override bool Grabbed {
|
||||||
set { _grabbed = value;
|
set { _grabbed = value; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public override bool Selected {
|
public override bool Selected {
|
||||||
set { _selected = value;
|
set { _selected = value; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public override void CrossingFailure() { return; }
|
public override void CrossingFailure() { return; }
|
||||||
public override void link(PhysicsActor obj) { return; }
|
public override void link(PhysicsActor obj) { return; }
|
||||||
|
@ -204,7 +236,7 @@ public class BSCharacter : BSPhysObject
|
||||||
|
|
||||||
public override OMV.Vector3 Position {
|
public override OMV.Vector3 Position {
|
||||||
get {
|
get {
|
||||||
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
// _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
|
||||||
return _position;
|
return _position;
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
|
@ -214,7 +246,7 @@ public class BSCharacter : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
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
|
// 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 back to the physics engine. This routine would be used by anyone
|
||||||
// who is not already pushing the value.
|
// who is not already pushing the value.
|
||||||
private bool PositionSanityCheck2(bool inTaintTime)
|
private bool PositionSanityCheck(bool inTaintTime)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (PositionSanityCheck())
|
if (PositionSanityCheck())
|
||||||
|
@ -273,7 +305,7 @@ public class BSCharacter : BSPhysObject
|
||||||
BSScene.TaintCallback sanityOperation = delegate()
|
BSScene.TaintCallback sanityOperation = delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
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)
|
if (inTaintTime)
|
||||||
sanityOperation();
|
sanityOperation();
|
||||||
|
@ -284,11 +316,7 @@ public class BSCharacter : BSPhysObject
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override float Mass {
|
public override float Mass { get { return _mass; } }
|
||||||
get {
|
|
||||||
return _mass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// used when we only want this prim's mass and not the linkset thing
|
// used when we only want this prim's mass and not the linkset thing
|
||||||
public override float MassRaw { get {return _mass; } }
|
public override float MassRaw { get {return _mass; } }
|
||||||
|
@ -301,15 +329,13 @@ public class BSCharacter : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
||||||
BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
|
BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int VehicleType {
|
// Avatars don't do vehicles
|
||||||
get { return 0; }
|
public override int VehicleType { get { return 0; } set { return; } }
|
||||||
set { return; }
|
|
||||||
}
|
|
||||||
public override void VehicleFloatParam(int param, float value) { }
|
public override void VehicleFloatParam(int param, float value) { }
|
||||||
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
|
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
|
||||||
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
|
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
|
||||||
|
@ -328,15 +354,37 @@ public class BSCharacter : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
||||||
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
|
ForceVelocity = _velocity;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override OMV.Vector3 ForceVelocity {
|
public override OMV.Vector3 ForceVelocity {
|
||||||
get { return _velocity; }
|
get { return _velocity; }
|
||||||
set {
|
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;
|
_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 {
|
public override OMV.Vector3 Torque {
|
||||||
|
@ -360,8 +408,8 @@ public class BSCharacter : BSPhysObject
|
||||||
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
|
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
||||||
{
|
{
|
||||||
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
|
||||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,12 +437,18 @@ public class BSCharacter : BSPhysObject
|
||||||
set { _isPhysical = value;
|
set { _isPhysical = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public override bool IsSolid {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
public override bool IsStatic {
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
public override bool Flying {
|
public override bool Flying {
|
||||||
get { return _flying; }
|
get { return _flying; }
|
||||||
set {
|
set {
|
||||||
_flying = value;
|
_flying = value;
|
||||||
// simulate flying by changing the effect of gravity
|
// simulate flying by changing the effect of gravity
|
||||||
this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
|
Buoyancy = ComputeBuoyancyFromFlying(_flying);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Flying is implimented by changing the avatar's buoyancy.
|
// Flying is implimented by changing the avatar's buoyancy.
|
||||||
|
@ -454,10 +508,19 @@ public class BSCharacter : BSPhysObject
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
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
|
// Used for MoveTo
|
||||||
public override OMV.Vector3 PIDTarget {
|
public override OMV.Vector3 PIDTarget {
|
||||||
|
@ -518,27 +581,32 @@ public class BSCharacter : BSPhysObject
|
||||||
|
|
||||||
private void ComputeAvatarScale(OMV.Vector3 size)
|
private void ComputeAvatarScale(OMV.Vector3 size)
|
||||||
{
|
{
|
||||||
_scale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
// The 'size' given by the simulator is the mid-point of the avatar
|
||||||
_scale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
// and X and Y are unspecified.
|
||||||
|
|
||||||
// The 1.15 came from ODE but it seems to cause the avatar to float off the ground
|
OMV.Vector3 newScale = OMV.Vector3.Zero;
|
||||||
// _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
|
newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
||||||
_scale.Z = (_size.Z) - (_scale.X + _scale.Y);
|
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()
|
private void ComputeAvatarVolumeAndMass()
|
||||||
{
|
{
|
||||||
_avatarVolume = (float)(
|
_avatarVolume = (float)(
|
||||||
Math.PI
|
Math.PI
|
||||||
* _scale.X
|
* Scale.X
|
||||||
* _scale.Y // the area of capsule cylinder
|
* Scale.Y // the area of capsule cylinder
|
||||||
* _scale.Z // times height of capsule cylinder
|
* Scale.Z // times height of capsule cylinder
|
||||||
+ 1.33333333f
|
+ 1.33333333f
|
||||||
* Math.PI
|
* Math.PI
|
||||||
* _scale.X
|
* Scale.X
|
||||||
* Math.Min(_scale.X, _scale.Y)
|
* Math.Min(Scale.X, Scale.Y)
|
||||||
* _scale.Y // plus the volume of the capsule end caps
|
* Scale.Y // plus the volume of the capsule end caps
|
||||||
);
|
);
|
||||||
_mass = _avatarDensity * _avatarVolume;
|
_mass = _avatarDensity * _avatarVolume;
|
||||||
}
|
}
|
||||||
|
@ -553,7 +621,23 @@ public class BSCharacter : BSPhysObject
|
||||||
_acceleration = entprop.Acceleration;
|
_acceleration = entprop.Acceleration;
|
||||||
_rotationalVelocity = entprop.RotationalVelocity;
|
_rotationalVelocity = entprop.RotationalVelocity;
|
||||||
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
// 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.
|
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
||||||
// base.RequestPhysicsterseUpdate();
|
// base.RequestPhysicsterseUpdate();
|
||||||
|
|
|
@ -47,6 +47,7 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
TypeName = typeName;
|
TypeName = typeName;
|
||||||
|
|
||||||
Linkset = new BSLinkset(PhysicsScene, this);
|
Linkset = new BSLinkset(PhysicsScene, this);
|
||||||
|
LastAssetBuildFailed = false;
|
||||||
|
|
||||||
CollisionCollection = new CollisionEventUpdate();
|
CollisionCollection = new CollisionEventUpdate();
|
||||||
SubscribedEventsMs = 0;
|
SubscribedEventsMs = 0;
|
||||||
|
@ -69,6 +70,23 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
// Reference to the physical shape (btCollisionShape) of this object
|
// Reference to the physical shape (btCollisionShape) of this object
|
||||||
public BulletShape BSShape;
|
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.
|
// Stop all physical motion.
|
||||||
public abstract void ZeroMotion();
|
public abstract void ZeroMotion();
|
||||||
|
|
||||||
|
@ -89,6 +107,10 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
|
|
||||||
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
|
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
|
||||||
|
|
||||||
|
public abstract float ForceBuoyancy { get; set; }
|
||||||
|
|
||||||
|
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
|
||||||
|
|
||||||
#region Collisions
|
#region Collisions
|
||||||
|
|
||||||
// Requested number of milliseconds between collision events. Zero means disabled.
|
// 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 someone has subscribed for collision events....
|
||||||
if (SubscribedEvents()) {
|
if (SubscribedEvents()) {
|
||||||
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
||||||
// DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
||||||
// LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine to send the collected collisions into the simulator.
|
// 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.
|
|
||||||
// Called at taint time from within the Step() function thus no locking problems
|
// Called at taint time from within the Step() function thus no locking problems
|
||||||
// with CollisionCollection and ObjectsWithNoMoreCollisions.
|
// with CollisionCollection and ObjectsWithNoMoreCollisions.
|
||||||
// Return 'true' if there were some actual collisions passed up
|
// Return 'true' if there were some actual collisions passed up
|
||||||
public virtual bool SendCollisions()
|
public virtual bool SendCollisions()
|
||||||
{
|
{
|
||||||
bool ret = true;
|
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
|
// throttle the collisions to the number of milliseconds specified in the subscription
|
||||||
int nowTime = PhysicsScene.SimulationNowTime;
|
if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
|
||||||
if (nowTime >= NextCollisionOkTime)
|
|
||||||
{
|
{
|
||||||
NextCollisionOkTime = nowTime + SubscribedEventsMs;
|
NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
|
||||||
|
|
||||||
// We are called if we previously had collisions. If there are no collisions
|
// 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.
|
// 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 ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
private static readonly string LogHeader = "[BULLETS PRIM]";
|
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 _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 _grabbed;
|
||||||
private bool _isSelected;
|
private bool _isSelected;
|
||||||
|
@ -98,12 +96,12 @@ public sealed class BSPrim : BSPhysObject
|
||||||
_physicsActorType = (int)ActorTypes.Prim;
|
_physicsActorType = (int)ActorTypes.Prim;
|
||||||
_position = pos;
|
_position = pos;
|
||||||
_size = size;
|
_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;
|
_orientation = rotation;
|
||||||
_buoyancy = 1f;
|
_buoyancy = 1f;
|
||||||
_velocity = OMV.Vector3.Zero;
|
_velocity = OMV.Vector3.Zero;
|
||||||
_rotationalVelocity = OMV.Vector3.Zero;
|
_rotationalVelocity = OMV.Vector3.Zero;
|
||||||
_pbs = pbs;
|
BaseShape = pbs;
|
||||||
_isPhysical = pisPhysical;
|
_isPhysical = pisPhysical;
|
||||||
_isVolumeDetect = false;
|
_isVolumeDetect = false;
|
||||||
_friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
|
_friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
|
||||||
|
@ -160,33 +158,32 @@ public sealed class BSPrim : BSPhysObject
|
||||||
get { return _size; }
|
get { return _size; }
|
||||||
set {
|
set {
|
||||||
_size = value;
|
_size = value;
|
||||||
PhysicsScene.TaintedObject("BSPrim.setSize", delegate()
|
ForceBodyShapeRebuild(false);
|
||||||
{
|
|
||||||
_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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Scale is what we set in the physics engine. It is different than 'size' in that
|
// 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>.
|
// 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
|
||||||
public OMV.Vector3 Scale
|
public override OMV.Vector3 Scale { get; set; }
|
||||||
{
|
|
||||||
get { return _scale; }
|
|
||||||
set { _scale = value; }
|
|
||||||
}
|
|
||||||
public override PrimitiveBaseShape Shape {
|
public override PrimitiveBaseShape Shape {
|
||||||
set {
|
set {
|
||||||
_pbs = value;
|
BaseShape = value;
|
||||||
PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
|
ForceBodyShapeRebuild(false);
|
||||||
{
|
|
||||||
_mass = CalculateMass(); // changing the shape changes the mass
|
|
||||||
CreateGeomAndObject(true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 {
|
public override bool Grabbed {
|
||||||
set { _grabbed = value;
|
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
|
// 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.
|
// who is not already pushing the value.
|
||||||
private bool PositionSanityCheck2(bool inTaintTime)
|
private bool PositionSanityCheck(bool inTaintTime)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (PositionSanityCheck())
|
if (PositionSanityCheck())
|
||||||
|
@ -337,7 +334,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
BSScene.TaintCallback sanityOperation = delegate()
|
BSScene.TaintCallback sanityOperation = delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
ForcePosition = _position;
|
||||||
};
|
};
|
||||||
if (inTaintTime)
|
if (inTaintTime)
|
||||||
sanityOperation();
|
sanityOperation();
|
||||||
|
@ -547,13 +544,13 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// An object is static (does not move) if selected or not physical
|
// An object is static (does not move) if selected or not physical
|
||||||
private bool IsStatic
|
public override bool IsStatic
|
||||||
{
|
{
|
||||||
get { return _isSelected || !IsPhysical; }
|
get { return _isSelected || !IsPhysical; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// An object is solid if it's not phantom and if it's not doing VolumeDetect
|
// 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; }
|
get { return !IsPhantom && !_isVolumeDetect; }
|
||||||
}
|
}
|
||||||
|
@ -631,6 +628,12 @@ public sealed class BSPrim : BSPhysObject
|
||||||
BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
|
BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
|
||||||
// There is no inertia in a static object
|
// There is no inertia in a static object
|
||||||
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
|
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
|
// There can be special things needed for implementing linksets
|
||||||
Linkset.MakeStatic(this);
|
Linkset.MakeStatic(this);
|
||||||
// The activation state is 'disabled' so Bullet will not try to act on it.
|
// The activation state is 'disabled' so Bullet will not try to act on it.
|
||||||
|
@ -662,6 +665,13 @@ public sealed class BSPrim : BSPhysObject
|
||||||
BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
|
BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
|
||||||
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
|
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
|
// Various values for simulation limits
|
||||||
BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
|
BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
|
||||||
BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
|
BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
|
||||||
|
@ -813,13 +823,20 @@ public sealed class BSPrim : BSPhysObject
|
||||||
_buoyancy = value;
|
_buoyancy = value;
|
||||||
PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
|
PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
|
||||||
{
|
{
|
||||||
// DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
ForceBuoyancy = _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));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Used for MoveTo
|
// Used for MoveTo
|
||||||
public override OMV.Vector3 PIDTarget {
|
public override OMV.Vector3 PIDTarget {
|
||||||
|
@ -907,19 +924,19 @@ public sealed class BSPrim : BSPhysObject
|
||||||
float tmp;
|
float tmp;
|
||||||
|
|
||||||
float returnMass = 0;
|
float returnMass = 0;
|
||||||
float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
|
float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
|
||||||
float hollowVolume = hollowAmount * hollowAmount;
|
float hollowVolume = hollowAmount * hollowAmount;
|
||||||
|
|
||||||
switch (_pbs.ProfileShape)
|
switch (BaseShape.ProfileShape)
|
||||||
{
|
{
|
||||||
case ProfileShape.Square:
|
case ProfileShape.Square:
|
||||||
// default box
|
// default box
|
||||||
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||||
{
|
{
|
||||||
if (hollowAmount > 0.0)
|
if (hollowAmount > 0.0)
|
||||||
{
|
{
|
||||||
switch (_pbs.HollowShape)
|
switch (BaseShape.HollowShape)
|
||||||
{
|
{
|
||||||
case HollowShape.Square:
|
case HollowShape.Square:
|
||||||
case HollowShape.Same:
|
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
|
//a tube
|
||||||
|
|
||||||
volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
|
volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
|
||||||
tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
|
tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
|
||||||
volume -= volume*tmp*tmp;
|
volume -= volume*tmp*tmp;
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
if (hollowAmount > 0.0)
|
||||||
{
|
{
|
||||||
hollowVolume *= hollowAmount;
|
hollowVolume *= hollowAmount;
|
||||||
|
|
||||||
switch (_pbs.HollowShape)
|
switch (BaseShape.HollowShape)
|
||||||
{
|
{
|
||||||
case HollowShape.Square:
|
case HollowShape.Square:
|
||||||
case HollowShape.Same:
|
case HollowShape.Same:
|
||||||
|
@ -980,13 +997,13 @@ public sealed class BSPrim : BSPhysObject
|
||||||
|
|
||||||
case ProfileShape.Circle:
|
case ProfileShape.Circle:
|
||||||
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||||
{
|
{
|
||||||
volume *= 0.78539816339f; // elipse base
|
volume *= 0.78539816339f; // elipse base
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
if (hollowAmount > 0.0)
|
||||||
{
|
{
|
||||||
switch (_pbs.HollowShape)
|
switch (BaseShape.HollowShape)
|
||||||
{
|
{
|
||||||
case HollowShape.Same:
|
case HollowShape.Same:
|
||||||
case HollowShape.Circle:
|
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);
|
volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
|
||||||
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
|
||||||
volume *= (1.0f - tmp * tmp);
|
volume *= (1.0f - tmp * tmp);
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
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
|
// calculate the hollow volume by it's shape compared to the prim shape
|
||||||
hollowVolume *= hollowAmount;
|
hollowVolume *= hollowAmount;
|
||||||
|
|
||||||
switch (_pbs.HollowShape)
|
switch (BaseShape.HollowShape)
|
||||||
{
|
{
|
||||||
case HollowShape.Same:
|
case HollowShape.Same:
|
||||||
case HollowShape.Circle:
|
case HollowShape.Circle:
|
||||||
|
@ -1044,7 +1061,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProfileShape.HalfCircle:
|
case ProfileShape.HalfCircle:
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||||
{
|
{
|
||||||
volume *= 0.52359877559829887307710723054658f;
|
volume *= 0.52359877559829887307710723054658f;
|
||||||
}
|
}
|
||||||
|
@ -1052,7 +1069,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
|
|
||||||
case ProfileShape.EquilateralTriangle:
|
case ProfileShape.EquilateralTriangle:
|
||||||
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||||
{
|
{
|
||||||
volume *= 0.32475953f;
|
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
|
// calculate the hollow volume by it's shape compared to the prim shape
|
||||||
switch (_pbs.HollowShape)
|
switch (BaseShape.HollowShape)
|
||||||
{
|
{
|
||||||
case HollowShape.Same:
|
case HollowShape.Same:
|
||||||
case HollowShape.Triangle:
|
case HollowShape.Triangle:
|
||||||
|
@ -1085,11 +1102,11 @@ public sealed class BSPrim : BSPhysObject
|
||||||
volume *= (1.0f - hollowVolume);
|
volume *= (1.0f - hollowVolume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||||
{
|
{
|
||||||
volume *= 0.32475953f;
|
volume *= 0.32475953f;
|
||||||
volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
|
volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
|
||||||
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
|
||||||
volume *= (1.0f - tmp * tmp);
|
volume *= (1.0f - tmp * tmp);
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
if (hollowAmount > 0.0)
|
||||||
|
@ -1097,7 +1114,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
|
|
||||||
hollowVolume *= hollowAmount;
|
hollowVolume *= hollowAmount;
|
||||||
|
|
||||||
switch (_pbs.HollowShape)
|
switch (BaseShape.HollowShape)
|
||||||
{
|
{
|
||||||
case HollowShape.Same:
|
case HollowShape.Same:
|
||||||
case HollowShape.Triangle:
|
case HollowShape.Triangle:
|
||||||
|
@ -1137,26 +1154,26 @@ public sealed class BSPrim : BSPhysObject
|
||||||
float profileBegin;
|
float profileBegin;
|
||||||
float profileEnd;
|
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)
|
if (taperX1 > 1.0f)
|
||||||
taperX1 = 2.0f - taperX1;
|
taperX1 = 2.0f - taperX1;
|
||||||
taperX = 1.0f - taperX1;
|
taperX = 1.0f - taperX1;
|
||||||
|
|
||||||
taperY1 = _pbs.PathScaleY * 0.01f;
|
taperY1 = BaseShape.PathScaleY * 0.01f;
|
||||||
if (taperY1 > 1.0f)
|
if (taperY1 > 1.0f)
|
||||||
taperY1 = 2.0f - taperY1;
|
taperY1 = 2.0f - taperY1;
|
||||||
taperY = 1.0f - taperY1;
|
taperY = 1.0f - taperY1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
taperX = _pbs.PathTaperX * 0.01f;
|
taperX = BaseShape.PathTaperX * 0.01f;
|
||||||
if (taperX < 0.0f)
|
if (taperX < 0.0f)
|
||||||
taperX = -taperX;
|
taperX = -taperX;
|
||||||
taperX1 = 1.0f - taperX;
|
taperX1 = 1.0f - taperX;
|
||||||
|
|
||||||
taperY = _pbs.PathTaperY * 0.01f;
|
taperY = BaseShape.PathTaperY * 0.01f;
|
||||||
if (taperY < 0.0f)
|
if (taperY < 0.0f)
|
||||||
taperY = -taperY;
|
taperY = -taperY;
|
||||||
taperY1 = 1.0f - 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);
|
volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
|
||||||
|
|
||||||
pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
|
pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
|
||||||
pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
|
pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
|
||||||
volume *= (pathEnd - pathBegin);
|
volume *= (pathEnd - pathBegin);
|
||||||
|
|
||||||
// this is crude aproximation
|
// this is crude aproximation
|
||||||
profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
|
profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
|
||||||
profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
|
profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
|
||||||
volume *= (profileEnd - profileBegin);
|
volume *= (profileEnd - profileBegin);
|
||||||
|
|
||||||
returnMass = _density * volume;
|
returnMass = _density * volume;
|
||||||
|
@ -1207,7 +1224,8 @@ public sealed class BSPrim : BSPhysObject
|
||||||
shape.Position = _position;
|
shape.Position = _position;
|
||||||
shape.Rotation = _orientation;
|
shape.Rotation = _orientation;
|
||||||
shape.Velocity = _velocity;
|
shape.Velocity = _velocity;
|
||||||
shape.Scale = _scale;
|
shape.Size = _size;
|
||||||
|
shape.Scale = Scale;
|
||||||
shape.Mass = _isPhysical ? _mass : 0f;
|
shape.Mass = _isPhysical ? _mass : 0f;
|
||||||
shape.Buoyancy = _buoyancy;
|
shape.Buoyancy = _buoyancy;
|
||||||
shape.HullKey = 0;
|
shape.HullKey = 0;
|
||||||
|
@ -1217,7 +1235,6 @@ public sealed class BSPrim : BSPhysObject
|
||||||
shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
|
shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
|
||||||
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
|
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
|
||||||
shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
|
shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
|
||||||
shape.Size = _size;
|
|
||||||
}
|
}
|
||||||
// Rebuild the geometry and object.
|
// Rebuild the geometry and object.
|
||||||
// This is called when the shape changes so we need to recreate the mesh/hull.
|
// 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.
|
// Create the correct physical representation for this type of object.
|
||||||
// Updates BSBody and BSShape with the new information.
|
// Updates BSBody and BSShape with the new information.
|
||||||
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
|
// 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)
|
null, delegate(BulletBody dBody)
|
||||||
{
|
{
|
||||||
// Called if the current prim body is about to be destroyed.
|
// Called if the current prim body is about to be destroyed.
|
||||||
|
@ -1328,9 +1345,11 @@ public sealed class BSPrim : BSPhysObject
|
||||||
_acceleration = entprop.Acceleration;
|
_acceleration = entprop.Acceleration;
|
||||||
_rotationalVelocity = entprop.RotationalVelocity;
|
_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}",
|
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
||||||
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
|
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
|
||||||
|
@ -1348,6 +1367,9 @@ public sealed class BSPrim : BSPhysObject
|
||||||
entprop.Acceleration, entprop.RotationalVelocity);
|
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);
|
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||||
|
|
||||||
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
|
// 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_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
|
||||||
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
|
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
|
||||||
m_DebugLogCallbackHandle);
|
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));
|
|
||||||
|
|
||||||
Constraints = new BSConstraintCollection(World);
|
Constraints = new BSConstraintCollection(World);
|
||||||
|
|
||||||
|
@ -360,7 +356,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anything left in the unmanaged code should be cleaned out
|
// Anything left in the unmanaged code should be cleaned out
|
||||||
BulletSimAPI.Shutdown(WorldID);
|
BulletSimAPI.Shutdown2(World.ptr);
|
||||||
|
|
||||||
// Not logging any more
|
// Not logging any more
|
||||||
PhysicsLogging.Close();
|
PhysicsLogging.Close();
|
||||||
|
@ -498,7 +494,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
{
|
{
|
||||||
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
|
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);
|
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
|
||||||
|
|
||||||
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
|
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
|
||||||
|
@ -536,26 +532,26 @@ 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.
|
// The above SendCollision's batch up the collisions on the objects.
|
||||||
// Now push the collisions into the simulator.
|
// Now push the collisions into the simulator.
|
||||||
if (ObjectsWithCollisions.Count > 0)
|
if (ObjectsWithCollisions.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (BSPhysObject bsp in ObjectsWithCollisions)
|
foreach (BSPhysObject bsp in ObjectsWithCollisions)
|
||||||
if (!m_avatars.Contains(bsp)) // don't call avatars twice
|
if (!bsp.SendCollisions())
|
||||||
if (!bsp.SendCollisions())
|
{
|
||||||
{
|
// If the object is done colliding, see that it's removed from the colliding list
|
||||||
// If the object is done colliding, see that it's removed from the colliding list
|
ObjectsWithNoMoreCollisions.Add(bsp);
|
||||||
ObjectsWithNoMoreCollisions.Add(bsp);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
// Objects that are done colliding are removed from the ObjectsWithCollisions list.
|
||||||
// Not done above because it is inside an iteration of ObjectWithCollisions.
|
// Not done above because it is inside an iteration of ObjectWithCollisions.
|
||||||
if (ObjectsWithNoMoreCollisions.Count > 0)
|
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.
|
// The physics engine returns the number of milliseconds it simulated this call.
|
||||||
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
|
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
|
||||||
// We multiply by 45 to give a recognizable running rate (45 or less).
|
// We multiply by 55 to give a recognizable running rate (55 or less).
|
||||||
return numSubSteps * m_fixedTimeStep * 1000 * 45;
|
return numSubSteps * m_fixedTimeStep * 1000 * 55;
|
||||||
// return timeStep * 1000 * 45;
|
// return timeStep * 1000 * 55;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Something has collided
|
// Something has collided
|
||||||
|
@ -800,6 +800,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
|
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
|
||||||
delegate float ParamGet(BSScene scene);
|
delegate float ParamGet(BSScene scene);
|
||||||
delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
|
delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
|
||||||
|
delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
|
||||||
|
|
||||||
private struct ParameterDefn
|
private struct ParameterDefn
|
||||||
{
|
{
|
||||||
|
@ -809,6 +810,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
public ParamUser userParam; // get the value from the configuration file
|
public ParamUser userParam; // get the value from the configuration file
|
||||||
public ParamGet getter; // return the current value stored for this parameter
|
public ParamGet getter; // return the current value stored for this parameter
|
||||||
public ParamSet setter; // set the current value 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)
|
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
|
||||||
{
|
{
|
||||||
name = n;
|
name = n;
|
||||||
|
@ -817,6 +819,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
userParam = u;
|
userParam = u;
|
||||||
getter = g;
|
getter = g;
|
||||||
setter = s;
|
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:
|
// The single letter parameters for the delegates are:
|
||||||
// s = BSScene
|
// s = BSScene
|
||||||
|
// o = BSPhysObject
|
||||||
// p = string parameter name
|
// p = string parameter name
|
||||||
// l = localID of referenced object
|
// l = localID of referenced object
|
||||||
// v = float value
|
// v = float value
|
||||||
|
@ -947,70 +961,84 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
-9.80665f,
|
-9.80665f,
|
||||||
(s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].gravity; },
|
(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)",
|
new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
|
||||||
0f,
|
0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].linearDamping; },
|
(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)",
|
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
|
||||||
0f,
|
0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].angularDamping; },
|
(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",
|
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
|
||||||
0.2f,
|
0.2f,
|
||||||
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].deactivationTime; },
|
(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",
|
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
|
||||||
0.8f,
|
0.8f,
|
||||||
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].linearSleepingThreshold; },
|
(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",
|
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
|
||||||
1.0f,
|
1.0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].angularSleepingThreshold; },
|
(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)" ,
|
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
|
||||||
0f, // set to zero to disable
|
0f, // set to zero to disable
|
||||||
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].ccdMotionThreshold; },
|
(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" ,
|
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
|
||||||
0f,
|
0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
|
(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" ,
|
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
|
||||||
0.1f,
|
0.1f,
|
||||||
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].contactProcessingThreshold; },
|
(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" ,
|
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
|
||||||
0.5f,
|
0.5f,
|
||||||
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].terrainFriction; },
|
(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" ,
|
new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
|
||||||
0.8f,
|
0.8f,
|
||||||
(s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].terrainHitFraction; },
|
(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" ,
|
new ParameterDefn("TerrainRestitution", "Bouncyness" ,
|
||||||
0f,
|
0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].terrainRestitution; },
|
(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.",
|
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
|
||||||
0.2f,
|
0.2f,
|
||||||
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].avatarFriction; },
|
(s) => { return s.m_params[0].avatarFriction; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
|
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
|
||||||
|
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
|
||||||
|
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.",
|
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
|
||||||
60f,
|
60f,
|
||||||
(s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
|
||||||
|
@ -1227,52 +1255,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
return ret;
|
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
|
// update all the localIDs specified
|
||||||
// If the local ID is APPLY_TO_NONE, just change the default value
|
// 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 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
|
// 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)
|
switch (localID)
|
||||||
{
|
{
|
||||||
case PhysParameterEntry.APPLY_TO_NONE:
|
case PhysParameterEntry.APPLY_TO_NONE:
|
||||||
defaultLoc = val; // setting only the default value
|
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;
|
break;
|
||||||
case PhysParameterEntry.APPLY_TO_ALL:
|
case PhysParameterEntry.APPLY_TO_ALL:
|
||||||
defaultLoc = val; // setting ALL also sets the default value
|
defaultLoc = val; // setting ALL also sets the default value
|
||||||
List<uint> objectIDs = lIDs;
|
lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
|
||||||
string xparm = parm.ToLower();
|
TaintedUpdateParameter(parm, objectIDs, val);
|
||||||
float xval = val;
|
|
||||||
TaintedObject("BSScene.UpdateParameterSet", delegate() {
|
|
||||||
foreach (uint lID in objectIDs)
|
|
||||||
{
|
|
||||||
BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// setting only one localID
|
// setting only one localID
|
||||||
TaintedUpdateParameter(parm, localID, val);
|
objectIDs.Add(localID);
|
||||||
|
TaintedUpdateParameter(parm, objectIDs, val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// schedule the actual updating of the paramter to when the phys engine is not busy
|
// 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;
|
float xval = val;
|
||||||
TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
|
List<uint> xlIDs = lIDs;
|
||||||
BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
|
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.
|
// 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
|
private struct HullDesc
|
||||||
{
|
{
|
||||||
public IntPtr ptr;
|
public IntPtr ptr;
|
||||||
|
@ -59,17 +59,9 @@ public class BSShapeCollection : IDisposable
|
||||||
public DateTime lastReferenced;
|
public DateTime lastReferenced;
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct BodyDesc
|
// The sharable set of meshes and hulls. Indexed by their shape hash.
|
||||||
{
|
|
||||||
public IntPtr ptr;
|
|
||||||
// Bodies are only used once so reference count is always either one or zero
|
|
||||||
public int referenceCount;
|
|
||||||
public DateTime lastReferenced;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
|
private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
|
||||||
private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
|
private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
|
||||||
private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
|
|
||||||
|
|
||||||
public BSShapeCollection(BSScene physScene)
|
public BSShapeCollection(BSScene physScene)
|
||||||
{
|
{
|
||||||
|
@ -92,8 +84,12 @@ public class BSShapeCollection : IDisposable
|
||||||
// First checks the shape and updates that if necessary then makes
|
// First checks the shape and updates that if necessary then makes
|
||||||
// sure the body is of the right type.
|
// sure the body is of the right type.
|
||||||
// Return 'true' if either the body or the shape changed.
|
// 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!!
|
// 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,
|
ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||||
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
||||||
{
|
{
|
||||||
|
@ -103,7 +99,8 @@ public class BSShapeCollection : IDisposable
|
||||||
lock (m_collectionActivityLock)
|
lock (m_collectionActivityLock)
|
||||||
{
|
{
|
||||||
// Do we have the correct geometry for this type of object?
|
// 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);
|
bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
|
||||||
// If we had to select a new shape geometry for the object,
|
// If we had to select a new shape geometry for the object,
|
||||||
// rebuild the body around it.
|
// rebuild the body around it.
|
||||||
|
@ -120,40 +117,24 @@ public class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
// Track another user of a body
|
// Track another user of a body
|
||||||
// We presume the caller has allocated the 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)
|
public void ReferenceBody(BulletBody body, bool inTaintTime)
|
||||||
{
|
{
|
||||||
lock (m_collectionActivityLock)
|
lock (m_collectionActivityLock)
|
||||||
{
|
{
|
||||||
BodyDesc bodyDesc;
|
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
|
||||||
if (Bodies.TryGetValue(body.ID, out bodyDesc))
|
BSScene.TaintCallback createOperation = delegate()
|
||||||
{
|
{
|
||||||
bodyDesc.referenceCount++;
|
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
||||||
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);
|
|
||||||
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);
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
|
}
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}",
|
};
|
||||||
body.ID, body);
|
if (inTaintTime)
|
||||||
}
|
createOperation();
|
||||||
};
|
else
|
||||||
if (inTaintTime)
|
PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
|
||||||
createOperation();
|
|
||||||
else
|
|
||||||
PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
|
|
||||||
}
|
|
||||||
bodyDesc.lastReferenced = System.DateTime.Now;
|
|
||||||
Bodies[body.ID] = bodyDesc;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,43 +147,25 @@ public class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
lock (m_collectionActivityLock)
|
lock (m_collectionActivityLock)
|
||||||
{
|
{
|
||||||
BodyDesc bodyDesc;
|
BSScene.TaintCallback removeOperation = delegate()
|
||||||
if (Bodies.TryGetValue(body.ID, out bodyDesc))
|
|
||||||
{
|
{
|
||||||
bodyDesc.referenceCount--;
|
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
|
||||||
bodyDesc.lastReferenced = System.DateTime.Now;
|
body.ID, body.ptr.ToString("X"), inTaintTime);
|
||||||
Bodies[body.ID] = bodyDesc;
|
// If the caller needs to know the old body is going away, pass the event up.
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
|
if (bodyCallback != null) bodyCallback(body);
|
||||||
|
|
||||||
// If body is no longer being used, free it -- bodies can never be shared.
|
// It may have already been removed from the world in which case the next is a NOOP.
|
||||||
if (bodyDesc.referenceCount == 0)
|
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||||
{
|
|
||||||
Bodies.Remove(body.ID);
|
|
||||||
BSScene.TaintCallback removeOperation = delegate()
|
|
||||||
{
|
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
|
|
||||||
body.ID, body.ptr.ToString("X"), inTaintTime);
|
|
||||||
// If the caller needs to know the old body is going away, pass the event up.
|
|
||||||
if (bodyCallback != null) bodyCallback(body);
|
|
||||||
|
|
||||||
// It may have already been removed from the world in which case the next is a NOOP.
|
// Zero any reference to the shape so it is not freed when the body is deleted.
|
||||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
|
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
|
||||||
|
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
|
||||||
// Zero any reference to the shape so it is not freed when the body is deleted.
|
};
|
||||||
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
|
// If already in taint-time, do the operations now. Otherwise queue for later.
|
||||||
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
|
if (inTaintTime)
|
||||||
};
|
removeOperation();
|
||||||
// If already in taint-time, do the operations now. Otherwise queue for later.
|
|
||||||
if (inTaintTime)
|
|
||||||
removeOperation();
|
|
||||||
else
|
|
||||||
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +234,6 @@ public class BSShapeCollection : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the usage of a shape.
|
// 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)
|
public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
if (shape.ptr == IntPtr.Zero)
|
if (shape.ptr == IntPtr.Zero)
|
||||||
|
@ -279,26 +241,32 @@ public class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
BSScene.TaintCallback dereferenceOperation = delegate()
|
BSScene.TaintCallback dereferenceOperation = delegate()
|
||||||
{
|
{
|
||||||
switch (shape.type)
|
if (shape.ptr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
if (shape.isNativeShape)
|
||||||
DereferenceHull(shape, shapeCallback);
|
{
|
||||||
break;
|
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
|
||||||
DereferenceMesh(shape, shapeCallback);
|
|
||||||
break;
|
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Native shapes are not tracked and are released immediately
|
// 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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (shape.type)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||||
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
DereferenceHull(shape, shapeCallback);
|
||||||
if (shapeCallback != null) shapeCallback(shape);
|
break;
|
||||||
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||||
|
DereferenceMesh(shape, shapeCallback);
|
||||||
|
break;
|
||||||
|
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (inTaintTime)
|
if (inTaintTime)
|
||||||
|
@ -351,19 +319,31 @@ public class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
// Create the geometry information in Bullet for later use.
|
// Create the geometry information in Bullet for later use.
|
||||||
// The objects needs a hull if it's physical otherwise a mesh is enough.
|
// 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 unconditionally rebuilt. For meshes and hulls,
|
||||||
// if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
|
// 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.
|
// Returns 'true' if the geometry was rebuilt.
|
||||||
// Called at taint-time!
|
// 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)
|
PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
bool haveShape = false;
|
bool haveShape = false;
|
||||||
bool nativeShapePossible = true;
|
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 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.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
|
||||||
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
||||||
&& pbs.ProfileHollow == 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.
|
// 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
|
// 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.
|
// made. Native shapes are best used in either case.
|
||||||
if (!haveShape)
|
if (!haveShape && pbs != null)
|
||||||
{
|
{
|
||||||
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
|
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
|
||||||
{
|
{
|
||||||
|
@ -425,12 +405,12 @@ public class BSShapeCollection : IDisposable
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a native shape and assignes it to prim.BSShape
|
// Creates a native shape and assignes it to prim.BSShape.
|
||||||
private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
|
// "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,
|
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
||||||
ShapeDestructionCallback shapeCallback)
|
ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
BulletShape newShape;
|
|
||||||
|
|
||||||
shapeData.Type = shapeType;
|
shapeData.Type = shapeType;
|
||||||
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||||
|
@ -440,23 +420,42 @@ public class BSShapeCollection : IDisposable
|
||||||
// release any previous shape
|
// release any previous shape
|
||||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||||
|
|
||||||
// Native shapes are always built independently.
|
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
|
||||||
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
|
|
||||||
newShape.shapeKey = (System.UInt64)shapeKey;
|
|
||||||
newShape.isNativeShape = true;
|
|
||||||
|
|
||||||
// Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
|
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
||||||
// DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
|
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
|
||||||
|
shapeData.ID, newShape, shapeData.Scale);
|
||||||
|
|
||||||
prim.BSShape = newShape;
|
prim.BSShape = newShape;
|
||||||
return true;
|
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.
|
// 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.
|
// Dereferences previous shape in BSShape and adds a reference for this new shape.
|
||||||
// Returns 'true' of a mesh was actually built. Otherwise .
|
// Returns 'true' of a mesh was actually built. Otherwise .
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||||
ShapeDestructionCallback shapeCallback)
|
ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
||||||
|
@ -475,6 +474,8 @@ public class BSShapeCollection : IDisposable
|
||||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||||
|
|
||||||
newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
|
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);
|
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)
|
private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||||
{
|
{
|
||||||
IMesh meshData = null;
|
IMesh meshData = null;
|
||||||
IntPtr meshPtr;
|
IntPtr meshPtr = IntPtr.Zero;
|
||||||
MeshDesc meshDesc;
|
MeshDesc meshDesc;
|
||||||
if (Meshes.TryGetValue(newMeshKey, out meshDesc))
|
if (Meshes.TryGetValue(newMeshKey, out meshDesc))
|
||||||
{
|
{
|
||||||
|
@ -500,23 +501,26 @@ public class BSShapeCollection : IDisposable
|
||||||
// Pass false for physicalness as this creates some sort of bounding box which we don't need
|
// 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);
|
meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||||
|
|
||||||
int[] indices = meshData.getIndexListAsInt();
|
if (meshData != null)
|
||||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
|
||||||
|
|
||||||
float[] verticesAsFloats = new float[vertices.Count * 3];
|
|
||||||
int vi = 0;
|
|
||||||
foreach (OMV.Vector3 vv in vertices)
|
|
||||||
{
|
{
|
||||||
verticesAsFloats[vi++] = vv.X;
|
int[] indices = meshData.getIndexListAsInt();
|
||||||
verticesAsFloats[vi++] = vv.Y;
|
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||||
verticesAsFloats[vi++] = vv.Z;
|
|
||||||
|
float[] verticesAsFloats = new float[vertices.Count * 3];
|
||||||
|
int vi = 0;
|
||||||
|
foreach (OMV.Vector3 vv in vertices)
|
||||||
|
{
|
||||||
|
verticesAsFloats[vi++] = vv.X;
|
||||||
|
verticesAsFloats[vi++] = vv.Y;
|
||||||
|
verticesAsFloats[vi++] = vv.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
|
||||||
|
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
||||||
|
|
||||||
|
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
||||||
|
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||||
}
|
}
|
||||||
|
|
||||||
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
|
|
||||||
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
|
||||||
|
|
||||||
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
|
||||||
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
|
||||||
}
|
}
|
||||||
BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
|
BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
|
||||||
newShape.shapeKey = newMeshKey;
|
newShape.shapeKey = newMeshKey;
|
||||||
|
@ -526,7 +530,7 @@ public class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
// See that hull shape exists in the physical world and update prim.BSShape.
|
// See that hull shape exists in the physical world and update prim.BSShape.
|
||||||
// We could be creating the hull because scale changed or whatever.
|
// 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)
|
ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
BulletShape newShape;
|
BulletShape newShape;
|
||||||
|
@ -545,6 +549,7 @@ public class BSShapeCollection : IDisposable
|
||||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||||
|
|
||||||
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
|
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
|
||||||
|
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
||||||
|
|
||||||
ReferenceShape(newShape);
|
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)
|
private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||||
{
|
{
|
||||||
|
|
||||||
IntPtr hullPtr;
|
IntPtr hullPtr = IntPtr.Zero;
|
||||||
HullDesc hullDesc;
|
HullDesc hullDesc;
|
||||||
if (Hulls.TryGetValue(newHullKey, out hullDesc))
|
if (Hulls.TryGetValue(newHullKey, out hullDesc))
|
||||||
{
|
{
|
||||||
|
@ -570,86 +575,89 @@ public class BSShapeCollection : IDisposable
|
||||||
// Build a new hull in the physical world
|
// Build a new hull in the physical world
|
||||||
// Pass false for physicalness as this creates some sort of bounding box which we don't need
|
// Pass 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);
|
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||||
|
if (meshData != null)
|
||||||
int[] indices = meshData.getIndexListAsInt();
|
|
||||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
|
||||||
|
|
||||||
//format conversion from IMesh format to DecompDesc format
|
|
||||||
List<int> convIndices = new List<int>();
|
|
||||||
List<float3> convVertices = new List<float3>();
|
|
||||||
for (int ii = 0; ii < indices.GetLength(0); ii++)
|
|
||||||
{
|
{
|
||||||
convIndices.Add(indices[ii]);
|
|
||||||
}
|
|
||||||
foreach (OMV.Vector3 vv in vertices)
|
|
||||||
{
|
|
||||||
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup and do convex hull conversion
|
int[] indices = meshData.getIndexListAsInt();
|
||||||
m_hulls = new List<ConvexResult>();
|
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||||
DecompDesc dcomp = new DecompDesc();
|
|
||||||
dcomp.mIndices = convIndices;
|
|
||||||
dcomp.mVertices = convVertices;
|
|
||||||
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
|
|
||||||
// create the hull into the _hulls variable
|
|
||||||
convexBuilder.process(dcomp);
|
|
||||||
|
|
||||||
// Convert the vertices and indices for passing to unmanaged.
|
//format conversion from IMesh format to DecompDesc format
|
||||||
// The hull information is passed as a large floating point array.
|
List<int> convIndices = new List<int>();
|
||||||
// The format is:
|
List<float3> convVertices = new List<float3>();
|
||||||
// convHulls[0] = number of hulls
|
for (int ii = 0; ii < indices.GetLength(0); ii++)
|
||||||
// convHulls[1] = number of vertices in first hull
|
|
||||||
// convHulls[2] = hull centroid X coordinate
|
|
||||||
// convHulls[3] = hull centroid Y coordinate
|
|
||||||
// convHulls[4] = hull centroid Z coordinate
|
|
||||||
// convHulls[5] = first hull vertex X
|
|
||||||
// convHulls[6] = first hull vertex Y
|
|
||||||
// convHulls[7] = first hull vertex Z
|
|
||||||
// convHulls[8] = second hull vertex X
|
|
||||||
// ...
|
|
||||||
// convHulls[n] = number of vertices in second hull
|
|
||||||
// convHulls[n+1] = second hull centroid X coordinate
|
|
||||||
// ...
|
|
||||||
//
|
|
||||||
// TODO: is is very inefficient. Someday change the convex hull generator to return
|
|
||||||
// data structures that do not need to be converted in order to pass to Bullet.
|
|
||||||
// And maybe put the values directly into pinned memory rather than marshaling.
|
|
||||||
int hullCount = m_hulls.Count;
|
|
||||||
int totalVertices = 1; // include one for the count of the hulls
|
|
||||||
foreach (ConvexResult cr in m_hulls)
|
|
||||||
{
|
|
||||||
totalVertices += 4; // add four for the vertex count and centroid
|
|
||||||
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
|
|
||||||
}
|
|
||||||
float[] convHulls = new float[totalVertices];
|
|
||||||
|
|
||||||
convHulls[0] = (float)hullCount;
|
|
||||||
int jj = 1;
|
|
||||||
foreach (ConvexResult cr in m_hulls)
|
|
||||||
{
|
|
||||||
// copy vertices for index access
|
|
||||||
float3[] verts = new float3[cr.HullVertices.Count];
|
|
||||||
int kk = 0;
|
|
||||||
foreach (float3 ff in cr.HullVertices)
|
|
||||||
{
|
{
|
||||||
verts[kk++] = ff;
|
convIndices.Add(indices[ii]);
|
||||||
|
}
|
||||||
|
foreach (OMV.Vector3 vv in vertices)
|
||||||
|
{
|
||||||
|
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add to the array one hull's worth of data
|
// setup and do convex hull conversion
|
||||||
convHulls[jj++] = cr.HullIndices.Count;
|
m_hulls = new List<ConvexResult>();
|
||||||
convHulls[jj++] = 0f; // centroid x,y,z
|
DecompDesc dcomp = new DecompDesc();
|
||||||
convHulls[jj++] = 0f;
|
dcomp.mIndices = convIndices;
|
||||||
convHulls[jj++] = 0f;
|
dcomp.mVertices = convVertices;
|
||||||
foreach (int ind in cr.HullIndices)
|
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
|
||||||
|
// create the hull into the _hulls variable
|
||||||
|
convexBuilder.process(dcomp);
|
||||||
|
|
||||||
|
// Convert the vertices and indices for passing to unmanaged.
|
||||||
|
// The hull information is passed as a large floating point array.
|
||||||
|
// The format is:
|
||||||
|
// convHulls[0] = number of hulls
|
||||||
|
// convHulls[1] = number of vertices in first hull
|
||||||
|
// convHulls[2] = hull centroid X coordinate
|
||||||
|
// convHulls[3] = hull centroid Y coordinate
|
||||||
|
// convHulls[4] = hull centroid Z coordinate
|
||||||
|
// convHulls[5] = first hull vertex X
|
||||||
|
// convHulls[6] = first hull vertex Y
|
||||||
|
// convHulls[7] = first hull vertex Z
|
||||||
|
// convHulls[8] = second hull vertex X
|
||||||
|
// ...
|
||||||
|
// convHulls[n] = number of vertices in second hull
|
||||||
|
// convHulls[n+1] = second hull centroid X coordinate
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// TODO: is is very inefficient. Someday change the convex hull generator to return
|
||||||
|
// data structures that do not need to be converted in order to pass to Bullet.
|
||||||
|
// And maybe put the values directly into pinned memory rather than marshaling.
|
||||||
|
int hullCount = m_hulls.Count;
|
||||||
|
int totalVertices = 1; // include one for the count of the hulls
|
||||||
|
foreach (ConvexResult cr in m_hulls)
|
||||||
{
|
{
|
||||||
convHulls[jj++] = verts[ind].x;
|
totalVertices += 4; // add four for the vertex count and centroid
|
||||||
convHulls[jj++] = verts[ind].y;
|
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
|
||||||
convHulls[jj++] = verts[ind].z;
|
|
||||||
}
|
}
|
||||||
|
float[] convHulls = new float[totalVertices];
|
||||||
|
|
||||||
|
convHulls[0] = (float)hullCount;
|
||||||
|
int jj = 1;
|
||||||
|
foreach (ConvexResult cr in m_hulls)
|
||||||
|
{
|
||||||
|
// copy vertices for index access
|
||||||
|
float3[] verts = new float3[cr.HullVertices.Count];
|
||||||
|
int kk = 0;
|
||||||
|
foreach (float3 ff in cr.HullVertices)
|
||||||
|
{
|
||||||
|
verts[kk++] = ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to the array one hull's worth of data
|
||||||
|
convHulls[jj++] = cr.HullIndices.Count;
|
||||||
|
convHulls[jj++] = 0f; // centroid x,y,z
|
||||||
|
convHulls[jj++] = 0f;
|
||||||
|
convHulls[jj++] = 0f;
|
||||||
|
foreach (int ind in cr.HullIndices)
|
||||||
|
{
|
||||||
|
convHulls[jj++] = verts[ind].x;
|
||||||
|
convHulls[jj++] = verts[ind].y;
|
||||||
|
convHulls[jj++] = verts[ind].z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create the hull data structure in Bullet
|
||||||
|
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
|
||||||
}
|
}
|
||||||
// create the hull data structure in Bullet
|
|
||||||
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
|
BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
|
||||||
|
@ -690,11 +698,55 @@ public class BSShapeCollection : IDisposable
|
||||||
return ComputeShapeKey(shapeData, pbs, out lod);
|
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.
|
// Create a body object in Bullet.
|
||||||
// Updates prim.BSBody with the information about the new body if one is created.
|
// Updates prim.BSBody with the information about the new body if one is created.
|
||||||
// Returns 'true' if an object was actually created.
|
// Returns 'true' if an object was actually created.
|
||||||
// Called at taint-time.
|
// 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)
|
ShapeData shapeData, BodyDestructionCallback bodyCallback)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
|
@ -114,6 +114,7 @@ public class BSTerrainManager
|
||||||
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
|
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
|
||||||
Vector3.Zero, Quaternion.Identity));
|
Vector3.Zero, Quaternion.Identity));
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
||||||
|
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
||||||
// Ground plane does not move
|
// Ground plane does not move
|
||||||
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
|
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
|
||||||
// Everything collides with the ground plane.
|
// Everything collides with the ground plane.
|
||||||
|
@ -334,7 +335,8 @@ public class BSTerrainManager
|
||||||
|
|
||||||
// Make sure the new shape is processed.
|
// Make sure the new shape is processed.
|
||||||
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
|
// 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;
|
m_terrainModified = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -223,6 +223,7 @@ public struct ShapeData
|
||||||
KEY_SPHERE = 2,
|
KEY_SPHERE = 2,
|
||||||
KEY_CONE = 3,
|
KEY_CONE = 3,
|
||||||
KEY_CYLINDER = 4,
|
KEY_CYLINDER = 4,
|
||||||
|
KEY_CAPSULE = 5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
@ -282,6 +283,7 @@ public struct ConfigurationParameters
|
||||||
public float terrainHitFraction;
|
public float terrainHitFraction;
|
||||||
public float terrainRestitution;
|
public float terrainRestitution;
|
||||||
public float avatarFriction;
|
public float avatarFriction;
|
||||||
|
public float avatarStandingFriction;
|
||||||
public float avatarDensity;
|
public float avatarDensity;
|
||||||
public float avatarRestitution;
|
public float avatarRestitution;
|
||||||
public float avatarCapsuleRadius;
|
public float avatarCapsuleRadius;
|
||||||
|
@ -388,7 +390,7 @@ public enum CollisionFilterGroups : uint
|
||||||
VolumeDetectMask = ~BSensorTrigger,
|
VolumeDetectMask = ~BSensorTrigger,
|
||||||
TerrainFilter = BTerrainFilter,
|
TerrainFilter = BTerrainFilter,
|
||||||
TerrainMask = BAllFilter & ~BStaticFilter,
|
TerrainMask = BAllFilter & ~BStaticFilter,
|
||||||
GroundPlaneFilter = BAllFilter,
|
GroundPlaneFilter = BGroundPlaneFilter,
|
||||||
GroundPlaneMask = BAllFilter
|
GroundPlaneMask = BAllFilter
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -428,6 +430,7 @@ public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg
|
||||||
[return: MarshalAs(UnmanagedType.LPStr)]
|
[return: MarshalAs(UnmanagedType.LPStr)]
|
||||||
public static extern string GetVersion();
|
public static extern string GetVersion();
|
||||||
|
|
||||||
|
/* Remove the linkage to the old api methods
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
|
public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
|
||||||
int maxCollisions, IntPtr collisionArray,
|
int maxCollisions, IntPtr collisionArray,
|
||||||
|
@ -531,7 +534,7 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
|
||||||
// ===============================================================================
|
// ===============================================================================
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern void DumpBulletStatistics();
|
public static extern void DumpBulletStatistics();
|
||||||
|
*/
|
||||||
// Log a debug message
|
// Log a debug message
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern void SetDebugLogCallback(DebugLogCallback callback);
|
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]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
|
public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
|
||||||
int maxCollisions, IntPtr collisionArray,
|
int maxCollisions, IntPtr collisionArray,
|
||||||
int maxUpdates, IntPtr updateArray);
|
int maxUpdates, IntPtr updateArray,
|
||||||
|
DebugLogCallback logRoutine);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
|
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]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern bool IsNativeShape2(IntPtr shape);
|
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]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr CreateCompoundShape2(IntPtr sim);
|
public static extern IntPtr CreateCompoundShape2(IntPtr sim);
|
||||||
|
|
||||||
|
|
|
@ -4125,6 +4125,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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
|
/// 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
|
/// 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
|
/// 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
|
/// Mentions NULL_KEY being returned
|
||||||
/// http://wiki.secondlife.com/wiki/LlGetLinkName
|
/// http://wiki.secondlife.com/wiki/LlGetLinkName
|
||||||
/// Mentions using the LINK_* constants, some of which are negative
|
/// Mentions using the LINK_* constants, some of which are negative
|
||||||
/// </summary>
|
/// </remarks>
|
||||||
public LSL_String llGetLinkName(int linknum)
|
public LSL_String llGetLinkName(int linknum)
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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
|
// parse for sitting avatare-names
|
||||||
List<String> nametable = new List<String>();
|
List<String> nametable = new List<String>();
|
||||||
World.ForEachRootScenePresence(delegate(ScenePresence presence)
|
World.ForEachRootScenePresence(delegate(ScenePresence presence)
|
||||||
|
@ -4179,10 +4193,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
return nametable[totalprims - linknum];
|
return nametable[totalprims - linknum];
|
||||||
}
|
}
|
||||||
|
|
||||||
// simplest case, this prims link number
|
|
||||||
if (m_host.LinkNum == linknum)
|
|
||||||
return m_host.Name;
|
|
||||||
|
|
||||||
// Single prim
|
// Single prim
|
||||||
if (m_host.LinkNum == 0)
|
if (m_host.LinkNum == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -128,7 +128,7 @@ namespace OpenSim.Services.Connectors.Friends
|
||||||
return Call(region, sendData);
|
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>();
|
Dictionary<string, object> sendData = new Dictionary<string, object>();
|
||||||
//sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
|
//sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
|
||||||
|
@ -136,7 +136,7 @@ namespace OpenSim.Services.Connectors.Friends
|
||||||
sendData["METHOD"] = "status";
|
sendData["METHOD"] = "status";
|
||||||
|
|
||||||
sendData["FromID"] = userID.ToString();
|
sendData["FromID"] = userID.ToString();
|
||||||
sendData["ToID"] = friendID.ToString();
|
sendData["ToID"] = friendID;
|
||||||
sendData["Online"] = online.ToString();
|
sendData["Online"] = online.ToString();
|
||||||
|
|
||||||
return Call(region, sendData);
|
return Call(region, sendData);
|
||||||
|
|
|
@ -397,7 +397,7 @@ namespace OpenSim.Services.HypergridService
|
||||||
if (region != null)
|
if (region != null)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[HGFRIENDS SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline"));
|
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)
|
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_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
|
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);
|
bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove session information.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <param name='sessionID'></param>
|
||||||
bool LogoutAgent(UUID sessionID);
|
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);
|
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);
|
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);
|
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);
|
PresenceInfo[] GetAgents(string[] userIDs);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1573,6 +1573,11 @@
|
||||||
;MessagingModule = GroupsMessagingModule
|
;MessagingModule = GroupsMessagingModule
|
||||||
;MessagingEnabled = true
|
;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
|
; 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
|
; 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