Merge branch 'master' into careminster
Conflicts: OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs OpenSim/Region/Framework/Scenes/ScenePresence.cs OpenSim/Region/Physics/Manager/PhysicsActor.cs OpenSim/Region/Physics/Manager/PhysicsScene.csavinationmerge
commit
e82d4154a2
|
@ -1402,17 +1402,16 @@ namespace OpenSim.Groups
|
||||||
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
||||||
|
|
||||||
// TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
|
// TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
|
||||||
UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, dataForAgentID);
|
string firstname = "Unknown", lastname = "Unknown";
|
||||||
string firstname, lastname;
|
string name = m_UserManagement.GetUserName(dataForAgentID);
|
||||||
if (account != null)
|
if (!string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
firstname = account.FirstName;
|
string[] parts = name.Split(new char[] { ' ' });
|
||||||
lastname = account.LastName;
|
if (parts.Length >= 2)
|
||||||
}
|
{
|
||||||
else
|
firstname = parts[0];
|
||||||
{
|
lastname = parts[1];
|
||||||
firstname = "Unknown";
|
}
|
||||||
lastname = "Unknown";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname,
|
remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname,
|
||||||
|
|
|
@ -834,6 +834,8 @@ namespace OpenSim.Framework
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
event UpdateAgent OnAgentUpdate;
|
event UpdateAgent OnAgentUpdate;
|
||||||
|
|
||||||
|
event UpdateAgent OnAgentCameraUpdate;
|
||||||
|
|
||||||
event AgentRequestSit OnAgentRequestSit;
|
event AgentRequestSit OnAgentRequestSit;
|
||||||
event AgentSit OnAgentSit;
|
event AgentSit OnAgentSit;
|
||||||
event AvatarPickerRequest OnAvatarPickerRequest;
|
event AvatarPickerRequest OnAvatarPickerRequest;
|
||||||
|
@ -1489,7 +1491,7 @@ namespace OpenSim.Framework
|
||||||
void SendChangeUserRights(UUID agentID, UUID friendID, int rights);
|
void SendChangeUserRights(UUID agentID, UUID friendID, int rights);
|
||||||
void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId);
|
void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId);
|
||||||
|
|
||||||
void StopFlying(ISceneEntity presence);
|
void SendAgentTerseUpdate(ISceneEntity presence);
|
||||||
|
|
||||||
void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data);
|
void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,7 +225,13 @@ namespace OpenSim.Framework.Monitoring
|
||||||
public virtual string ToConsoleString()
|
public virtual string ToConsoleString()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.AppendFormat("{0}.{1}.{2} : {3} {4}", Category, Container, ShortName, Value, UnitName);
|
sb.AppendFormat(
|
||||||
|
"{0}.{1}.{2} : {3}{4}",
|
||||||
|
Category,
|
||||||
|
Container,
|
||||||
|
ShortName,
|
||||||
|
Value,
|
||||||
|
UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName));
|
||||||
|
|
||||||
AppendMeasuresOfInterest(sb);
|
AppendMeasuresOfInterest(sb);
|
||||||
|
|
||||||
|
@ -253,6 +259,8 @@ namespace OpenSim.Framework.Monitoring
|
||||||
== MeasuresOfInterest.AverageChangeOverTime)
|
== MeasuresOfInterest.AverageChangeOverTime)
|
||||||
{
|
{
|
||||||
double totalChange = 0;
|
double totalChange = 0;
|
||||||
|
double lastChangeOverTime = 0;
|
||||||
|
double? penultimateSample = null;
|
||||||
double? lastSample = null;
|
double? lastSample = null;
|
||||||
|
|
||||||
lock (m_samples)
|
lock (m_samples)
|
||||||
|
@ -266,13 +274,25 @@ namespace OpenSim.Framework.Monitoring
|
||||||
if (lastSample != null)
|
if (lastSample != null)
|
||||||
totalChange += s - (double)lastSample;
|
totalChange += s - (double)lastSample;
|
||||||
|
|
||||||
|
penultimateSample = lastSample;
|
||||||
lastSample = s;
|
lastSample = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lastSample != null && penultimateSample != null)
|
||||||
|
lastChangeOverTime
|
||||||
|
= ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
|
||||||
|
|
||||||
int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
|
int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
|
||||||
|
|
||||||
sb.AppendFormat(", {0:0.##} {1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName);
|
double averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
|
||||||
|
|
||||||
|
sb.AppendFormat(
|
||||||
|
", {0:0.##}{1}/s, {2:0.##}{3}/s",
|
||||||
|
lastChangeOverTime,
|
||||||
|
UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName),
|
||||||
|
averageChangeOverTime,
|
||||||
|
UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
||||||
public event UpdateAgent OnPreAgentUpdate;
|
public event UpdateAgent OnPreAgentUpdate;
|
||||||
public event UpdateAgent OnAgentUpdate;
|
public event UpdateAgent OnAgentUpdate;
|
||||||
|
public event UpdateAgent OnAgentCameraUpdate;
|
||||||
public event AgentRequestSit OnAgentRequestSit;
|
public event AgentRequestSit OnAgentRequestSit;
|
||||||
public event AgentSit OnAgentSit;
|
public event AgentSit OnAgentSit;
|
||||||
public event AvatarPickerRequest OnAvatarPickerRequest;
|
public event AvatarPickerRequest OnAvatarPickerRequest;
|
||||||
|
@ -368,7 +369,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
|
/// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
|
||||||
/// cannot retain a reference to it outside of that method.
|
/// cannot retain a reference to it outside of that method.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private AgentUpdateArgs m_lastAgentUpdateArgs;
|
private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
|
||||||
|
|
||||||
protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
|
protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
|
||||||
protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
|
protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
|
||||||
|
@ -505,6 +506,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
m_udpServer = udpServer;
|
m_udpServer = udpServer;
|
||||||
m_udpClient = udpClient;
|
m_udpClient = udpClient;
|
||||||
m_udpClient.OnQueueEmpty += HandleQueueEmpty;
|
m_udpClient.OnQueueEmpty += HandleQueueEmpty;
|
||||||
|
m_udpClient.HasUpdates += HandleHasUpdates;
|
||||||
m_udpClient.OnPacketStats += PopulateStats;
|
m_udpClient.OnPacketStats += PopulateStats;
|
||||||
|
|
||||||
m_prioritizer = new Prioritizer(m_scene);
|
m_prioritizer = new Prioritizer(m_scene);
|
||||||
|
@ -4164,8 +4166,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
|
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
|
||||||
{
|
{
|
||||||
|
// if (!m_udpServer.IsRunningOutbound)
|
||||||
|
// return;
|
||||||
|
|
||||||
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
|
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
|
||||||
{
|
{
|
||||||
|
// if (!m_udpServer.IsRunningOutbound)
|
||||||
|
// return;
|
||||||
|
|
||||||
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
|
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
|
||||||
{
|
{
|
||||||
m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
|
m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
|
||||||
|
@ -4191,6 +4199,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
|
ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
|
||||||
|
{
|
||||||
|
bool hasUpdates = false;
|
||||||
|
|
||||||
|
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
|
||||||
|
{
|
||||||
|
if (m_entityUpdates.Count > 0)
|
||||||
|
hasUpdates = true;
|
||||||
|
else if (m_entityProps.Count > 0)
|
||||||
|
hasUpdates = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
|
||||||
|
{
|
||||||
|
if (ImageManager.HasUpdates())
|
||||||
|
hasUpdates = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasUpdates;
|
||||||
|
}
|
||||||
|
|
||||||
public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
|
public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
|
||||||
{
|
{
|
||||||
AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
|
AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
|
||||||
|
@ -5058,7 +5087,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
SceneObjectPart part = (SceneObjectPart)entity;
|
SceneObjectPart part = (SceneObjectPart)entity;
|
||||||
|
|
||||||
attachPoint = part.ParentGroup.AttachmentPoint;
|
attachPoint = part.ParentGroup.AttachmentPoint;
|
||||||
|
attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
|
// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
|
||||||
// attachPoint, part.Name, part.LocalId, Name);
|
// attachPoint, part.Name, part.LocalId, Name);
|
||||||
|
@ -5086,7 +5115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
pos += 4;
|
pos += 4;
|
||||||
|
|
||||||
// Avatar/CollisionPlane
|
// Avatar/CollisionPlane
|
||||||
data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ;
|
data[pos++] = (byte) attachPoint;
|
||||||
if (avatar)
|
if (avatar)
|
||||||
{
|
{
|
||||||
data[pos++] = 1;
|
data[pos++] = 1;
|
||||||
|
@ -5618,83 +5647,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
#region Packet Handlers
|
#region Packet Handlers
|
||||||
|
|
||||||
|
public int TotalAgentUpdates { get; set; }
|
||||||
|
|
||||||
#region Scene/Avatar
|
#region Scene/Avatar
|
||||||
|
|
||||||
|
// Threshold for body rotation to be a significant agent update
|
||||||
|
private const float QDELTA = 0.000001f;
|
||||||
|
// Threshold for camera rotation to be a significant agent update
|
||||||
|
private const float VDELTA = 0.01f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This checks the update significance against the last update made.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Can only be called by one thread at a time</remarks>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <param name='x'></param>
|
||||||
|
public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
|
||||||
|
{
|
||||||
|
return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This checks the movement/state update significance against the last update made.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Can only be called by one thread at a time</remarks>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <param name='x'></param>
|
||||||
|
private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
|
||||||
|
{
|
||||||
|
float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
|
||||||
|
//qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
|
||||||
|
|
||||||
|
bool movementSignificant =
|
||||||
|
(qdelta1 > QDELTA) // significant if body rotation above threshold
|
||||||
|
// Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
|
||||||
|
// || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
|
||||||
|
|| (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
|
||||||
|
|| (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
|
||||||
|
|| (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
|
||||||
|
|| (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
|
||||||
|
|| (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
|
||||||
|
;
|
||||||
|
//if (movementSignificant)
|
||||||
|
//{
|
||||||
|
//m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
|
||||||
|
// qdelta1, qdelta2);
|
||||||
|
//m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
|
||||||
|
// x.ControlFlags, x.Flags, x.Far, x.State);
|
||||||
|
//}
|
||||||
|
return movementSignificant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This checks the camera update significance against the last update made.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Can only be called by one thread at a time</remarks>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <param name='x'></param>
|
||||||
|
private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
|
||||||
|
{
|
||||||
|
float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
|
||||||
|
float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
|
||||||
|
float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
|
||||||
|
float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
|
||||||
|
|
||||||
|
bool cameraSignificant =
|
||||||
|
(vdelta1 > VDELTA) ||
|
||||||
|
(vdelta2 > VDELTA) ||
|
||||||
|
(vdelta3 > VDELTA) ||
|
||||||
|
(vdelta4 > VDELTA)
|
||||||
|
;
|
||||||
|
|
||||||
|
//if (cameraSignificant)
|
||||||
|
//{
|
||||||
|
//m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
|
||||||
|
// x.CameraAtAxis, x.CameraCenter);
|
||||||
|
//m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
|
||||||
|
// x.CameraLeftAxis, x.CameraUpAxis);
|
||||||
|
//}
|
||||||
|
|
||||||
|
return cameraSignificant;
|
||||||
|
}
|
||||||
|
|
||||||
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
|
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
|
||||||
{
|
{
|
||||||
if (OnAgentUpdate != null)
|
// We got here, which means that something in agent update was significant
|
||||||
|
|
||||||
|
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
|
||||||
|
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
|
||||||
|
|
||||||
|
if (x.AgentID != AgentId || x.SessionID != SessionId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Before we update the current m_thisAgentUpdateArgs, let's check this again
|
||||||
|
// to see what exactly changed
|
||||||
|
bool movement = CheckAgentMovementUpdateSignificance(x);
|
||||||
|
bool camera = CheckAgentCameraUpdateSignificance(x);
|
||||||
|
|
||||||
|
m_thisAgentUpdateArgs.AgentID = x.AgentID;
|
||||||
|
m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
|
||||||
|
m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
|
||||||
|
m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
|
||||||
|
m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
|
||||||
|
m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
|
||||||
|
m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
|
||||||
|
m_thisAgentUpdateArgs.Far = x.Far;
|
||||||
|
m_thisAgentUpdateArgs.Flags = x.Flags;
|
||||||
|
m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
|
||||||
|
m_thisAgentUpdateArgs.SessionID = x.SessionID;
|
||||||
|
m_thisAgentUpdateArgs.State = x.State;
|
||||||
|
|
||||||
|
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
|
||||||
|
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
|
||||||
|
UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
|
||||||
|
|
||||||
|
// Was there a significant movement/state change?
|
||||||
|
if (movement)
|
||||||
{
|
{
|
||||||
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
|
if (handlerPreAgentUpdate != null)
|
||||||
|
OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
|
||||||
|
|
||||||
#region Packet Session and User Check
|
if (handlerAgentUpdate != null)
|
||||||
if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
|
OnAgentUpdate(this, m_thisAgentUpdateArgs);
|
||||||
{
|
|
||||||
PacketPool.Instance.ReturnPacket(packet);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
bool update = false;
|
|
||||||
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
|
|
||||||
|
|
||||||
if (m_lastAgentUpdateArgs != null)
|
|
||||||
{
|
|
||||||
// These should be ordered from most-likely to
|
|
||||||
// least likely to change. I've made an initial
|
|
||||||
// guess at that.
|
|
||||||
update =
|
|
||||||
(
|
|
||||||
(x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
|
|
||||||
(x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
|
|
||||||
(x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
|
|
||||||
(x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
|
|
||||||
(x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
|
|
||||||
(x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
|
|
||||||
(x.ControlFlags != 0) ||
|
|
||||||
(x.Far != m_lastAgentUpdateArgs.Far) ||
|
|
||||||
(x.Flags != m_lastAgentUpdateArgs.Flags) ||
|
|
||||||
(x.State != m_lastAgentUpdateArgs.State) ||
|
|
||||||
(x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
|
|
||||||
(x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
|
|
||||||
(x.AgentID != m_lastAgentUpdateArgs.AgentID)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_lastAgentUpdateArgs = new AgentUpdateArgs();
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (update)
|
|
||||||
{
|
|
||||||
// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
|
|
||||||
|
|
||||||
m_lastAgentUpdateArgs.AgentID = x.AgentID;
|
|
||||||
m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
|
|
||||||
m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
|
|
||||||
m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
|
|
||||||
m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
|
|
||||||
m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
|
|
||||||
m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
|
|
||||||
m_lastAgentUpdateArgs.Far = x.Far;
|
|
||||||
m_lastAgentUpdateArgs.Flags = x.Flags;
|
|
||||||
m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
|
|
||||||
m_lastAgentUpdateArgs.SessionID = x.SessionID;
|
|
||||||
m_lastAgentUpdateArgs.State = x.State;
|
|
||||||
|
|
||||||
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
|
|
||||||
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
|
|
||||||
|
|
||||||
if (handlerPreAgentUpdate != null)
|
|
||||||
OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
|
|
||||||
|
|
||||||
if (handlerAgentUpdate != null)
|
|
||||||
OnAgentUpdate(this, m_lastAgentUpdateArgs);
|
|
||||||
|
|
||||||
handlerAgentUpdate = null;
|
|
||||||
handlerPreAgentUpdate = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Was there a significant camera(s) change?
|
||||||
|
if (camera)
|
||||||
|
if (handlerAgentCameraUpdate != null)
|
||||||
|
handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
|
||||||
|
|
||||||
|
handlerAgentUpdate = null;
|
||||||
|
handlerPreAgentUpdate = null;
|
||||||
|
handlerAgentCameraUpdate = null;
|
||||||
|
|
||||||
PacketPool.Instance.ReturnPacket(packet);
|
PacketPool.Instance.ReturnPacket(packet);
|
||||||
|
|
||||||
|
@ -12813,7 +12896,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
OutPacket(dialog, ThrottleOutPacketType.Task);
|
OutPacket(dialog, ThrottleOutPacketType.Task);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopFlying(ISceneEntity p)
|
public void SendAgentTerseUpdate(ISceneEntity p)
|
||||||
{
|
{
|
||||||
if (p is ScenePresence)
|
if (p is ScenePresence)
|
||||||
{
|
{
|
||||||
|
@ -12827,25 +12910,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
Vector3 pos = presence.AbsolutePosition;
|
Vector3 pos = presence.AbsolutePosition;
|
||||||
|
|
||||||
if (presence.Appearance.AvatarHeight != 127.0f)
|
|
||||||
pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
|
|
||||||
else
|
|
||||||
pos += new Vector3(0f, 0f, (1.56f/6f));
|
|
||||||
|
|
||||||
presence.AbsolutePosition = pos;
|
|
||||||
|
|
||||||
// attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
|
|
||||||
// Collision plane below the avatar's position a 6th of the avatar's height is suitable.
|
|
||||||
// Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
|
|
||||||
// certain amount.. because the LLClient wouldn't land in that situation anyway.
|
|
||||||
|
|
||||||
// why are we still testing for this really old height value default???
|
|
||||||
if (presence.Appearance.AvatarHeight != 127.0f)
|
|
||||||
presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
|
|
||||||
else
|
|
||||||
presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
|
|
||||||
|
|
||||||
|
|
||||||
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
|
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
|
||||||
CreateImprovedTerseBlock(p, false);
|
CreateImprovedTerseBlock(p, false);
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasUpdates()
|
||||||
|
{
|
||||||
|
J2KImage image = GetHighestPriorityImage();
|
||||||
|
|
||||||
|
return image != null && image.IsDecoded;
|
||||||
|
}
|
||||||
|
|
||||||
public bool ProcessImageQueue(int packetsToSend)
|
public bool ProcessImageQueue(int packetsToSend)
|
||||||
{
|
{
|
||||||
int packetsSent = 0;
|
int packetsSent = 0;
|
||||||
|
|
|
@ -31,6 +31,7 @@ using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Monitoring;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenMetaverse.Packets;
|
using OpenMetaverse.Packets;
|
||||||
|
|
||||||
|
@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// hooked to put more data on the empty queue</summary>
|
/// hooked to put more data on the empty queue</summary>
|
||||||
public event QueueEmpty OnQueueEmpty;
|
public event QueueEmpty OnQueueEmpty;
|
||||||
|
|
||||||
|
public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
|
||||||
|
|
||||||
/// <summary>AgentID for this client</summary>
|
/// <summary>AgentID for this client</summary>
|
||||||
public readonly UUID AgentID;
|
public readonly UUID AgentID;
|
||||||
/// <summary>The remote address of the connected client</summary>
|
/// <summary>The remote address of the connected client</summary>
|
||||||
|
@ -645,15 +648,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// <param name="categories">Throttle categories to fire the callback for</param>
|
/// <param name="categories">Throttle categories to fire the callback for</param>
|
||||||
private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
|
private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
|
||||||
{
|
{
|
||||||
if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
||||||
|
if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
||||||
{
|
{
|
||||||
|
m_isQueueEmptyRunning = true;
|
||||||
|
|
||||||
|
int start = Environment.TickCount & Int32.MaxValue;
|
||||||
|
const int MIN_CALLBACK_MS = 30;
|
||||||
|
|
||||||
|
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
||||||
|
if (m_nextOnQueueEmpty == 0)
|
||||||
|
m_nextOnQueueEmpty = 1;
|
||||||
|
|
||||||
// Use a value of 0 to signal that FireQueueEmpty is running
|
// Use a value of 0 to signal that FireQueueEmpty is running
|
||||||
m_nextOnQueueEmpty = 0;
|
// m_nextOnQueueEmpty = 0;
|
||||||
// Asynchronously run the callback
|
|
||||||
Util.FireAndForget(FireQueueEmpty, categories);
|
m_categories = categories;
|
||||||
|
|
||||||
|
if (HasUpdates(m_categories))
|
||||||
|
{
|
||||||
|
// Asynchronously run the callback
|
||||||
|
Util.FireAndForget(FireQueueEmpty, categories);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_isQueueEmptyRunning = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool m_isQueueEmptyRunning;
|
||||||
|
private ThrottleOutPacketTypeFlags m_categories = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fires the OnQueueEmpty callback and sets the minimum time that it
|
/// Fires the OnQueueEmpty callback and sets the minimum time that it
|
||||||
/// can be called again
|
/// can be called again
|
||||||
|
@ -663,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// signature</param>
|
/// signature</param>
|
||||||
private void FireQueueEmpty(object o)
|
private void FireQueueEmpty(object o)
|
||||||
{
|
{
|
||||||
const int MIN_CALLBACK_MS = 30;
|
// int start = Environment.TickCount & Int32.MaxValue;
|
||||||
|
// const int MIN_CALLBACK_MS = 30;
|
||||||
|
|
||||||
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
|
// if (m_udpServer.IsRunningOutbound)
|
||||||
QueueEmpty callback = OnQueueEmpty;
|
// {
|
||||||
|
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
|
||||||
|
QueueEmpty callback = OnQueueEmpty;
|
||||||
|
|
||||||
int start = Environment.TickCount & Int32.MaxValue;
|
if (callback != null)
|
||||||
|
{
|
||||||
|
// if (m_udpServer.IsRunningOutbound)
|
||||||
|
// {
|
||||||
|
try { callback(categories); }
|
||||||
|
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
|
||||||
if (callback != null)
|
// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
||||||
{
|
// if (m_nextOnQueueEmpty == 0)
|
||||||
try { callback(categories); }
|
// m_nextOnQueueEmpty = 1;
|
||||||
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
|
|
||||||
}
|
|
||||||
|
|
||||||
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
// }
|
||||||
if (m_nextOnQueueEmpty == 0)
|
|
||||||
m_nextOnQueueEmpty = 1;
|
m_isQueueEmptyRunning = false;
|
||||||
}
|
}
|
||||||
internal void ForceThrottleSetting(int throttle, int setting)
|
internal void ForceThrottleSetting(int throttle, int setting)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,11 +67,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
m_udpServer.AddScene(scene);
|
m_udpServer.AddScene(scene);
|
||||||
|
|
||||||
|
StatsManager.RegisterStat(
|
||||||
|
new Stat(
|
||||||
|
"IncomingUDPReceivesCount",
|
||||||
|
"Number of UDP receives performed",
|
||||||
|
"Number of UDP receives performed",
|
||||||
|
"",
|
||||||
|
"clientstack",
|
||||||
|
scene.Name,
|
||||||
|
StatType.Pull,
|
||||||
|
MeasuresOfInterest.AverageChangeOverTime,
|
||||||
|
stat => stat.Value = m_udpServer.UdpReceives,
|
||||||
|
StatVerbosity.Debug));
|
||||||
|
|
||||||
StatsManager.RegisterStat(
|
StatsManager.RegisterStat(
|
||||||
new Stat(
|
new Stat(
|
||||||
"IncomingPacketsProcessedCount",
|
"IncomingPacketsProcessedCount",
|
||||||
"Number of inbound UDP packets processed",
|
"Number of inbound LL protocol packets processed",
|
||||||
"Number of inbound UDP packets processed",
|
"Number of inbound LL protocol packets processed",
|
||||||
"",
|
"",
|
||||||
"clientstack",
|
"clientstack",
|
||||||
scene.Name,
|
scene.Name,
|
||||||
|
@ -79,6 +92,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
MeasuresOfInterest.AverageChangeOverTime,
|
MeasuresOfInterest.AverageChangeOverTime,
|
||||||
stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
|
stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
|
||||||
StatVerbosity.Debug));
|
StatVerbosity.Debug));
|
||||||
|
|
||||||
|
StatsManager.RegisterStat(
|
||||||
|
new Stat(
|
||||||
|
"OutgoingUDPSendsCount",
|
||||||
|
"Number of UDP sends performed",
|
||||||
|
"Number of UDP sends performed",
|
||||||
|
"",
|
||||||
|
"clientstack",
|
||||||
|
scene.Name,
|
||||||
|
StatType.Pull,
|
||||||
|
MeasuresOfInterest.AverageChangeOverTime,
|
||||||
|
stat => stat.Value = m_udpServer.UdpSends,
|
||||||
|
StatVerbosity.Debug));
|
||||||
|
|
||||||
|
StatsManager.RegisterStat(
|
||||||
|
new Stat(
|
||||||
|
"AverageUDPProcessTime",
|
||||||
|
"Average number of milliseconds taken to process each incoming UDP packet in a sample.",
|
||||||
|
"This is for initial receive processing which is separate from the later client LL packet processing stage.",
|
||||||
|
"ms",
|
||||||
|
"clientstack",
|
||||||
|
scene.Name,
|
||||||
|
StatType.Pull,
|
||||||
|
MeasuresOfInterest.None,
|
||||||
|
stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
|
||||||
|
// stat =>
|
||||||
|
// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
|
||||||
|
StatVerbosity.Debug));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HandlesRegion(Location x)
|
public bool HandlesRegion(Location x)
|
||||||
|
@ -185,6 +226,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
protected bool m_sendPing;
|
protected bool m_sendPing;
|
||||||
|
|
||||||
private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
|
private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event used to signal when queued packets are available for sending.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
|
||||||
|
/// Some data is sent immediately and not queued. That data would not trigger this event.
|
||||||
|
/// </remarks>
|
||||||
|
private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
|
||||||
|
|
||||||
private Pool<IncomingPacket> m_incomingPacketPool;
|
private Pool<IncomingPacket> m_incomingPacketPool;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -462,6 +513,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
m_scene = (Scene)scene;
|
m_scene = (Scene)scene;
|
||||||
m_location = new Location(m_scene.RegionInfo.RegionHandle);
|
m_location = new Location(m_scene.RegionInfo.RegionHandle);
|
||||||
|
|
||||||
|
StatsManager.RegisterStat(
|
||||||
|
new Stat(
|
||||||
|
"InboxPacketsCount",
|
||||||
|
"Number of LL protocol packets waiting for the second stage of processing after initial receive.",
|
||||||
|
"Number of LL protocol packets waiting for the second stage of processing after initial receive.",
|
||||||
|
"",
|
||||||
|
"clientstack",
|
||||||
|
scene.Name,
|
||||||
|
StatType.Pull,
|
||||||
|
MeasuresOfInterest.AverageChangeOverTime,
|
||||||
|
stat => stat.Value = packetInbox.Count,
|
||||||
|
StatVerbosity.Debug));
|
||||||
|
|
||||||
// XXX: These stats are also pool stats but we register them separately since they are currently not
|
// XXX: These stats are also pool stats but we register them separately since they are currently not
|
||||||
// turned on and off by EnablePools()/DisablePools()
|
// turned on and off by EnablePools()/DisablePools()
|
||||||
StatsManager.RegisterStat(
|
StatsManager.RegisterStat(
|
||||||
|
@ -575,6 +639,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
"debug lludp status",
|
"debug lludp status",
|
||||||
"Return status of LLUDP packet processing.",
|
"Return status of LLUDP packet processing.",
|
||||||
HandleStatusCommand);
|
HandleStatusCommand);
|
||||||
|
|
||||||
|
MainConsole.Instance.Commands.AddCommand(
|
||||||
|
"Debug",
|
||||||
|
false,
|
||||||
|
"debug lludp toggle agentupdate",
|
||||||
|
"debug lludp toggle agentupdate",
|
||||||
|
"Toggle whether agentupdate packets are processed or simply discarded.",
|
||||||
|
HandleAgentUpdateCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePacketCommand(string module, string[] args)
|
private void HandlePacketCommand(string module, string[] args)
|
||||||
|
@ -709,6 +781,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool m_discardAgentUpdates;
|
||||||
|
|
||||||
|
private void HandleAgentUpdateCommand(string module, string[] args)
|
||||||
|
{
|
||||||
|
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_discardAgentUpdates = !m_discardAgentUpdates;
|
||||||
|
|
||||||
|
MainConsole.Instance.OutputFormat(
|
||||||
|
"Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleStatusCommand(string module, string[] args)
|
private void HandleStatusCommand(string module, string[] args)
|
||||||
{
|
{
|
||||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||||
|
@ -809,12 +894,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketPool.Instance.ReturnPacket(packet);
|
PacketPool.Instance.ReturnPacket(packet);
|
||||||
|
|
||||||
m_dataPresentEvent.Set();
|
m_dataPresentEvent.Set();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start the process of sending a packet to the client.
|
/// Start the process of sending a packet to the client.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1325,6 +1408,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
|
LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
|
||||||
#endregion BinaryStats
|
#endregion BinaryStats
|
||||||
|
|
||||||
|
if (packet.Type == PacketType.AgentUpdate)
|
||||||
|
{
|
||||||
|
if (m_discardAgentUpdates)
|
||||||
|
return;
|
||||||
|
|
||||||
|
((LLClientView)client).TotalAgentUpdates++;
|
||||||
|
|
||||||
|
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
|
||||||
|
|
||||||
|
LLClientView llClient = client as LLClientView;
|
||||||
|
if (agentUpdate.AgentData.SessionID != client.SessionId
|
||||||
|
|| agentUpdate.AgentData.AgentID != client.AgentId
|
||||||
|
|| !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
|
||||||
|
{
|
||||||
|
PacketPool.Instance.ReturnPacket(packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Ping Check Handling
|
#region Ping Check Handling
|
||||||
|
|
||||||
if (packet.Type == PacketType.StartPingCheck)
|
if (packet.Type == PacketType.StartPingCheck)
|
||||||
|
@ -1734,7 +1836,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// Action generic every round
|
// Action generic every round
|
||||||
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
|
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
|
||||||
|
|
||||||
// while (true)
|
|
||||||
while (base.IsRunningOutbound)
|
while (base.IsRunningOutbound)
|
||||||
{
|
{
|
||||||
m_scene.ThreadAlive(2);
|
m_scene.ThreadAlive(2);
|
||||||
|
@ -1798,6 +1899,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// token bucket could get more tokens
|
// token bucket could get more tokens
|
||||||
//if (!m_packetSent)
|
//if (!m_packetSent)
|
||||||
// Thread.Sleep((int)TickCountResolution);
|
// Thread.Sleep((int)TickCountResolution);
|
||||||
|
//
|
||||||
|
// Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
|
||||||
|
// modern mono it reduces CPU base load since there is no more continuous polling.
|
||||||
m_dataPresentEvent.WaitOne(100);
|
m_dataPresentEvent.WaitOne(100);
|
||||||
|
|
||||||
Watchdog.UpdateThread();
|
Watchdog.UpdateThread();
|
||||||
|
|
|
@ -77,6 +77,36 @@ namespace OpenMetaverse
|
||||||
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
|
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
|
||||||
public bool IsRunningOutbound { get; private set; }
|
public bool IsRunningOutbound { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of UDP receives.
|
||||||
|
/// </summary>
|
||||||
|
public int UdpReceives { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of UDP sends
|
||||||
|
/// </summary>
|
||||||
|
public int UdpSends { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of receives over which to establish a receive time average.
|
||||||
|
/// </summary>
|
||||||
|
private readonly static int s_receiveTimeSamples = 500;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current number of samples taken to establish a receive time average.
|
||||||
|
/// </summary>
|
||||||
|
private int m_currentReceiveTimeSamples;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cumulative receive time for the sample so far.
|
||||||
|
/// </summary>
|
||||||
|
private int m_receiveTicksInCurrentSamplePeriod;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The average time taken for each require receive in the last sample.
|
||||||
|
/// </summary>
|
||||||
|
public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -111,6 +141,8 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
if (!IsRunningInbound)
|
if (!IsRunningInbound)
|
||||||
{
|
{
|
||||||
|
m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
|
||||||
|
|
||||||
const int SIO_UDP_CONNRESET = -1744830452;
|
const int SIO_UDP_CONNRESET = -1744830452;
|
||||||
|
|
||||||
IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
|
IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
|
||||||
|
@ -151,6 +183,8 @@ namespace OpenMetaverse
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void StartOutbound()
|
public void StartOutbound()
|
||||||
{
|
{
|
||||||
|
m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
|
||||||
|
|
||||||
IsRunningOutbound = true;
|
IsRunningOutbound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,10 +192,8 @@ namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
if (IsRunningInbound)
|
if (IsRunningInbound)
|
||||||
{
|
{
|
||||||
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
|
m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
|
||||||
// will deny any more reader locks, in effect blocking all other send/receive
|
|
||||||
// threads. Once we have the lock, we set IsRunningInbound = false to inform the other
|
|
||||||
// threads that the socket is closed.
|
|
||||||
IsRunningInbound = false;
|
IsRunningInbound = false;
|
||||||
m_udpSocket.Close();
|
m_udpSocket.Close();
|
||||||
}
|
}
|
||||||
|
@ -169,6 +201,8 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
public void StopOutbound()
|
public void StopOutbound()
|
||||||
{
|
{
|
||||||
|
m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
|
||||||
|
|
||||||
IsRunningOutbound = false;
|
IsRunningOutbound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +301,8 @@ namespace OpenMetaverse
|
||||||
// to AsyncBeginReceive
|
// to AsyncBeginReceive
|
||||||
if (IsRunningInbound)
|
if (IsRunningInbound)
|
||||||
{
|
{
|
||||||
|
UdpReceives++;
|
||||||
|
|
||||||
// Asynchronous mode will start another receive before the
|
// Asynchronous mode will start another receive before the
|
||||||
// callback for this packet is even fired. Very parallel :-)
|
// callback for this packet is even fired. Very parallel :-)
|
||||||
if (m_asyncPacketHandling)
|
if (m_asyncPacketHandling)
|
||||||
|
@ -278,6 +314,8 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
int startTick = Util.EnvironmentTickCount();
|
||||||
|
|
||||||
// get the length of data actually read from the socket, store it with the
|
// get the length of data actually read from the socket, store it with the
|
||||||
// buffer
|
// buffer
|
||||||
buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
|
buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
|
||||||
|
@ -285,6 +323,23 @@ namespace OpenMetaverse
|
||||||
// call the abstract method PacketReceived(), passing the buffer that
|
// call the abstract method PacketReceived(), passing the buffer that
|
||||||
// has just been filled from the socket read.
|
// has just been filled from the socket read.
|
||||||
PacketReceived(buffer);
|
PacketReceived(buffer);
|
||||||
|
|
||||||
|
// If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
|
||||||
|
// then a particular stat may be inaccurate due to a race condition. We won't worry about this
|
||||||
|
// since this should be rare and won't cause a runtime problem.
|
||||||
|
if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
|
||||||
|
{
|
||||||
|
AverageReceiveTicksForLastSamplePeriod
|
||||||
|
= (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
|
||||||
|
|
||||||
|
m_receiveTicksInCurrentSamplePeriod = 0;
|
||||||
|
m_currentReceiveTimeSamples = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
|
||||||
|
m_currentReceiveTimeSamples++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (SocketException) { }
|
catch (SocketException) { }
|
||||||
catch (ObjectDisposedException) { }
|
catch (ObjectDisposedException) { }
|
||||||
|
@ -298,14 +353,13 @@ namespace OpenMetaverse
|
||||||
if (!m_asyncPacketHandling)
|
if (!m_asyncPacketHandling)
|
||||||
AsyncBeginReceive();
|
AsyncBeginReceive();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AsyncBeginSend(UDPPacketBuffer buf)
|
public void AsyncBeginSend(UDPPacketBuffer buf)
|
||||||
{
|
{
|
||||||
if (IsRunningOutbound)
|
// if (IsRunningOutbound)
|
||||||
{
|
// {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_udpSocket.BeginSendTo(
|
m_udpSocket.BeginSendTo(
|
||||||
|
@ -319,7 +373,7 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
catch (SocketException) { }
|
catch (SocketException) { }
|
||||||
catch (ObjectDisposedException) { }
|
catch (ObjectDisposedException) { }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEndSend(IAsyncResult result)
|
void AsyncEndSend(IAsyncResult result)
|
||||||
|
@ -328,6 +382,8 @@ namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
|
// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
|
||||||
m_udpSocket.EndSendTo(result);
|
m_udpSocket.EndSendTo(result);
|
||||||
|
|
||||||
|
UdpSends++;
|
||||||
}
|
}
|
||||||
catch (SocketException) { }
|
catch (SocketException) { }
|
||||||
catch (ObjectDisposedException) { }
|
catch (ObjectDisposedException) { }
|
||||||
|
|
|
@ -185,8 +185,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel)
|
public void UploadInventoryItem(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel)
|
||||||
{
|
{
|
||||||
|
if (type == AssetType.Link)
|
||||||
|
return;
|
||||||
|
|
||||||
string userAssetServer = string.Empty;
|
string userAssetServer = string.Empty;
|
||||||
if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission)
|
if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission)
|
||||||
{
|
{
|
||||||
|
@ -221,7 +224,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
{
|
{
|
||||||
UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data);
|
UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data);
|
||||||
|
|
||||||
UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0);
|
UploadInventoryItem(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0);
|
||||||
|
|
||||||
return newAssetID;
|
return newAssetID;
|
||||||
}
|
}
|
||||||
|
@ -232,7 +235,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
protected override void ExportAsset(UUID agentID, UUID assetID)
|
protected override void ExportAsset(UUID agentID, UUID assetID)
|
||||||
{
|
{
|
||||||
if (!assetID.Equals(UUID.Zero))
|
if (!assetID.Equals(UUID.Zero))
|
||||||
UploadInventoryItem(agentID, assetID, "", 0);
|
UploadInventoryItem(agentID, AssetType.Unknown, assetID, "", 0);
|
||||||
else
|
else
|
||||||
m_log.Debug("[HGScene]: Scene.Inventory did not create asset");
|
m_log.Debug("[HGScene]: Scene.Inventory did not create asset");
|
||||||
}
|
}
|
||||||
|
@ -348,7 +351,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
|
InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
|
||||||
InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
|
InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
|
||||||
|
|
||||||
inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray());
|
List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
|
||||||
|
|
||||||
|
foreach (InventoryFolderBase f in content.Folders)
|
||||||
|
{
|
||||||
|
if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
|
||||||
|
keep.Add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,7 +392,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
|
|
||||||
foreach (InventoryFolderBase f in content.Folders)
|
foreach (InventoryFolderBase f in content.Folders)
|
||||||
{
|
{
|
||||||
if (f.Name != "My Suitcase")
|
if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
|
||||||
{
|
{
|
||||||
f.Name = f.Name + " (Unavailable)";
|
f.Name = f.Name + " (Unavailable)";
|
||||||
keep.Add(f);
|
keep.Add(f);
|
||||||
|
|
|
@ -389,7 +389,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
||||||
}
|
}
|
||||||
|
|
||||||
names[0] = "Unknown";
|
names[0] = "Unknown";
|
||||||
names[1] = "UserUMMTGUN7";
|
names[1] = "UserUMMTGUN8";
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -601,7 +601,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
||||||
// TODO: Can be removed when GUN* unknown users have definitely dropped significantly or
|
// TODO: Can be removed when GUN* unknown users have definitely dropped significantly or
|
||||||
// disappeared.
|
// disappeared.
|
||||||
user.FirstName = "Unknown";
|
user.FirstName = "Unknown";
|
||||||
user.LastName = "UserUMMAU3";
|
user.LastName = "UserUMMAU4";
|
||||||
}
|
}
|
||||||
|
|
||||||
AddUserInternal(user);
|
AddUserInternal(user);
|
||||||
|
|
|
@ -743,7 +743,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
public event OnIncomingSceneObjectDelegate OnIncomingSceneObject;
|
public event OnIncomingSceneObjectDelegate OnIncomingSceneObject;
|
||||||
public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so);
|
public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so);
|
||||||
|
|
||||||
public delegate void NewInventoryItemUploadComplete(UUID avatarID, UUID assetID, string name, int userlevel);
|
public delegate void NewInventoryItemUploadComplete(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel);
|
||||||
|
|
||||||
public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete;
|
public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete;
|
||||||
|
|
||||||
|
@ -2172,7 +2172,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, UUID AssetID, String AssetName, int userlevel)
|
public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, AssetType type, UUID AssetID, String AssetName, int userlevel)
|
||||||
{
|
{
|
||||||
NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete;
|
NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete;
|
||||||
if (handlerNewInventoryItemUpdateComplete != null)
|
if (handlerNewInventoryItemUpdateComplete != null)
|
||||||
|
@ -2181,7 +2181,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
d(agentID, AssetID, AssetName, userlevel);
|
d(agentID, type, AssetID, AssetName, userlevel);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -139,7 +139,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
userlevel = 1;
|
userlevel = 1;
|
||||||
}
|
}
|
||||||
EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel);
|
EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
userlevel = 1;
|
userlevel = 1;
|
||||||
}
|
}
|
||||||
EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel);
|
EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
|
||||||
|
|
||||||
if (originalFolder != UUID.Zero)
|
if (originalFolder != UUID.Zero)
|
||||||
{
|
{
|
||||||
|
|
|
@ -416,6 +416,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args)
|
void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args)
|
||||||
{
|
{
|
||||||
// TODO: don't create new blocks if recycling an old packet
|
// TODO: don't create new blocks if recycling an old packet
|
||||||
|
bool discardableEffects = true;
|
||||||
ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count];
|
ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count];
|
||||||
for (int i = 0; i < args.Count; i++)
|
for (int i = 0; i < args.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -427,15 +428,32 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
effect.Type = args[i].Type;
|
effect.Type = args[i].Type;
|
||||||
effect.TypeData = args[i].TypeData;
|
effect.TypeData = args[i].TypeData;
|
||||||
effectBlockArray[i] = effect;
|
effectBlockArray[i] = effect;
|
||||||
|
|
||||||
|
if ((EffectType)effect.Type != EffectType.LookAt && (EffectType)effect.Type != EffectType.Beam)
|
||||||
|
discardableEffects = false;
|
||||||
|
|
||||||
|
//m_log.DebugFormat("[YYY]: VE {0} {1} {2}", effect.AgentID, effect.Duration, (EffectType)effect.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEachClient(
|
ForEachScenePresence(sp =>
|
||||||
delegate(IClientAPI client)
|
|
||||||
{
|
{
|
||||||
if (client.AgentId != remoteClient.AgentId)
|
if (sp.ControllingClient.AgentId != remoteClient.AgentId)
|
||||||
client.SendViewerEffect(effectBlockArray);
|
{
|
||||||
}
|
if (!discardableEffects ||
|
||||||
);
|
(discardableEffects && ShouldSendDiscardableEffect(remoteClient, sp)))
|
||||||
|
{
|
||||||
|
//m_log.DebugFormat("[YYY]: Sending to {0}", sp.UUID);
|
||||||
|
sp.ControllingClient.SendViewerEffect(effectBlockArray);
|
||||||
|
}
|
||||||
|
//else
|
||||||
|
// m_log.DebugFormat("[YYY]: Not sending to {0}", sp.UUID);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShouldSendDiscardableEffect(IClientAPI thisClient, ScenePresence other)
|
||||||
|
{
|
||||||
|
return Vector3.Distance(other.CameraPosition, thisClient.SceneAgent.AbsolutePosition) < 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DescendentsRequestData
|
private class DescendentsRequestData
|
||||||
|
|
|
@ -142,6 +142,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
private Vector3 m_lastVelocity;
|
private Vector3 m_lastVelocity;
|
||||||
private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f);
|
private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f);
|
||||||
|
|
||||||
|
private bool m_followCamAuto = false;
|
||||||
|
|
||||||
|
|
||||||
private Vector3? m_forceToApply;
|
private Vector3? m_forceToApply;
|
||||||
private int m_userFlags;
|
private int m_userFlags;
|
||||||
|
@ -874,6 +876,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
|
ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
|
||||||
ControllingClient.OnAgentUpdate += HandleAgentUpdate;
|
ControllingClient.OnAgentUpdate += HandleAgentUpdate;
|
||||||
|
ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate;
|
||||||
ControllingClient.OnAgentRequestSit += HandleAgentRequestSit;
|
ControllingClient.OnAgentRequestSit += HandleAgentRequestSit;
|
||||||
ControllingClient.OnAgentSit += HandleAgentSit;
|
ControllingClient.OnAgentSit += HandleAgentSit;
|
||||||
ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun;
|
ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun;
|
||||||
|
@ -1306,7 +1309,26 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public void StopFlying()
|
public void StopFlying()
|
||||||
{
|
{
|
||||||
ControllingClient.StopFlying(this);
|
Vector3 pos = AbsolutePosition;
|
||||||
|
if (Appearance.AvatarHeight != 127.0f)
|
||||||
|
pos += new Vector3(0f, 0f, (Appearance.AvatarHeight / 6f));
|
||||||
|
else
|
||||||
|
pos += new Vector3(0f, 0f, (1.56f / 6f));
|
||||||
|
|
||||||
|
AbsolutePosition = pos;
|
||||||
|
|
||||||
|
// attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
|
||||||
|
// Collision plane below the avatar's position a 6th of the avatar's height is suitable.
|
||||||
|
// Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
|
||||||
|
// certain amount.. because the LLClient wouldn't land in that situation anyway.
|
||||||
|
|
||||||
|
// why are we still testing for this really old height value default???
|
||||||
|
if (Appearance.AvatarHeight != 127.0f)
|
||||||
|
CollisionPlane = new Vector4(0, 0, 0, pos.Z - Appearance.AvatarHeight / 6f);
|
||||||
|
else
|
||||||
|
CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f / 6f));
|
||||||
|
|
||||||
|
ControllingClient.SendAgentTerseUpdate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1662,9 +1684,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
|
public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat(
|
//m_log.DebugFormat(
|
||||||
// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
|
// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
|
||||||
// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
|
// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
|
||||||
|
|
||||||
if (IsChildAgent)
|
if (IsChildAgent)
|
||||||
{
|
{
|
||||||
|
@ -1672,10 +1694,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
++m_movementUpdateCount;
|
|
||||||
if (m_movementUpdateCount < 1)
|
|
||||||
m_movementUpdateCount = 1;
|
|
||||||
|
|
||||||
#region Sanity Checking
|
#region Sanity Checking
|
||||||
|
|
||||||
// This is irritating. Really.
|
// This is irritating. Really.
|
||||||
|
@ -1706,21 +1724,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
|
AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
|
||||||
|
|
||||||
// Camera location in world. We'll need to raytrace
|
|
||||||
// from this location from time to time.
|
|
||||||
CameraPosition = agentData.CameraCenter;
|
|
||||||
if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
|
|
||||||
{
|
|
||||||
ReprioritizeUpdates();
|
|
||||||
m_lastCameraPosition = CameraPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use these three vectors to figure out what the agent is looking at
|
|
||||||
// Convert it to a Matrix and/or Quaternion
|
|
||||||
CameraAtAxis = agentData.CameraAtAxis;
|
|
||||||
CameraLeftAxis = agentData.CameraLeftAxis;
|
|
||||||
CameraUpAxis = agentData.CameraUpAxis;
|
|
||||||
|
|
||||||
// The Agent's Draw distance setting
|
// The Agent's Draw distance setting
|
||||||
// When we get to the point of re-computing neighbors everytime this
|
// When we get to the point of re-computing neighbors everytime this
|
||||||
// changes, then start using the agent's drawdistance rather than the
|
// changes, then start using the agent's drawdistance rather than the
|
||||||
|
@ -2005,7 +2008,76 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
SendControlsToScripts(flagsForScripts);
|
SendControlsToScripts(flagsForScripts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to send this back to the client in order to see the edit beams
|
||||||
|
if ((State & (uint)AgentState.Editing) != 0)
|
||||||
|
ControllingClient.SendAgentTerseUpdate(this);
|
||||||
|
|
||||||
m_scene.EventManager.TriggerOnClientMovement(this);
|
m_scene.EventManager.TriggerOnClientMovement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering.
|
||||||
|
/// </summary>
|
||||||
|
private void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
|
||||||
|
{
|
||||||
|
//m_log.DebugFormat(
|
||||||
|
// "[SCENE PRESENCE]: In {0} received agent camera update from {1}, flags {2}",
|
||||||
|
// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
|
||||||
|
|
||||||
|
if (IsChildAgent)
|
||||||
|
{
|
||||||
|
// // m_log.Debug("DEBUG: HandleAgentUpdate: child agent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
++m_movementUpdateCount;
|
||||||
|
if (m_movementUpdateCount < 1)
|
||||||
|
m_movementUpdateCount = 1;
|
||||||
|
|
||||||
|
|
||||||
|
AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
|
||||||
|
|
||||||
|
// Camera location in world. We'll need to raytrace
|
||||||
|
// from this location from time to time.
|
||||||
|
CameraPosition = agentData.CameraCenter;
|
||||||
|
if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
|
||||||
|
{
|
||||||
|
ReprioritizeUpdates();
|
||||||
|
m_lastCameraPosition = CameraPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use these three vectors to figure out what the agent is looking at
|
||||||
|
// Convert it to a Matrix and/or Quaternion
|
||||||
|
CameraAtAxis = agentData.CameraAtAxis;
|
||||||
|
CameraLeftAxis = agentData.CameraLeftAxis;
|
||||||
|
CameraUpAxis = agentData.CameraUpAxis;
|
||||||
|
|
||||||
|
// The Agent's Draw distance setting
|
||||||
|
// When we get to the point of re-computing neighbors everytime this
|
||||||
|
// changes, then start using the agent's drawdistance rather than the
|
||||||
|
// region's draw distance.
|
||||||
|
// DrawDistance = agentData.Far;
|
||||||
|
DrawDistance = Scene.DefaultDrawDistance;
|
||||||
|
|
||||||
|
// Check if Client has camera in 'follow cam' or 'build' mode.
|
||||||
|
Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation);
|
||||||
|
|
||||||
|
m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)
|
||||||
|
&& (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false;
|
||||||
|
|
||||||
|
|
||||||
|
//m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto);
|
||||||
|
// Raycast from the avatar's head to the camera to see if there's anything blocking the view
|
||||||
|
if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast())
|
||||||
|
{
|
||||||
|
if (m_followCamAuto)
|
||||||
|
{
|
||||||
|
Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
|
||||||
|
m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TriggerScenePresenceUpdated();
|
TriggerScenePresenceUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -688,6 +688,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
|
||||||
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
||||||
public event UpdateAgent OnPreAgentUpdate;
|
public event UpdateAgent OnPreAgentUpdate;
|
||||||
public event UpdateAgent OnAgentUpdate;
|
public event UpdateAgent OnAgentUpdate;
|
||||||
|
public event UpdateAgent OnAgentCameraUpdate;
|
||||||
public event AgentRequestSit OnAgentRequestSit;
|
public event AgentRequestSit OnAgentRequestSit;
|
||||||
public event AgentSit OnAgentSit;
|
public event AgentSit OnAgentSit;
|
||||||
public event AvatarPickerRequest OnAvatarPickerRequest;
|
public event AvatarPickerRequest OnAvatarPickerRequest;
|
||||||
|
@ -1687,7 +1688,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopFlying(ISceneEntity presence)
|
public void SendAgentTerseUpdate(ISceneEntity presence)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -611,7 +611,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
|
||||||
//
|
//
|
||||||
if (showParams.Length <= 4)
|
if (showParams.Length <= 4)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,6} {3,11} {4, 10}", "Region", "Name", "Root", "Time", "Reqs/min");
|
m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "AgentUpdates");
|
||||||
foreach (Scene scene in m_scenes.Values)
|
foreach (Scene scene in m_scenes.Values)
|
||||||
{
|
{
|
||||||
scene.ForEachClient(
|
scene.ForEachClient(
|
||||||
|
@ -624,9 +624,15 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
|
||||||
int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
|
int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
|
||||||
avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
|
avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
|
||||||
|
|
||||||
m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,4} {3,9}min {4,10}",
|
m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
|
||||||
scene.RegionInfo.RegionName, llClient.Name,
|
scene.RegionInfo.RegionName, llClient.Name,
|
||||||
(llClient.SceneAgent.IsChildAgent ? "N" : "Y"), (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs);
|
llClient.SceneAgent.IsChildAgent ? "N" : "Y",
|
||||||
|
(DateTime.Now - cinfo.StartedTime).Minutes,
|
||||||
|
avg_reqs,
|
||||||
|
string.Format(
|
||||||
|
"{0} ({1:0.00}%)",
|
||||||
|
llClient.TotalAgentUpdates,
|
||||||
|
(float)cinfo.SyncRequests["AgentUpdate"] / llClient.TotalAgentUpdates * 100));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||||
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
||||||
public event UpdateAgent OnPreAgentUpdate;
|
public event UpdateAgent OnPreAgentUpdate;
|
||||||
public event UpdateAgent OnAgentUpdate;
|
public event UpdateAgent OnAgentUpdate;
|
||||||
|
public event UpdateAgent OnAgentCameraUpdate;
|
||||||
public event AgentRequestSit OnAgentRequestSit;
|
public event AgentRequestSit OnAgentRequestSit;
|
||||||
public event AgentSit OnAgentSit;
|
public event AgentSit OnAgentSit;
|
||||||
public event AvatarPickerRequest OnAvatarPickerRequest;
|
public event AvatarPickerRequest OnAvatarPickerRequest;
|
||||||
|
@ -1242,7 +1243,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopFlying(ISceneEntity presence)
|
public void SendAgentTerseUpdate(ISceneEntity presence)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class BSActorCollection
|
||||||
{
|
{
|
||||||
lock (m_actors)
|
lock (m_actors)
|
||||||
{
|
{
|
||||||
Release();
|
ForEachActor(a => a.Dispose());
|
||||||
m_actors.Clear();
|
m_actors.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,10 +98,6 @@ public class BSActorCollection
|
||||||
{
|
{
|
||||||
ForEachActor(a => a.SetEnabled(enabl));
|
ForEachActor(a => a.SetEnabled(enabl));
|
||||||
}
|
}
|
||||||
public void Release()
|
|
||||||
{
|
|
||||||
ForEachActor(a => a.Dispose());
|
|
||||||
}
|
|
||||||
public void Refresh()
|
public void Refresh()
|
||||||
{
|
{
|
||||||
ForEachActor(a => a.Refresh());
|
ForEachActor(a => a.Refresh());
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
private static string LogHeader = "[BULLETSIM VEHICLE]";
|
private static string LogHeader = "[BULLETSIM VEHICLE]";
|
||||||
|
|
||||||
// the prim this dynamic controller belongs to
|
// the prim this dynamic controller belongs to
|
||||||
private BSPrim ControllingPrim { get; set; }
|
private BSPrimLinkable ControllingPrim { get; set; }
|
||||||
|
|
||||||
private bool m_haveRegisteredForSceneEvents;
|
private bool m_haveRegisteredForSceneEvents;
|
||||||
|
|
||||||
|
@ -128,9 +128,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
|
public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
|
||||||
: base(myScene, myPrim, actorName)
|
: base(myScene, myPrim, actorName)
|
||||||
{
|
{
|
||||||
ControllingPrim = myPrim;
|
|
||||||
Type = Vehicle.TYPE_NONE;
|
Type = Vehicle.TYPE_NONE;
|
||||||
m_haveRegisteredForSceneEvents = false;
|
m_haveRegisteredForSceneEvents = false;
|
||||||
|
|
||||||
|
ControllingPrim = myPrim as BSPrimLinkable;
|
||||||
|
if (ControllingPrim == null)
|
||||||
|
{
|
||||||
|
// THIS CANNOT HAPPEN!!
|
||||||
|
}
|
||||||
|
VDetailLog("{0},Creation", ControllingPrim.LocalID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return 'true' if this vehicle is doing vehicle things
|
// Return 'true' if this vehicle is doing vehicle things
|
||||||
|
@ -585,6 +591,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// Friction affects are handled by this vehicle code
|
// Friction affects are handled by this vehicle code
|
||||||
m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
|
m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
|
||||||
m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
|
m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
|
||||||
|
// ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
|
||||||
|
// ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
|
||||||
|
|
||||||
// Moderate angular movement introduced by Bullet.
|
// Moderate angular movement introduced by Bullet.
|
||||||
// TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
|
// TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
|
||||||
|
@ -595,17 +603,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
// Vehicles report collision events so we know when it's on the ground
|
// Vehicles report collision events so we know when it's on the ground
|
||||||
m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
|
m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
|
||||||
|
// ControllingPrim.Linkset.SetPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
|
||||||
|
|
||||||
Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
|
Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
|
||||||
ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
|
ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
|
||||||
m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
|
m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
|
||||||
m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
|
m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
|
||||||
|
// ControllingPrim.Linkset.ComputeLocalInertia(BSParam.VehicleInertiaFactor);
|
||||||
|
|
||||||
// Set the gravity for the vehicle depending on the buoyancy
|
// Set the gravity for the vehicle depending on the buoyancy
|
||||||
// TODO: what should be done if prim and vehicle buoyancy differ?
|
// TODO: what should be done if prim and vehicle buoyancy differ?
|
||||||
m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
|
m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
|
||||||
// The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
|
// The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
|
||||||
m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
|
m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
|
||||||
|
// ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
|
||||||
|
|
||||||
VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
|
VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
|
||||||
ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
|
ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
|
||||||
|
@ -617,6 +628,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
if (ControllingPrim.PhysBody.HasPhysicalBody)
|
if (ControllingPrim.PhysBody.HasPhysicalBody)
|
||||||
m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
|
m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
|
||||||
|
// ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,6 +641,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// BSActor.Release()
|
// BSActor.Release()
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
|
VDetailLog("{0},Dispose", ControllingPrim.LocalID);
|
||||||
UnregisterForSceneEvents();
|
UnregisterForSceneEvents();
|
||||||
Type = Vehicle.TYPE_NONE;
|
Type = Vehicle.TYPE_NONE;
|
||||||
Enabled = false;
|
Enabled = false;
|
||||||
|
@ -1001,7 +1014,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
else if (newVelocityLengthSq < 0.001f)
|
else if (newVelocityLengthSq < 0.001f)
|
||||||
VehicleVelocity = Vector3.Zero;
|
VehicleVelocity = Vector3.Zero;
|
||||||
|
|
||||||
VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity );
|
VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
|
||||||
|
|
||||||
} // end MoveLinear()
|
} // end MoveLinear()
|
||||||
|
|
||||||
|
@ -1029,8 +1042,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// Add this correction to the velocity to make it faster/slower.
|
// Add this correction to the velocity to make it faster/slower.
|
||||||
VehicleVelocity += linearMotorVelocityW;
|
VehicleVelocity += linearMotorVelocityW;
|
||||||
|
|
||||||
VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}",
|
VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
|
||||||
ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV,
|
ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
|
||||||
linearMotorVelocityW, VehicleVelocity, frictionFactorV);
|
linearMotorVelocityW, VehicleVelocity, frictionFactorV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1062,7 +1075,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation;
|
Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation;
|
||||||
|
|
||||||
// Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
|
// Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
|
||||||
if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.IsColliding)
|
if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision)
|
||||||
{
|
{
|
||||||
linearDeflectionW.Z = 0f;
|
linearDeflectionW.Z = 0f;
|
||||||
}
|
}
|
||||||
|
@ -1222,7 +1235,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
|
float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
|
||||||
distanceAboveGround = VehiclePosition.Z - targetHeight;
|
distanceAboveGround = VehiclePosition.Z - targetHeight;
|
||||||
// Not colliding if the vehicle is off the ground
|
// Not colliding if the vehicle is off the ground
|
||||||
if (!Prim.IsColliding)
|
if (!Prim.HasSomeCollision)
|
||||||
{
|
{
|
||||||
// downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
|
// downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
|
||||||
VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
|
VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
|
||||||
|
@ -1233,12 +1246,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// be computed with a motor.
|
// be computed with a motor.
|
||||||
// TODO: add interaction with banking.
|
// TODO: add interaction with banking.
|
||||||
VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
|
VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
|
||||||
Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
|
Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Another approach is to measure if we're going up. If going up and not colliding,
|
// Another approach is to measure if we're going up. If going up and not colliding,
|
||||||
// the vehicle is in the air. Fix that by pushing down.
|
// the vehicle is in the air. Fix that by pushing down.
|
||||||
if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1)
|
if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1)
|
||||||
{
|
{
|
||||||
// Get rid of any of the velocity vector that is pushing us up.
|
// Get rid of any of the velocity vector that is pushing us up.
|
||||||
float upVelocity = VehicleVelocity.Z;
|
float upVelocity = VehicleVelocity.Z;
|
||||||
|
@ -1260,7 +1273,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
|
VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
|
||||||
ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity);
|
ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1270,14 +1283,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
|
Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
|
||||||
|
|
||||||
// Hack to reduce downward force if the vehicle is probably sitting on the ground
|
// Hack to reduce downward force if the vehicle is probably sitting on the ground
|
||||||
if (ControllingPrim.IsColliding && IsGroundVehicle)
|
if (ControllingPrim.HasSomeCollision && IsGroundVehicle)
|
||||||
appliedGravity *= BSParam.VehicleGroundGravityFudge;
|
appliedGravity *= BSParam.VehicleGroundGravityFudge;
|
||||||
|
|
||||||
VehicleAddForce(appliedGravity);
|
VehicleAddForce(appliedGravity);
|
||||||
|
|
||||||
VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
|
VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
|
||||||
ControllingPrim.LocalID, m_VehicleGravity,
|
ControllingPrim.LocalID, m_VehicleGravity,
|
||||||
ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
|
ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
|
|
|
@ -203,6 +203,33 @@ public abstract class BSLinkset
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called after a simulation step to post a collision with this object.
|
||||||
|
// Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
|
||||||
|
// anything to add for the collision and it should be passed through normal processing.
|
||||||
|
// Default processing for a linkset.
|
||||||
|
public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee,
|
||||||
|
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
// prims in the same linkset cannot collide with each other
|
||||||
|
BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
|
||||||
|
if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
|
||||||
|
{
|
||||||
|
// By returning 'true', we tell the caller the collision has been 'handled' so it won't
|
||||||
|
// do anything about this collision and thus, effectivily, ignoring the collision.
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not a collision between members of the linkset. Must be a real collision.
|
||||||
|
// So the linkset root can know if there is a collision anywhere in the linkset.
|
||||||
|
LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// I am the root of a linkset and a new child is being added
|
// I am the root of a linkset and a new child is being added
|
||||||
// Called while LinkActivity is locked.
|
// Called while LinkActivity is locked.
|
||||||
protected abstract void AddChildToLinkset(BSPrimLinkable child);
|
protected abstract void AddChildToLinkset(BSPrimLinkable child);
|
||||||
|
@ -250,6 +277,73 @@ public abstract class BSLinkset
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
public abstract bool RemoveDependencies(BSPrimLinkable child);
|
public abstract bool RemoveDependencies(BSPrimLinkable child);
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// Some physical setting happen to all members of the linkset
|
||||||
|
public virtual void SetPhysicalFriction(float friction)
|
||||||
|
{
|
||||||
|
ForEachMember((member) =>
|
||||||
|
{
|
||||||
|
if (member.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.SetFriction(member.PhysBody, friction);
|
||||||
|
return false; // 'false' says to continue looping
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public virtual void SetPhysicalRestitution(float restitution)
|
||||||
|
{
|
||||||
|
ForEachMember((member) =>
|
||||||
|
{
|
||||||
|
if (member.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
|
||||||
|
return false; // 'false' says to continue looping
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
|
||||||
|
{
|
||||||
|
ForEachMember((member) =>
|
||||||
|
{
|
||||||
|
if (member.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
|
||||||
|
return false; // 'false' says to continue looping
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public virtual void ComputeLocalInertia(OMV.Vector3 inertiaFactor)
|
||||||
|
{
|
||||||
|
ForEachMember((member) =>
|
||||||
|
{
|
||||||
|
if (member.PhysBody.HasPhysicalBody)
|
||||||
|
{
|
||||||
|
OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass);
|
||||||
|
member.Inertia = inertia * inertiaFactor;
|
||||||
|
m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia);
|
||||||
|
m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
|
||||||
|
}
|
||||||
|
return false; // 'false' says to continue looping
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
|
||||||
|
{
|
||||||
|
ForEachMember((member) =>
|
||||||
|
{
|
||||||
|
if (member.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
|
||||||
|
return false; // 'false' says to continue looping
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
|
||||||
|
{
|
||||||
|
ForEachMember((member) =>
|
||||||
|
{
|
||||||
|
if (member.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
|
||||||
|
return false; // 'false' says to continue looping
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
// ================================================================
|
// ================================================================
|
||||||
protected virtual float ComputeLinksetMass()
|
protected virtual float ComputeLinksetMass()
|
||||||
{
|
{
|
||||||
|
@ -311,6 +405,5 @@ public abstract class BSLinkset
|
||||||
if (m_physicsScene.PhysicsLogging.Enabled)
|
if (m_physicsScene.PhysicsLogging.Enabled)
|
||||||
m_physicsScene.DetailLog(msg, args);
|
m_physicsScene.DetailLog(msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,42 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// Changing the physical property of the linkset only needs to change the root
|
||||||
|
public override void SetPhysicalFriction(float friction)
|
||||||
|
{
|
||||||
|
if (LinksetRoot.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
|
||||||
|
}
|
||||||
|
public override void SetPhysicalRestitution(float restitution)
|
||||||
|
{
|
||||||
|
if (LinksetRoot.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
|
||||||
|
}
|
||||||
|
public override void SetPhysicalGravity(OMV.Vector3 gravity)
|
||||||
|
{
|
||||||
|
if (LinksetRoot.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
|
||||||
|
}
|
||||||
|
public override void ComputeLocalInertia(OMV.Vector3 inertiaFactor)
|
||||||
|
{
|
||||||
|
OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, LinksetRoot.Mass);
|
||||||
|
LinksetRoot.Inertia = inertia * inertiaFactor;
|
||||||
|
m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, LinksetRoot.Mass, LinksetRoot.Inertia);
|
||||||
|
m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
|
||||||
|
}
|
||||||
|
public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
|
||||||
|
{
|
||||||
|
if (LinksetRoot.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
|
||||||
|
}
|
||||||
|
public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
|
||||||
|
{
|
||||||
|
if (LinksetRoot.PhysBody.HasPhysicalBody)
|
||||||
|
m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
|
||||||
|
}
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
// When physical properties are changed the linkset needs to recalculate
|
// When physical properties are changed the linkset needs to recalculate
|
||||||
// its internal properties.
|
// its internal properties.
|
||||||
public override void Refresh(BSPrimLinkable requestor)
|
public override void Refresh(BSPrimLinkable requestor)
|
||||||
|
@ -59,6 +95,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
|
DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
|
||||||
requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
|
requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
|
||||||
|
|
||||||
// When rebuilding, it is possible to set properties that would normally require a rebuild.
|
// When rebuilding, it is possible to set properties that would normally require a rebuild.
|
||||||
// If already rebuilding, don't request another rebuild.
|
// If already rebuilding, don't request another rebuild.
|
||||||
// If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
|
// If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
|
||||||
|
|
|
@ -48,12 +48,22 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
{
|
{
|
||||||
base.Refresh(requestor);
|
base.Refresh(requestor);
|
||||||
|
|
||||||
if (HasAnyChildren && IsRoot(requestor))
|
}
|
||||||
|
|
||||||
|
private void ScheduleRebuild(BSPrimLinkable requestor)
|
||||||
|
{
|
||||||
|
DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
|
||||||
|
requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
|
||||||
|
|
||||||
|
// When rebuilding, it is possible to set properties that would normally require a rebuild.
|
||||||
|
// If already rebuilding, don't request another rebuild.
|
||||||
|
// If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
|
||||||
|
if (!Rebuilding && HasAnyChildren)
|
||||||
{
|
{
|
||||||
// Queue to happen after all the other taint processing
|
// Queue to happen after all the other taint processing
|
||||||
m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
|
m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
|
||||||
{
|
{
|
||||||
if (HasAnyChildren && IsRoot(requestor))
|
if (HasAnyChildren)
|
||||||
RecomputeLinksetConstraints();
|
RecomputeLinksetConstraints();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -67,8 +77,14 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public override bool MakeDynamic(BSPrimLinkable child)
|
public override bool MakeDynamic(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
// What is done for each object in BSPrim is what we want.
|
bool ret = false;
|
||||||
return false;
|
DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
|
||||||
|
if (IsRoot(child))
|
||||||
|
{
|
||||||
|
// The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
|
||||||
|
ScheduleRebuild(LinksetRoot);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The object is going static (non-physical). Do any setup necessary for a static linkset.
|
// The object is going static (non-physical). Do any setup necessary for a static linkset.
|
||||||
|
@ -78,8 +94,16 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// Called at taint-time!
|
// Called at taint-time!
|
||||||
public override bool MakeStatic(BSPrimLinkable child)
|
public override bool MakeStatic(BSPrimLinkable child)
|
||||||
{
|
{
|
||||||
// What is done for each object in BSPrim is what we want.
|
bool ret = false;
|
||||||
return false;
|
|
||||||
|
DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
|
||||||
|
child.ClearDisplacement();
|
||||||
|
if (IsRoot(child))
|
||||||
|
{
|
||||||
|
// Schedule a rebuild to verify that the root shape is set to the real shape.
|
||||||
|
ScheduleRebuild(LinksetRoot);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called at taint-time!!
|
// Called at taint-time!!
|
||||||
|
@ -105,7 +129,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
// Just undo all the constraints for this linkset. Rebuild at the end of the step.
|
// Just undo all the constraints for this linkset. Rebuild at the end of the step.
|
||||||
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
|
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
|
||||||
// Cause the constraints, et al to be rebuilt before the next simulation step.
|
// Cause the constraints, et al to be rebuilt before the next simulation step.
|
||||||
Refresh(LinksetRoot);
|
ScheduleRebuild(LinksetRoot);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +147,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
|
DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
|
||||||
|
|
||||||
// Cause constraints and assorted properties to be recomputed before the next simulation step.
|
// Cause constraints and assorted properties to be recomputed before the next simulation step.
|
||||||
Refresh(LinksetRoot);
|
ScheduleRebuild(LinksetRoot);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +171,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
PhysicallyUnlinkAChildFromRoot(rootx, childx);
|
PhysicallyUnlinkAChildFromRoot(rootx, childx);
|
||||||
});
|
});
|
||||||
// See that the linkset parameters are recomputed at the end of the taint time.
|
// See that the linkset parameters are recomputed at the end of the taint time.
|
||||||
Refresh(LinksetRoot);
|
ScheduleRebuild(LinksetRoot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -165,6 +189,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
Refresh(rootPrim);
|
Refresh(rootPrim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a static constraint between the two passed objects
|
||||||
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
|
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
|
||||||
{
|
{
|
||||||
// Zero motion for children so they don't interpolate
|
// Zero motion for children so they don't interpolate
|
||||||
|
@ -281,24 +306,39 @@ public sealed class BSLinksetConstraints : BSLinkset
|
||||||
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
|
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
|
||||||
LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
|
LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
|
||||||
|
|
||||||
foreach (BSPrimLinkable child in m_children)
|
try
|
||||||
{
|
{
|
||||||
// A child in the linkset physically shows the mass of the whole linkset.
|
Rebuilding = true;
|
||||||
// This allows Bullet to apply enough force on the child to move the whole linkset.
|
|
||||||
// (Also do the mass stuff before recomputing the constraint so mass is not zero.)
|
|
||||||
child.UpdatePhysicalMassProperties(linksetMass, true);
|
|
||||||
|
|
||||||
BSConstraint constrain;
|
// There is no reason to build all this physical stuff for a non-physical linkset.
|
||||||
if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
|
if (!LinksetRoot.IsPhysicallyActive)
|
||||||
{
|
{
|
||||||
// If constraint doesn't exist yet, create it.
|
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
|
||||||
constrain = BuildConstraint(LinksetRoot, child);
|
return; // Note the 'finally' clause at the botton which will get executed.
|
||||||
}
|
}
|
||||||
constrain.RecomputeConstraintVariables(linksetMass);
|
|
||||||
|
|
||||||
// PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
|
foreach (BSPrimLinkable child in m_children)
|
||||||
|
{
|
||||||
|
// A child in the linkset physically shows the mass of the whole linkset.
|
||||||
|
// This allows Bullet to apply enough force on the child to move the whole linkset.
|
||||||
|
// (Also do the mass stuff before recomputing the constraint so mass is not zero.)
|
||||||
|
child.UpdatePhysicalMassProperties(linksetMass, true);
|
||||||
|
|
||||||
|
BSConstraint constrain;
|
||||||
|
if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
|
||||||
|
{
|
||||||
|
// If constraint doesn't exist yet, create it.
|
||||||
|
constrain = BuildConstraint(LinksetRoot, child);
|
||||||
|
}
|
||||||
|
constrain.RecomputeConstraintVariables(linksetMass);
|
||||||
|
|
||||||
|
// PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Rebuilding = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -461,8 +461,9 @@ public static class BSParam
|
||||||
(s) => { return MaxAddForceMagnitude; },
|
(s) => { return MaxAddForceMagnitude; },
|
||||||
(s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
|
(s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
|
||||||
// Density is passed around as 100kg/m3. This scales that to 1kg/m3.
|
// Density is passed around as 100kg/m3. This scales that to 1kg/m3.
|
||||||
|
// Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well
|
||||||
new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
|
new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
|
||||||
0.01f ),
|
0.0001f ),
|
||||||
|
|
||||||
new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
|
new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
|
||||||
2200f ),
|
2200f ),
|
||||||
|
@ -607,8 +608,9 @@ public static class BSParam
|
||||||
0.0f ),
|
0.0f ),
|
||||||
new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
|
new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
|
||||||
0.0f ),
|
0.0f ),
|
||||||
|
// Turn off fudge with DensityScaleFactor = 0.0001. Value used to be 0.2f;
|
||||||
new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
|
new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
|
||||||
0.2f ),
|
1.0f ),
|
||||||
new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
|
new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
|
||||||
60.0f ),
|
60.0f ),
|
||||||
new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",
|
new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",
|
||||||
|
@ -701,7 +703,7 @@ public static class BSParam
|
||||||
new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
|
new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
|
||||||
(float)BSLinkset.LinksetImplementation.Compound ),
|
(float)BSLinkset.LinksetImplementation.Compound ),
|
||||||
new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same",
|
new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same",
|
||||||
false ),
|
true ),
|
||||||
new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
|
new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
|
||||||
false ),
|
false ),
|
||||||
new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
|
new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
|
||||||
|
|
|
@ -353,6 +353,16 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
CollidingStep = BSScene.NotASimulationStep;
|
CollidingStep = BSScene.NotASimulationStep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Complex objects (like linksets) need to know if there is a collision on any part of
|
||||||
|
// their shape. 'IsColliding' has an existing definition of reporting a collision on
|
||||||
|
// only this specific prim or component of linksets.
|
||||||
|
// 'HasSomeCollision' is defined as reporting if there is a collision on any part of
|
||||||
|
// the complex body that this prim is the root of.
|
||||||
|
public virtual bool HasSomeCollision
|
||||||
|
{
|
||||||
|
get { return IsColliding; }
|
||||||
|
set { IsColliding = value; }
|
||||||
|
}
|
||||||
public override bool CollidingGround {
|
public override bool CollidingGround {
|
||||||
get { return (CollidingGroundStep == PhysScene.SimulationStep); }
|
get { return (CollidingGroundStep == PhysScene.SimulationStep); }
|
||||||
set
|
set
|
||||||
|
@ -386,6 +396,7 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
// Return 'true' if a collision was processed and should be sent up.
|
// Return 'true' if a collision was processed and should be sent up.
|
||||||
// Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
|
// Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
|
||||||
// Called at taint time from within the Step() function
|
// Called at taint time from within the Step() function
|
||||||
|
public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
|
||||||
public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
|
public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
|
||||||
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class BSPrim : BSPhysObject
|
||||||
_isVolumeDetect = false;
|
_isVolumeDetect = false;
|
||||||
|
|
||||||
// Add a dynamic vehicle to our set of actors that can move this prim.
|
// Add a dynamic vehicle to our set of actors that can move this prim.
|
||||||
PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName));
|
// PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName));
|
||||||
|
|
||||||
_mass = CalculateMass();
|
_mass = CalculateMass();
|
||||||
|
|
||||||
|
@ -440,8 +440,8 @@ public class BSPrim : BSPhysObject
|
||||||
Gravity = ComputeGravity(Buoyancy);
|
Gravity = ComputeGravity(Buoyancy);
|
||||||
PhysScene.PE.SetGravity(PhysBody, Gravity);
|
PhysScene.PE.SetGravity(PhysBody, Gravity);
|
||||||
|
|
||||||
OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
|
// OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
|
||||||
DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
|
// DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
|
||||||
|
|
||||||
Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
|
Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
|
||||||
PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
|
PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
|
||||||
|
@ -495,9 +495,9 @@ public class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find and return a handle to the current vehicle actor.
|
// Find and return a handle to the current vehicle actor.
|
||||||
// Return 'null' if there is no vehicle actor.
|
// Return 'null' if there is no vehicle actor.
|
||||||
public BSDynamics GetVehicleActor()
|
public BSDynamics GetVehicleActor(bool createIfNone)
|
||||||
{
|
{
|
||||||
BSDynamics ret = null;
|
BSDynamics ret = null;
|
||||||
BSActor actor;
|
BSActor actor;
|
||||||
|
@ -505,12 +505,21 @@ public class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
ret = actor as BSDynamics;
|
ret = actor as BSDynamics;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (createIfNone)
|
||||||
|
{
|
||||||
|
ret = new BSDynamics(PhysScene, this, VehicleActorName);
|
||||||
|
PhysicalActors.Add(ret.ActorName, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int VehicleType {
|
public override int VehicleType {
|
||||||
get {
|
get {
|
||||||
int ret = (int)Vehicle.TYPE_NONE;
|
int ret = (int)Vehicle.TYPE_NONE;
|
||||||
BSDynamics vehicleActor = GetVehicleActor();
|
BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
|
||||||
if (vehicleActor != null)
|
if (vehicleActor != null)
|
||||||
ret = (int)vehicleActor.Type;
|
ret = (int)vehicleActor.Type;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -524,11 +533,24 @@ public class BSPrim : BSPhysObject
|
||||||
// change all the parameters. Like a plane changing to CAR when on the
|
// change all the parameters. Like a plane changing to CAR when on the
|
||||||
// ground. In this case, don't want to zero motion.
|
// ground. In this case, don't want to zero motion.
|
||||||
// ZeroMotion(true /* inTaintTime */);
|
// ZeroMotion(true /* inTaintTime */);
|
||||||
BSDynamics vehicleActor = GetVehicleActor();
|
if (type == Vehicle.TYPE_NONE)
|
||||||
if (vehicleActor != null)
|
|
||||||
{
|
{
|
||||||
vehicleActor.ProcessTypeChange(type);
|
// Vehicle type is 'none' so get rid of any actor that may have been allocated.
|
||||||
ActivateIfPhysical(false);
|
BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
|
||||||
|
if (vehicleActor != null)
|
||||||
|
{
|
||||||
|
PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Vehicle type is not 'none' so create an actor and set it running.
|
||||||
|
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
|
||||||
|
if (vehicleActor != null)
|
||||||
|
{
|
||||||
|
vehicleActor.ProcessTypeChange(type);
|
||||||
|
ActivateIfPhysical(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -537,7 +559,7 @@ public class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
|
PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
|
||||||
{
|
{
|
||||||
BSDynamics vehicleActor = GetVehicleActor();
|
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
|
||||||
if (vehicleActor != null)
|
if (vehicleActor != null)
|
||||||
{
|
{
|
||||||
vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
|
vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
|
||||||
|
@ -549,7 +571,7 @@ public class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
|
PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
|
||||||
{
|
{
|
||||||
BSDynamics vehicleActor = GetVehicleActor();
|
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
|
||||||
if (vehicleActor != null)
|
if (vehicleActor != null)
|
||||||
{
|
{
|
||||||
vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
|
vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
|
||||||
|
@ -561,7 +583,7 @@ public class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
|
PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
|
||||||
{
|
{
|
||||||
BSDynamics vehicleActor = GetVehicleActor();
|
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
|
||||||
if (vehicleActor != null)
|
if (vehicleActor != null)
|
||||||
{
|
{
|
||||||
vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
|
vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
|
||||||
|
@ -573,7 +595,7 @@ public class BSPrim : BSPhysObject
|
||||||
{
|
{
|
||||||
PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate()
|
PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate()
|
||||||
{
|
{
|
||||||
BSDynamics vehicleActor = GetVehicleActor();
|
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
|
||||||
if (vehicleActor != null)
|
if (vehicleActor != null)
|
||||||
{
|
{
|
||||||
vehicleActor.ProcessVehicleFlags(param, remove);
|
vehicleActor.ProcessVehicleFlags(param, remove);
|
||||||
|
|
|
@ -200,20 +200,38 @@ public class BSPrimLinkable : BSPrimDisplaced
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after a simulation step to post a collision with this object.
|
// Called after a simulation step to post a collision with this object.
|
||||||
|
// This returns 'true' if the collision has been queued and the SendCollisions call must
|
||||||
|
// be made at the end of the simulation step.
|
||||||
public override bool Collide(uint collidingWith, BSPhysObject collidee,
|
public override bool Collide(uint collidingWith, BSPhysObject collidee,
|
||||||
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
|
||||||
{
|
{
|
||||||
// prims in the same linkset cannot collide with each other
|
bool ret = false;
|
||||||
BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
|
// Ask the linkset if it wants to handle the collision
|
||||||
if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID))
|
if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth))
|
||||||
{
|
{
|
||||||
return false;
|
// The linkset didn't handle it so pass the collision through normal processing
|
||||||
|
ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: handle collisions of other objects with with children of linkset.
|
// A linkset reports any collision on any part of the linkset.
|
||||||
// This is a problem for LinksetCompound since the children are packed into the root.
|
public long SomeCollisionSimulationStep = 0;
|
||||||
|
public override bool HasSomeCollision
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
SomeCollisionSimulationStep = PhysScene.SimulationStep;
|
||||||
|
else
|
||||||
|
SomeCollisionSimulationStep = 0;
|
||||||
|
|
||||||
return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
|
base.HasSomeCollision = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ public class BasicVehicles : OpenSimTestCase
|
||||||
// Instead the appropriate values are set and calls are made just the parts of the
|
// Instead the appropriate values are set and calls are made just the parts of the
|
||||||
// controller we want to exercise. Stepping the physics engine then applies
|
// controller we want to exercise. Stepping the physics engine then applies
|
||||||
// the actions of that one feature.
|
// the actions of that one feature.
|
||||||
BSDynamics vehicleActor = TestVehicle.GetVehicleActor();
|
BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */);
|
||||||
if (vehicleActor != null)
|
if (vehicleActor != null)
|
||||||
{
|
{
|
||||||
vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
|
vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
|
||||||
|
|
|
@ -415,6 +415,11 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
public virtual PhysicsActor ParentActor { get { return this; } }
|
public virtual PhysicsActor ParentActor { get { return this; } }
|
||||||
|
|
||||||
|
|
||||||
|
// Extendable interface for new, physics engine specific operations
|
||||||
|
public virtual object Extension(string pFunct, params object[] pParams)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NullPhysicsActor : PhysicsActor
|
public class NullPhysicsActor : PhysicsActor
|
||||||
|
|
|
@ -25,10 +25,13 @@
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
using log4net;
|
using log4net;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
|
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
|
||||||
|
@ -386,5 +389,11 @@ namespace OpenSim.Region.Physics.Manager
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extendable interface for new, physics engine specific operations
|
||||||
|
public virtual object Extension(string pFunct, params object[] pParams)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -493,6 +493,22 @@ namespace OpenSim.Services.HypergridService
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private XInventoryFolder GetCurrentOutfitXFolder(UUID userID)
|
||||||
|
{
|
||||||
|
XInventoryFolder root = GetRootXFolder(userID);
|
||||||
|
if (root == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
XInventoryFolder[] folders = m_Database.GetFolders(
|
||||||
|
new string[] { "agentID", "type", "parentFolderID" },
|
||||||
|
new string[] { userID.ToString(), ((int)AssetType.CurrentOutfitFolder).ToString(), root.folderID.ToString() });
|
||||||
|
|
||||||
|
if (folders.Length == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return folders[0];
|
||||||
|
}
|
||||||
|
|
||||||
private XInventoryFolder GetSuitcaseXFolder(UUID principalID)
|
private XInventoryFolder GetSuitcaseXFolder(UUID principalID)
|
||||||
{
|
{
|
||||||
// Warp! Root folder for travelers
|
// Warp! Root folder for travelers
|
||||||
|
@ -531,6 +547,7 @@ namespace OpenSim.Services.HypergridService
|
||||||
if (m_SuitcaseTrees.TryGetValue(principalID, out t))
|
if (m_SuitcaseTrees.TryGetValue(principalID, out t))
|
||||||
return t;
|
return t;
|
||||||
|
|
||||||
|
// Get the tree of the suitcase folder
|
||||||
t = GetFolderTreeRecursive(folder);
|
t = GetFolderTreeRecursive(folder);
|
||||||
m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5minutes
|
m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5minutes
|
||||||
return t;
|
return t;
|
||||||
|
@ -577,6 +594,9 @@ namespace OpenSim.Services.HypergridService
|
||||||
List<XInventoryFolder> tree = new List<XInventoryFolder>();
|
List<XInventoryFolder> tree = new List<XInventoryFolder>();
|
||||||
tree.Add(suitcase); // Warp! the tree is the real root folder plus the children of the suitcase folder
|
tree.Add(suitcase); // Warp! the tree is the real root folder plus the children of the suitcase folder
|
||||||
tree.AddRange(GetFolderTree(principalID, suitcase.folderID));
|
tree.AddRange(GetFolderTree(principalID, suitcase.folderID));
|
||||||
|
// Also add the Current Outfit folder to the list of available folders
|
||||||
|
tree.Add(GetCurrentOutfitXFolder(principalID));
|
||||||
|
|
||||||
XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl)
|
XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl)
|
||||||
{
|
{
|
||||||
if (fl.folderID == folderID) return true;
|
if (fl.folderID == folderID) return true;
|
||||||
|
|
|
@ -107,6 +107,7 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
||||||
public event UpdateAgent OnPreAgentUpdate;
|
public event UpdateAgent OnPreAgentUpdate;
|
||||||
public event UpdateAgent OnAgentUpdate;
|
public event UpdateAgent OnAgentUpdate;
|
||||||
|
public event UpdateAgent OnAgentCameraUpdate;
|
||||||
public event AgentRequestSit OnAgentRequestSit;
|
public event AgentRequestSit OnAgentRequestSit;
|
||||||
public event AgentSit OnAgentSit;
|
public event AgentSit OnAgentSit;
|
||||||
public event AvatarPickerRequest OnAvatarPickerRequest;
|
public event AvatarPickerRequest OnAvatarPickerRequest;
|
||||||
|
@ -1266,7 +1267,7 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopFlying(ISceneEntity presence)
|
public void SendAgentTerseUpdate(ISceneEntity presence)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue