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.cs
avinationmerge
Melanie 2013-07-24 04:45:07 +01:00
commit e82d4154a2
31 changed files with 915 additions and 252 deletions

View File

@ -1402,19 +1402,18 @@ namespace OpenSim.Groups
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
UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, dataForAgentID);
string firstname, lastname;
if (account != null)
string firstname = "Unknown", lastname = "Unknown";
string name = m_UserManagement.GetUserName(dataForAgentID);
if (!string.IsNullOrEmpty(name))
{
firstname = account.FirstName;
lastname = account.LastName;
string[] parts = name.Split(new char[] { ' ' });
if (parts.Length >= 2)
{
firstname = parts[0];
lastname = parts[1];
}
}
else
{
firstname = "Unknown";
lastname = "Unknown";
}
remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname,
lastname, activeGroupPowers, activeGroupName,
activeGroupTitle);

View File

@ -834,6 +834,8 @@ namespace OpenSim.Framework
/// </remarks>
event UpdateAgent OnAgentUpdate;
event UpdateAgent OnAgentCameraUpdate;
event AgentRequestSit OnAgentRequestSit;
event AgentSit OnAgentSit;
event AvatarPickerRequest OnAvatarPickerRequest;
@ -1489,7 +1491,7 @@ namespace OpenSim.Framework
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 StopFlying(ISceneEntity presence);
void SendAgentTerseUpdate(ISceneEntity presence);
void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data);
}

View File

@ -225,7 +225,13 @@ namespace OpenSim.Framework.Monitoring
public virtual string ToConsoleString()
{
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);
@ -253,6 +259,8 @@ namespace OpenSim.Framework.Monitoring
== MeasuresOfInterest.AverageChangeOverTime)
{
double totalChange = 0;
double lastChangeOverTime = 0;
double? penultimateSample = null;
double? lastSample = null;
lock (m_samples)
@ -266,13 +274,25 @@ namespace OpenSim.Framework.Monitoring
if (lastSample != null)
totalChange += s - (double)lastSample;
penultimateSample = lastSample;
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;
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));
}
}
}

View File

@ -96,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
public event UpdateAgent OnPreAgentUpdate;
public event UpdateAgent OnAgentUpdate;
public event UpdateAgent OnAgentCameraUpdate;
public event AgentRequestSit OnAgentRequestSit;
public event AgentSit OnAgentSit;
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
/// cannot retain a reference to it outside of that method.
/// </remarks>
private AgentUpdateArgs m_lastAgentUpdateArgs;
private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
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
@ -505,6 +506,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_udpServer = udpServer;
m_udpClient = udpClient;
m_udpClient.OnQueueEmpty += HandleQueueEmpty;
m_udpClient.HasUpdates += HandleHasUpdates;
m_udpClient.OnPacketStats += PopulateStats;
m_prioritizer = new Prioritizer(m_scene);
@ -4164,8 +4166,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
{
// if (!m_udpServer.IsRunningOutbound)
// return;
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
{
// if (!m_udpServer.IsRunningOutbound)
// return;
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
{
m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@ -4191,6 +4199,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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)
{
AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@ -5058,7 +5087,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
SceneObjectPart part = (SceneObjectPart)entity;
attachPoint = part.ParentGroup.AttachmentPoint;
attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
// m_log.DebugFormat(
// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
// attachPoint, part.Name, part.LocalId, Name);
@ -5086,7 +5115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
pos += 4;
// Avatar/CollisionPlane
data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ;
data[pos++] = (byte) attachPoint;
if (avatar)
{
data[pos++] = 1;
@ -5618,83 +5647,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Packet Handlers
public int TotalAgentUpdates { get; set; }
#region Scene/Avatar
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
// 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)
{
if (OnAgentUpdate != null)
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)
{
// 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 (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
{
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;
}
if (handlerAgentUpdate != null)
OnAgentUpdate(this, m_thisAgentUpdateArgs);
}
// 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);
@ -12813,7 +12896,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(dialog, ThrottleOutPacketType.Task);
}
public void StopFlying(ISceneEntity p)
public void SendAgentTerseUpdate(ISceneEntity p)
{
if (p is ScenePresence)
{
@ -12827,25 +12910,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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 =
CreateImprovedTerseBlock(p, false);

View File

@ -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)
{
int packetsSent = 0;

View File

@ -31,6 +31,7 @@ using System.Net;
using System.Threading;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
using OpenMetaverse;
using OpenMetaverse.Packets;
@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// hooked to put more data on the empty queue</summary>
public event QueueEmpty OnQueueEmpty;
public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
/// <summary>AgentID for this client</summary>
public readonly UUID AgentID;
/// <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>
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
m_nextOnQueueEmpty = 0;
// Asynchronously run the callback
Util.FireAndForget(FireQueueEmpty, categories);
// m_nextOnQueueEmpty = 0;
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>
/// Fires the OnQueueEmpty callback and sets the minimum time that it
/// can be called again
@ -663,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// signature</param>
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;
QueueEmpty callback = OnQueueEmpty;
int start = Environment.TickCount & Int32.MaxValue;
// if (m_udpServer.IsRunningOutbound)
// {
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
QueueEmpty callback = OnQueueEmpty;
if (callback != null)
{
try { callback(categories); }
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
}
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); }
// }
}
// }
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
if (m_nextOnQueueEmpty == 0)
m_nextOnQueueEmpty = 1;
// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
// if (m_nextOnQueueEmpty == 0)
// m_nextOnQueueEmpty = 1;
// }
m_isQueueEmptyRunning = false;
}
internal void ForceThrottleSetting(int throttle, int setting)
{

View File

@ -67,11 +67,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
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(
new Stat(
"IncomingPacketsProcessedCount",
"Number of inbound UDP packets processed",
"Number of inbound UDP packets processed",
"Number of inbound LL protocol packets processed",
"Number of inbound LL protocol packets processed",
"",
"clientstack",
scene.Name,
@ -79,6 +92,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
MeasuresOfInterest.AverageChangeOverTime,
stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
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)
@ -185,6 +226,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected bool m_sendPing;
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;
/// <summary>
@ -462,6 +513,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_scene = (Scene)scene;
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
// turned on and off by EnablePools()/DisablePools()
StatsManager.RegisterStat(
@ -575,6 +639,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
"debug lludp status",
"Return status of LLUDP packet processing.",
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)
@ -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)
{
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
@ -809,12 +894,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
PacketPool.Instance.ReturnPacket(packet);
m_dataPresentEvent.Set();
}
private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
/// <summary>
/// Start the process of sending a packet to the client.
/// </summary>
@ -1325,6 +1408,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
#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
if (packet.Type == PacketType.StartPingCheck)
@ -1734,7 +1836,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Action generic every round
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
// while (true)
while (base.IsRunningOutbound)
{
m_scene.ThreadAlive(2);
@ -1798,6 +1899,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// token bucket could get more tokens
//if (!m_packetSent)
// 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);
Watchdog.UpdateThread();

View File

@ -77,6 +77,36 @@ namespace OpenMetaverse
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
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>
/// Default constructor
/// </summary>
@ -111,6 +141,8 @@ namespace OpenMetaverse
if (!IsRunningInbound)
{
m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
const int SIO_UDP_CONNRESET = -1744830452;
IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@ -151,6 +183,8 @@ namespace OpenMetaverse
/// </summary>
public void StartOutbound()
{
m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
IsRunningOutbound = true;
}
@ -158,10 +192,8 @@ namespace OpenMetaverse
{
if (IsRunningInbound)
{
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
// 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.
m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
IsRunningInbound = false;
m_udpSocket.Close();
}
@ -169,6 +201,8 @@ namespace OpenMetaverse
public void StopOutbound()
{
m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
IsRunningOutbound = false;
}
@ -267,6 +301,8 @@ namespace OpenMetaverse
// to AsyncBeginReceive
if (IsRunningInbound)
{
UdpReceives++;
// Asynchronous mode will start another receive before the
// callback for this packet is even fired. Very parallel :-)
if (m_asyncPacketHandling)
@ -278,6 +314,8 @@ namespace OpenMetaverse
try
{
int startTick = Util.EnvironmentTickCount();
// get the length of data actually read from the socket, store it with the
// buffer
buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@ -285,6 +323,23 @@ namespace OpenMetaverse
// call the abstract method PacketReceived(), passing the buffer that
// has just been filled from the socket read.
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 (ObjectDisposedException) { }
@ -298,14 +353,13 @@ namespace OpenMetaverse
if (!m_asyncPacketHandling)
AsyncBeginReceive();
}
}
}
public void AsyncBeginSend(UDPPacketBuffer buf)
{
if (IsRunningOutbound)
{
// if (IsRunningOutbound)
// {
try
{
m_udpSocket.BeginSendTo(
@ -319,7 +373,7 @@ namespace OpenMetaverse
}
catch (SocketException) { }
catch (ObjectDisposedException) { }
}
// }
}
void AsyncEndSend(IAsyncResult result)
@ -328,6 +382,8 @@ namespace OpenMetaverse
{
// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
m_udpSocket.EndSendTo(result);
UdpSends++;
}
catch (SocketException) { }
catch (ObjectDisposedException) { }

View File

@ -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;
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);
UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0);
UploadInventoryItem(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0);
return newAssetID;
}
@ -232,7 +235,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
protected override void ExportAsset(UUID agentID, UUID assetID)
{
if (!assetID.Equals(UUID.Zero))
UploadInventoryItem(agentID, assetID, "", 0);
UploadInventoryItem(agentID, AssetType.Unknown, assetID, "", 0);
else
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);
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)
{
if (f.Name != "My Suitcase")
if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
{
f.Name = f.Name + " (Unavailable)";
keep.Add(f);

View File

@ -389,7 +389,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
}
names[0] = "Unknown";
names[1] = "UserUMMTGUN7";
names[1] = "UserUMMTGUN8";
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
// disappeared.
user.FirstName = "Unknown";
user.LastName = "UserUMMAU3";
user.LastName = "UserUMMAU4";
}
AddUserInternal(user);

View File

@ -743,7 +743,7 @@ namespace OpenSim.Region.Framework.Scenes
public event OnIncomingSceneObjectDelegate OnIncomingSceneObject;
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;
@ -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;
if (handlerNewInventoryItemUpdateComplete != null)
@ -2181,7 +2181,7 @@ namespace OpenSim.Region.Framework.Scenes
{
try
{
d(agentID, AssetID, AssetName, userlevel);
d(agentID, type, AssetID, AssetName, userlevel);
}
catch (Exception e)
{

View File

@ -139,7 +139,7 @@ namespace OpenSim.Region.Framework.Scenes
{
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;
}
@ -178,7 +178,7 @@ namespace OpenSim.Region.Framework.Scenes
{
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)
{

View File

@ -416,6 +416,7 @@ namespace OpenSim.Region.Framework.Scenes
void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args)
{
// TODO: don't create new blocks if recycling an old packet
bool discardableEffects = true;
ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count];
for (int i = 0; i < args.Count; i++)
{
@ -427,17 +428,34 @@ namespace OpenSim.Region.Framework.Scenes
effect.Type = args[i].Type;
effect.TypeData = args[i].TypeData;
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(
delegate(IClientAPI client)
ForEachScenePresence(sp =>
{
if (client.AgentId != remoteClient.AgentId)
client.SendViewerEffect(effectBlockArray);
}
);
if (sp.ControllingClient.AgentId != remoteClient.AgentId)
{
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
{
public IClientAPI RemoteClient;

View File

@ -142,6 +142,8 @@ namespace OpenSim.Region.Framework.Scenes
private Vector3 m_lastVelocity;
private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f);
private bool m_followCamAuto = false;
private Vector3? m_forceToApply;
private int m_userFlags;
@ -874,6 +876,7 @@ namespace OpenSim.Region.Framework.Scenes
{
ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
ControllingClient.OnAgentUpdate += HandleAgentUpdate;
ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate;
ControllingClient.OnAgentRequestSit += HandleAgentRequestSit;
ControllingClient.OnAgentSit += HandleAgentSit;
ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun;
@ -1306,7 +1309,26 @@ namespace OpenSim.Region.Framework.Scenes
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>
@ -1662,9 +1684,9 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary>
public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
{
// m_log.DebugFormat(
// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
//m_log.DebugFormat(
// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
if (IsChildAgent)
{
@ -1672,10 +1694,6 @@ namespace OpenSim.Region.Framework.Scenes
return;
}
++m_movementUpdateCount;
if (m_movementUpdateCount < 1)
m_movementUpdateCount = 1;
#region Sanity Checking
// This is irritating. Really.
@ -1706,21 +1724,6 @@ namespace OpenSim.Region.Framework.Scenes
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
@ -2005,10 +2008,79 @@ namespace OpenSim.Region.Framework.Scenes
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);
TriggerScenePresenceUpdated();
}
/// <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();
}
/// <summary>
/// Calculate an update to move the presence to the set target.
/// </summary>

View File

@ -688,6 +688,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
public event UpdateAgent OnPreAgentUpdate;
public event UpdateAgent OnAgentUpdate;
public event UpdateAgent OnAgentCameraUpdate;
public event AgentRequestSit OnAgentRequestSit;
public event AgentSit OnAgentSit;
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)
{
}

View File

@ -611,7 +611,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
//
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)
{
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();
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,
(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));
}
});
}

View File

@ -259,6 +259,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
public event UpdateAgent OnPreAgentUpdate;
public event UpdateAgent OnAgentUpdate;
public event UpdateAgent OnAgentCameraUpdate;
public event AgentRequestSit OnAgentRequestSit;
public event AgentSit OnAgentSit;
public event AvatarPickerRequest OnAvatarPickerRequest;
@ -1242,7 +1243,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
{
}
public void StopFlying(ISceneEntity presence)
public void SendAgentTerseUpdate(ISceneEntity presence)
{
}

View File

@ -69,7 +69,7 @@ public class BSActorCollection
{
lock (m_actors)
{
Release();
ForEachActor(a => a.Dispose());
m_actors.Clear();
}
}
@ -98,10 +98,6 @@ public class BSActorCollection
{
ForEachActor(a => a.SetEnabled(enabl));
}
public void Release()
{
ForEachActor(a => a.Dispose());
}
public void Refresh()
{
ForEachActor(a => a.Refresh());

View File

@ -45,7 +45,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
private static string LogHeader = "[BULLETSIM VEHICLE]";
// the prim this dynamic controller belongs to
private BSPrim ControllingPrim { get; set; }
private BSPrimLinkable ControllingPrim { get; set; }
private bool m_haveRegisteredForSceneEvents;
@ -128,9 +128,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
: base(myScene, myPrim, actorName)
{
ControllingPrim = myPrim;
Type = Vehicle.TYPE_NONE;
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
@ -585,6 +591,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Friction affects are handled by this vehicle code
m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
// ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
// ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
// Moderate angular movement introduced by Bullet.
// 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
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);
ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
// ControllingPrim.Linkset.ComputeLocalInertia(BSParam.VehicleInertiaFactor);
// Set the gravity for the vehicle depending on the buoyancy
// TODO: what should be done if prim and vehicle buoyancy differ?
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.
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}",
ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
@ -617,6 +628,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
if (ControllingPrim.PhysBody.HasPhysicalBody)
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()
public override void Dispose()
{
VDetailLog("{0},Dispose", ControllingPrim.LocalID);
UnregisterForSceneEvents();
Type = Vehicle.TYPE_NONE;
Enabled = false;
@ -1001,7 +1014,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
else if (newVelocityLengthSq < 0.001f)
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()
@ -1029,8 +1042,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Add this correction to the velocity to make it faster/slower.
VehicleVelocity += linearMotorVelocityW;
VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}",
ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV,
VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
linearMotorVelocityW, VehicleVelocity, frictionFactorV);
}
@ -1062,7 +1075,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation;
// 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;
}
@ -1222,7 +1235,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
distanceAboveGround = VehiclePosition.Z - targetHeight;
// Not colliding if the vehicle is off the ground
if (!Prim.IsColliding)
if (!Prim.HasSomeCollision)
{
// downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
@ -1233,12 +1246,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// be computed with a motor.
// TODO: add interaction with banking.
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,
// 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.
float upVelocity = VehicleVelocity.Z;
@ -1260,7 +1273,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
}
*/
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;
// 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;
VehicleAddForce(appliedGravity);
VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
ControllingPrim.LocalID, m_VehicleGravity,
ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
}
// =======================================================================

View File

@ -203,6 +203,33 @@ public abstract class BSLinkset
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
// Called while LinkActivity is locked.
protected abstract void AddChildToLinkset(BSPrimLinkable child);
@ -250,6 +277,73 @@ public abstract class BSLinkset
// Called at taint-time!!
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()
{
@ -311,6 +405,5 @@ public abstract class BSLinkset
if (m_physicsScene.PhysicsLogging.Enabled)
m_physicsScene.DetailLog(msg, args);
}
}
}

View File

@ -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
// its internal properties.
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}",
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.

View File

@ -48,12 +48,22 @@ public sealed class BSLinksetConstraints : BSLinkset
{
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
m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
{
if (HasAnyChildren && IsRoot(requestor))
if (HasAnyChildren)
RecomputeLinksetConstraints();
});
}
@ -67,8 +77,14 @@ public sealed class BSLinksetConstraints : BSLinkset
// Called at taint-time!
public override bool MakeDynamic(BSPrimLinkable child)
{
// What is done for each object in BSPrim is what we want.
return false;
bool ret = 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.
@ -78,8 +94,16 @@ public sealed class BSLinksetConstraints : BSLinkset
// Called at taint-time!
public override bool MakeStatic(BSPrimLinkable child)
{
// What is done for each object in BSPrim is what we want.
return false;
bool ret = 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!!
@ -105,7 +129,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// Just undo all the constraints for this linkset. Rebuild at the end of the step.
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
// Cause the constraints, et al to be rebuilt before the next simulation step.
Refresh(LinksetRoot);
ScheduleRebuild(LinksetRoot);
}
return ret;
}
@ -123,7 +147,7 @@ public sealed class BSLinksetConstraints : BSLinkset
DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
// Cause constraints and assorted properties to be recomputed before the next simulation step.
Refresh(LinksetRoot);
ScheduleRebuild(LinksetRoot);
}
return;
}
@ -147,7 +171,7 @@ public sealed class BSLinksetConstraints : BSLinkset
PhysicallyUnlinkAChildFromRoot(rootx, childx);
});
// See that the linkset parameters are recomputed at the end of the taint time.
Refresh(LinksetRoot);
ScheduleRebuild(LinksetRoot);
}
else
{
@ -165,6 +189,7 @@ public sealed class BSLinksetConstraints : BSLinkset
Refresh(rootPrim);
}
// Create a static constraint between the two passed objects
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
{
// 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}",
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.
// 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);
Rebuilding = true;
BSConstraint constrain;
if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
// There is no reason to build all this physical stuff for a non-physical linkset.
if (!LinksetRoot.IsPhysicallyActive)
{
// If constraint doesn't exist yet, create it.
constrain = BuildConstraint(LinksetRoot, child);
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
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;
}
}
}
}

View File

@ -461,8 +461,9 @@ public static class BSParam
(s) => { return MaxAddForceMagnitude; },
(s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
// 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)",
0.01f ),
0.0001f ),
new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
2200f ),
@ -607,8 +608,9 @@ public static class BSParam
0.0f ),
new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
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)",
0.2f ),
1.0f ),
new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
60.0f ),
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)",
(float)BSLinkset.LinksetImplementation.Compound ),
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.",
false ),
new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",

View File

@ -353,6 +353,16 @@ public abstract class BSPhysObject : PhysicsActor
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 {
get { return (CollidingGroundStep == PhysScene.SimulationStep); }
set
@ -386,6 +396,7 @@ public abstract class BSPhysObject : PhysicsActor
// 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.
// 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,
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
{

View File

@ -96,7 +96,7 @@ public class BSPrim : BSPhysObject
_isVolumeDetect = false;
// 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();
@ -440,8 +440,8 @@ public class BSPrim : BSPhysObject
Gravity = ComputeGravity(Buoyancy);
PhysScene.PE.SetGravity(PhysBody, Gravity);
OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, 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
Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
@ -495,9 +495,9 @@ public class BSPrim : BSPhysObject
}
}
// Find and return a handle to the current vehicle actor.
// Return 'null' if there is no vehicle actor.
public BSDynamics GetVehicleActor()
// Find and return a handle to the current vehicle actor.
// Return 'null' if there is no vehicle actor.
public BSDynamics GetVehicleActor(bool createIfNone)
{
BSDynamics ret = null;
BSActor actor;
@ -505,12 +505,21 @@ public class BSPrim : BSPhysObject
{
ret = actor as BSDynamics;
}
else
{
if (createIfNone)
{
ret = new BSDynamics(PhysScene, this, VehicleActorName);
PhysicalActors.Add(ret.ActorName, ret);
}
}
return ret;
}
public override int VehicleType {
get {
int ret = (int)Vehicle.TYPE_NONE;
BSDynamics vehicleActor = GetVehicleActor();
BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
if (vehicleActor != null)
ret = (int)vehicleActor.Type;
return ret;
@ -524,11 +533,24 @@ public class BSPrim : BSPhysObject
// change all the parameters. Like a plane changing to CAR when on the
// ground. In this case, don't want to zero motion.
// ZeroMotion(true /* inTaintTime */);
BSDynamics vehicleActor = GetVehicleActor();
if (vehicleActor != null)
if (type == Vehicle.TYPE_NONE)
{
vehicleActor.ProcessTypeChange(type);
ActivateIfPhysical(false);
// Vehicle type is 'none' so get rid of any actor that may have been allocated.
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()
{
BSDynamics vehicleActor = GetVehicleActor();
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null)
{
vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
@ -549,7 +571,7 @@ public class BSPrim : BSPhysObject
{
PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
{
BSDynamics vehicleActor = GetVehicleActor();
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null)
{
vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
@ -561,7 +583,7 @@ public class BSPrim : BSPhysObject
{
PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
{
BSDynamics vehicleActor = GetVehicleActor();
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null)
{
vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
@ -573,7 +595,7 @@ public class BSPrim : BSPhysObject
{
PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate()
{
BSDynamics vehicleActor = GetVehicleActor();
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null)
{
vehicleActor.ProcessVehicleFlags(param, remove);

View File

@ -200,20 +200,38 @@ public class BSPrimLinkable : BSPrimDisplaced
}
// 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,
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
{
// prims in the same linkset cannot collide with each other
BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID))
bool ret = false;
// Ask the linkset if it wants to handle the collision
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.
// This is a problem for LinksetCompound since the children are packed into the root.
// A linkset reports any collision on any part of the linkset.
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;
}
}
}
}

View File

@ -116,7 +116,7 @@ public class BasicVehicles : OpenSimTestCase
// 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
// the actions of that one feature.
BSDynamics vehicleActor = TestVehicle.GetVehicleActor();
BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null)
{
vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);

View File

@ -415,6 +415,11 @@ namespace OpenSim.Region.Physics.Manager
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

View File

@ -25,10 +25,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using log4net;
using Nini.Config;
using OpenSim.Framework;
using OpenMetaverse;
@ -386,5 +389,11 @@ namespace OpenSim.Region.Physics.Manager
{
return 0;
}
// Extendable interface for new, physics engine specific operations
public virtual object Extension(string pFunct, params object[] pParams)
{
throw new NotImplementedException();
}
}
}

View File

@ -493,6 +493,22 @@ namespace OpenSim.Services.HypergridService
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)
{
// Warp! Root folder for travelers
@ -531,6 +547,7 @@ namespace OpenSim.Services.HypergridService
if (m_SuitcaseTrees.TryGetValue(principalID, out t))
return t;
// Get the tree of the suitcase folder
t = GetFolderTreeRecursive(folder);
m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5minutes
return t;
@ -577,6 +594,9 @@ namespace OpenSim.Services.HypergridService
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.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)
{
if (fl.folderID == folderID) return true;

View File

@ -107,6 +107,7 @@ namespace OpenSim.Tests.Common.Mock
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
public event UpdateAgent OnPreAgentUpdate;
public event UpdateAgent OnAgentUpdate;
public event UpdateAgent OnAgentCameraUpdate;
public event AgentRequestSit OnAgentRequestSit;
public event AgentSit OnAgentSit;
public event AvatarPickerRequest OnAvatarPickerRequest;
@ -1266,7 +1267,7 @@ namespace OpenSim.Tests.Common.Mock
{
}
public void StopFlying(ISceneEntity presence)
public void SendAgentTerseUpdate(ISceneEntity presence)
{
}