Compare commits
80 Commits
master
...
cpu-perfor
Author | SHA1 | Date |
---|---|---|
Diva Canto | 47ce1a47bb | |
Diva Canto | 10def95c27 | |
Diva Canto | dab01a10d9 | |
Diva Canto | b44d96618c | |
Diva Canto | 3a6c690e69 | |
Diva Canto | 051cf81c9f | |
Diva Canto | c7a3714c37 | |
Diva Canto | 1815c2f98c | |
Diva Canto | 7c884d16f4 | |
Diva Canto | f3d31e6e53 | |
Diva Canto | 701e15760c | |
Diva Canto | 2b696bc0c8 | |
Justin Clark-Casey (justincc) | 9e277b54b9 | |
Justin Clark-Casey (justincc) | 805ac6435e | |
Justin Clark-Casey (justincc) | 511801c607 | |
Diva Canto | ff294dce6c | |
Diva Canto | 9c1ec98415 | |
Diva Canto | 01561166aa | |
Diva Canto | 8d1108e542 | |
Diva Canto | be4034fd1c | |
Diva Canto | 87a19d4cab | |
Justin Clark-Casey (justincc) | 35e46c2836 | |
Justin Clark-Casey (justincc) | 0d90834f86 | |
Justin Clark-Casey (justincc) | 0755fc2f65 | |
Justin Clark-Casey (justincc) | 94072fb633 | |
Robert Adams | 882efc1a2e | |
Justin Clark-Casey (justincc) | deace1f344 | |
Justin Clark-Casey (justincc) | 7f0f3cc011 | |
Diva Canto | c163276032 | |
Diva Canto | a2a05d470e | |
Diva Canto | d5f8b7924c | |
Diva Canto | d70a0c09cb | |
Diva Canto | df09fdf65d | |
Diva Canto | 37337a4de9 | |
Diva Canto | 8d98d287bd | |
Diva Canto | e1404adac6 | |
Diva Canto | 1d27c9f4d1 | |
Diva Canto | 428b51ffda | |
Diva Canto | fe2487f8d3 | |
Diva Canto | b69ddbb66b | |
Diva Canto | 1cb5e31716 | |
Diva Canto | 7f60800ca6 | |
Diva Canto | ceaa7e9a54 | |
Diva Canto | cab3e9978b | |
Diva Canto | 049022717c | |
Diva Canto | 40c54a718f | |
Diva Canto | 315097b8b9 | |
Diva Canto | 5e5aa5fba7 | |
Diva Canto | 9801d0d4c8 | |
Diva Canto | d95a470442 | |
Diva Canto | 74a341fd22 | |
Diva Canto | 95b248e9e5 | |
Diva Canto | 340abd1110 | |
Diva Canto | 0910c5c101 | |
Diva Canto | f0126a1575 | |
Diva Canto | 0d5b2dd5ce | |
Diva Canto | 64cda1b26e | |
Diva Canto | 778babaab2 | |
Diva Canto | d30e5f7ded | |
Robert Adams | f05654d8d6 | |
Diva Canto | 52bb732692 | |
Diva Canto | dc88ffc5b4 | |
Justin Clark-Casey (justincc) | 07420a3b4d | |
Justin Clark-Casey (justincc) | 42e5856464 | |
Justin Clark-Casey (justincc) | 3b8e7ff013 | |
Justin Clark-Casey (justincc) | 5c74f3ec9c | |
Diva Canto | d1e9beead8 | |
Justin Clark-Casey (justincc) | 35aa6c86fe | |
Justin Clark-Casey (justincc) | 5cdc21aac7 | |
Justin Clark-Casey (justincc) | cbb47f8489 | |
Justin Clark-Casey (justincc) | b2b29b7ec0 | |
Diva Canto | 27377194cd | |
Justin Clark-Casey (justincc) | 8c6761c152 | |
Diva Canto | 553d9cc5d2 | |
Diva Canto | c685cc1799 | |
Justin Clark-Casey (justincc) | 1ba5a05cf7 | |
Justin Clark-Casey (justincc) | 0af3b5ed9a | |
Justin Clark-Casey (justincc) | a94a43d249 | |
Justin Clark-Casey (justincc) | 7c544c0d4e | |
Justin Clark-Casey (justincc) | b402220dbb |
|
@ -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,
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace OpenSim.Groups
|
||||||
private ForeignImporter m_ForeignImporter;
|
private ForeignImporter m_ForeignImporter;
|
||||||
|
|
||||||
private Dictionary<string, bool> m_ActiveRequests = new Dictionary<string, bool>();
|
private Dictionary<string, bool> m_ActiveRequests = new Dictionary<string, bool>();
|
||||||
private const int GROUPS_CACHE_TIMEOUT = 5 * 60; // 5 minutes
|
private const int GROUPS_CACHE_TIMEOUT = 1 * 60; // 1 minutes
|
||||||
|
|
||||||
// This all important cache cahces objects of different types:
|
// This all important cache cahces objects of different types:
|
||||||
// group-<GroupID> or group-<Name> => ExtendedGroupRecord
|
// group-<GroupID> or group-<Name> => ExtendedGroupRecord
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
:VERSION 1 # --------------------------
|
:VERSION 2 # --------------------------
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
||||||
CREATE TABLE hg_traveling_data (
|
CREATE TABLE hg_traveling_data(
|
||||||
SessionID VARCHAR(36) NOT NULL,
|
SessionID VARCHAR(36) NOT NULL,
|
||||||
UserID VARCHAR(36) NOT NULL,
|
UserID VARCHAR(36) NOT NULL,
|
||||||
GridExternalName VARCHAR(255) NOT NULL DEFAULT '',
|
GridExternalName VARCHAR(255) NOT NULL DEFAULT "",
|
||||||
ServiceToken VARCHAR(255) NOT NULL DEFAULT '',
|
ServiceToken VARCHAR(255) NOT NULL DEFAULT "",
|
||||||
ClientIPAddress VARCHAR(16) NOT NULL DEFAULT '',
|
ClientIPAddress VARCHAR(16) NOT NULL DEFAULT "",
|
||||||
MyIPAddress VARCHAR(16) NOT NULL DEFAULT '',
|
MyIPAddress VARCHAR(16) NOT NULL DEFAULT "",
|
||||||
TMStamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
TMStamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`SessionID`),
|
PRIMARY KEY(SessionID),
|
||||||
KEY (`UserID`)
|
UNIQUE(UserID)
|
||||||
) ENGINE=InnoDB;
|
);
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
|
|
|
@ -287,7 +287,7 @@ namespace OpenSim.Framework
|
||||||
public Vector3 AtAxis;
|
public Vector3 AtAxis;
|
||||||
public Vector3 LeftAxis;
|
public Vector3 LeftAxis;
|
||||||
public Vector3 UpAxis;
|
public Vector3 UpAxis;
|
||||||
public bool ChangedGrid;
|
public bool SenderWantsToWaitForRoot;
|
||||||
|
|
||||||
public float Far;
|
public float Far;
|
||||||
public float Aspect;
|
public float Aspect;
|
||||||
|
@ -356,8 +356,9 @@ namespace OpenSim.Framework
|
||||||
args["left_axis"] = OSD.FromString(LeftAxis.ToString());
|
args["left_axis"] = OSD.FromString(LeftAxis.ToString());
|
||||||
args["up_axis"] = OSD.FromString(UpAxis.ToString());
|
args["up_axis"] = OSD.FromString(UpAxis.ToString());
|
||||||
|
|
||||||
|
//backwards compatibility
|
||||||
args["changed_grid"] = OSD.FromBoolean(ChangedGrid);
|
args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
|
||||||
|
args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
|
||||||
args["far"] = OSD.FromReal(Far);
|
args["far"] = OSD.FromReal(Far);
|
||||||
args["aspect"] = OSD.FromReal(Aspect);
|
args["aspect"] = OSD.FromReal(Aspect);
|
||||||
|
|
||||||
|
@ -526,8 +527,8 @@ namespace OpenSim.Framework
|
||||||
if (args["up_axis"] != null)
|
if (args["up_axis"] != null)
|
||||||
Vector3.TryParse(args["up_axis"].AsString(), out AtAxis);
|
Vector3.TryParse(args["up_axis"].AsString(), out AtAxis);
|
||||||
|
|
||||||
if (args["changed_grid"] != null)
|
if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null)
|
||||||
ChangedGrid = args["changed_grid"].AsBoolean();
|
SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean();
|
||||||
|
|
||||||
if (args["far"] != null)
|
if (args["far"] != null)
|
||||||
Far = (float)(args["far"].AsReal());
|
Far = (float)(args["far"].AsReal());
|
||||||
|
@ -634,17 +635,17 @@ namespace OpenSim.Framework
|
||||||
// The code to unpack textures, visuals, wearables and attachments
|
// The code to unpack textures, visuals, wearables and attachments
|
||||||
// should be removed; packed appearance contains the full appearance
|
// should be removed; packed appearance contains the full appearance
|
||||||
// This is retained for backward compatibility only
|
// This is retained for backward compatibility only
|
||||||
if (args["texture_entry"] != null)
|
if (args.ContainsKey("texture_entry") && args["texture_entry"] != null)
|
||||||
{
|
{
|
||||||
byte[] rawtextures = args["texture_entry"].AsBinary();
|
byte[] rawtextures = args["texture_entry"].AsBinary();
|
||||||
Primitive.TextureEntry textures = new Primitive.TextureEntry(rawtextures,0,rawtextures.Length);
|
Primitive.TextureEntry textures = new Primitive.TextureEntry(rawtextures,0,rawtextures.Length);
|
||||||
Appearance.SetTextureEntries(textures);
|
Appearance.SetTextureEntries(textures);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args["visual_params"] != null)
|
if (args.ContainsKey("visual_params") && args["visual_params"] != null)
|
||||||
Appearance.SetVisualParams(args["visual_params"].AsBinary());
|
Appearance.SetVisualParams(args["visual_params"].AsBinary());
|
||||||
|
|
||||||
if ((args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array)
|
if (args.ContainsKey("wearables") && (args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array)
|
||||||
{
|
{
|
||||||
OSDArray wears = (OSDArray)(args["wearables"]);
|
OSDArray wears = (OSDArray)(args["wearables"]);
|
||||||
for (int i = 0; i < wears.Count / 2; i++)
|
for (int i = 0; i < wears.Count / 2; i++)
|
||||||
|
@ -654,7 +655,7 @@ namespace OpenSim.Framework
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((args["attachments"] != null) && (args["attachments"]).Type == OSDType.Array)
|
if (args.ContainsKey("attachments") && (args["attachments"] != null) && (args["attachments"]).Type == OSDType.Array)
|
||||||
{
|
{
|
||||||
OSDArray attachs = (OSDArray)(args["attachments"]);
|
OSDArray attachs = (OSDArray)(args["attachments"]);
|
||||||
foreach (OSD o in attachs)
|
foreach (OSD o in attachs)
|
||||||
|
|
|
@ -825,6 +825,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;
|
||||||
|
@ -1474,7 +1476,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,24 @@ 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;
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1189,6 +1189,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
OSD llsdResponse = null;
|
OSD llsdResponse = null;
|
||||||
|
|
||||||
bool LegacyLLSDLoginLibOMV = (requestBody.Contains("passwd") && requestBody.Contains("mac") && requestBody.Contains("viewer_digest"));
|
bool LegacyLLSDLoginLibOMV = (requestBody.Contains("passwd") && requestBody.Contains("mac") && requestBody.Contains("viewer_digest"));
|
||||||
|
bool nohandler = false;
|
||||||
|
|
||||||
if (requestBody.Length == 0)
|
if (requestBody.Length == 0)
|
||||||
// Get Request
|
// Get Request
|
||||||
|
@ -1227,17 +1228,19 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
{
|
{
|
||||||
// Oops, no handler for this.. give em the failed message
|
// Oops, no handler for this.. give em the failed message
|
||||||
llsdResponse = GenerateNoLLSDHandlerResponse();
|
llsdResponse = GenerateNoLLSDHandlerResponse();
|
||||||
|
nohandler = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
llsdResponse = GenerateNoLLSDHandlerResponse();
|
llsdResponse = GenerateNoLLSDHandlerResponse();
|
||||||
|
nohandler = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] buffer = new byte[0];
|
byte[] buffer = new byte[0];
|
||||||
|
|
||||||
if (llsdResponse.ToString() == "shutdown404!")
|
if (llsdResponse.ToString() == "shutdown404!" || nohandler)
|
||||||
{
|
{
|
||||||
response.ContentType = "text/plain";
|
response.ContentType = "text/plain";
|
||||||
response.StatusCode = 404;
|
response.StatusCode = 404;
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
private readonly BaseHttpServer m_server;
|
private readonly BaseHttpServer m_server;
|
||||||
|
|
||||||
private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
|
private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
|
||||||
private static Queue<PollServiceHttpRequest> m_longPollRequests = new Queue<PollServiceHttpRequest>();
|
private static List<PollServiceHttpRequest> m_longPollRequests = new List<PollServiceHttpRequest>();
|
||||||
|
|
||||||
private uint m_WorkerThreadCount = 0;
|
private uint m_WorkerThreadCount = 0;
|
||||||
private Thread[] m_workerThreads;
|
private Thread[] m_workerThreads;
|
||||||
|
@ -96,7 +96,17 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
private void ReQueueEvent(PollServiceHttpRequest req)
|
private void ReQueueEvent(PollServiceHttpRequest req)
|
||||||
{
|
{
|
||||||
if (m_running)
|
if (m_running)
|
||||||
m_requests.Enqueue(req);
|
{
|
||||||
|
// delay the enqueueing for 100ms. There's no need to have the event
|
||||||
|
// actively on the queue
|
||||||
|
Timer t = new Timer(self => {
|
||||||
|
((Timer)self).Dispose();
|
||||||
|
m_requests.Enqueue(req);
|
||||||
|
});
|
||||||
|
|
||||||
|
t.Change(100, Timeout.Infinite);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Enqueue(PollServiceHttpRequest req)
|
public void Enqueue(PollServiceHttpRequest req)
|
||||||
|
@ -106,7 +116,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll)
|
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll)
|
||||||
{
|
{
|
||||||
lock (m_longPollRequests)
|
lock (m_longPollRequests)
|
||||||
m_longPollRequests.Enqueue(req);
|
m_longPollRequests.Add(req);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_requests.Enqueue(req);
|
m_requests.Enqueue(req);
|
||||||
|
@ -118,7 +128,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
// The only purpose of this thread is to check the EQs for events.
|
// The only purpose of this thread is to check the EQs for events.
|
||||||
// If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests.
|
// If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests.
|
||||||
// If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests.
|
// If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests.
|
||||||
// All other types of tasks (Inventory handlers) don't have the long-poll nature,
|
// All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature,
|
||||||
// so if they aren't ready to be served by a worker thread (no events), they are placed
|
// so if they aren't ready to be served by a worker thread (no events), they are placed
|
||||||
// directly back in the "ready-to-serve" queue by the worker thread.
|
// directly back in the "ready-to-serve" queue by the worker thread.
|
||||||
while (m_running)
|
while (m_running)
|
||||||
|
@ -129,18 +139,20 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>();
|
List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>();
|
||||||
lock (m_longPollRequests)
|
lock (m_longPollRequests)
|
||||||
{
|
{
|
||||||
while (m_longPollRequests.Count > 0 && m_running)
|
if (m_longPollRequests.Count > 0 && m_running)
|
||||||
{
|
{
|
||||||
PollServiceHttpRequest req = m_longPollRequests.Dequeue();
|
List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req =>
|
||||||
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ
|
(req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ
|
||||||
(Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout
|
(Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout
|
||||||
m_requests.Enqueue(req);
|
);
|
||||||
else
|
|
||||||
not_ready.Add(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (PollServiceHttpRequest req in not_ready)
|
ready.ForEach(req =>
|
||||||
m_longPollRequests.Enqueue(req);
|
{
|
||||||
|
m_requests.Enqueue(req);
|
||||||
|
m_longPollRequests.Remove(req);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,8 +171,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
lock (m_longPollRequests)
|
lock (m_longPollRequests)
|
||||||
{
|
{
|
||||||
while (m_longPollRequests.Count > 0 && m_running)
|
if (m_longPollRequests.Count > 0 && m_running)
|
||||||
m_requests.Enqueue(m_longPollRequests.Dequeue());
|
m_longPollRequests.ForEach(req => m_requests.Enqueue(req));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (m_requests.Count() > 0)
|
while (m_requests.Count() > 0)
|
||||||
|
@ -176,6 +188,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_longPollRequests.Clear();
|
||||||
m_requests.Clear();
|
m_requests.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,33 +198,35 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
{
|
{
|
||||||
while (m_running)
|
while (m_running)
|
||||||
{
|
{
|
||||||
|
PollServiceHttpRequest req = m_requests.Dequeue(5000);
|
||||||
|
//m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
|
||||||
|
|
||||||
Watchdog.UpdateThread();
|
Watchdog.UpdateThread();
|
||||||
|
if (req != null)
|
||||||
PollServiceHttpRequest req = null;
|
|
||||||
lock (m_requests)
|
|
||||||
{
|
{
|
||||||
if (m_requests.Count() > 0)
|
try
|
||||||
req = m_requests.Dequeue();
|
|
||||||
}
|
|
||||||
if (req == null)
|
|
||||||
Thread.Sleep(100);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//PollServiceHttpRequest req = m_requests.Dequeue(5000);
|
|
||||||
//m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
|
|
||||||
|
|
||||||
if (req != null)
|
|
||||||
{
|
{
|
||||||
try
|
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
|
||||||
{
|
{
|
||||||
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
|
Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
|
||||||
|
|
||||||
|
if (responsedata == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue
|
||||||
{
|
{
|
||||||
Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
|
try
|
||||||
|
{
|
||||||
if (responsedata == null)
|
req.DoHTTPGruntWork(m_server, responsedata);
|
||||||
continue;
|
}
|
||||||
|
catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
|
||||||
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue
|
{
|
||||||
|
// Ignore it, no need to reply
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_threadPool.QueueWorkItem(x =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -221,41 +236,27 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
{
|
{
|
||||||
// Ignore it, no need to reply
|
// Ignore it, no need to reply
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_threadPool.QueueWorkItem(x =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
req.DoHTTPGruntWork(m_server, responsedata);
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
|
|
||||||
{
|
|
||||||
// Ignore it, no need to reply
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}, null);
|
}, null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
|
||||||
|
{
|
||||||
|
req.DoHTTPGruntWork(
|
||||||
|
m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
|
ReQueueEvent(req);
|
||||||
{
|
|
||||||
req.DoHTTPGruntWork(
|
|
||||||
m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReQueueEvent(req);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
}
|
||||||
{
|
catch (Exception e)
|
||||||
m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
|
{
|
||||||
}
|
m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1779,10 +1779,12 @@ namespace OpenSim.Framework
|
||||||
FireAndForget(callback, null);
|
FireAndForget(callback, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InitThreadPool(int maxThreads)
|
public static void InitThreadPool(int minThreads, int maxThreads)
|
||||||
{
|
{
|
||||||
if (maxThreads < 2)
|
if (maxThreads < 2)
|
||||||
throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
|
throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
|
||||||
|
if (minThreads > maxThreads || minThreads < 2)
|
||||||
|
throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads");
|
||||||
if (m_ThreadPool != null)
|
if (m_ThreadPool != null)
|
||||||
throw new InvalidOperationException("SmartThreadPool is already initialized");
|
throw new InvalidOperationException("SmartThreadPool is already initialized");
|
||||||
|
|
||||||
|
@ -1791,6 +1793,7 @@ namespace OpenSim.Framework
|
||||||
startInfo.IdleTimeout = 2000;
|
startInfo.IdleTimeout = 2000;
|
||||||
startInfo.MaxWorkerThreads = maxThreads;
|
startInfo.MaxWorkerThreads = maxThreads;
|
||||||
startInfo.MinWorkerThreads = 2;
|
startInfo.MinWorkerThreads = 2;
|
||||||
|
startInfo.MinWorkerThreads = minThreads;
|
||||||
|
|
||||||
m_ThreadPool = new SmartThreadPool(startInfo);
|
m_ThreadPool = new SmartThreadPool(startInfo);
|
||||||
}
|
}
|
||||||
|
@ -1865,7 +1868,7 @@ namespace OpenSim.Framework
|
||||||
break;
|
break;
|
||||||
case FireAndForgetMethod.SmartThreadPool:
|
case FireAndForgetMethod.SmartThreadPool:
|
||||||
if (m_ThreadPool == null)
|
if (m_ThreadPool == null)
|
||||||
InitThreadPool(15);
|
InitThreadPool(2, 15);
|
||||||
m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
|
m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
|
||||||
break;
|
break;
|
||||||
case FireAndForgetMethod.Thread:
|
case FireAndForgetMethod.Thread:
|
||||||
|
|
|
@ -86,6 +86,7 @@ namespace OpenSim
|
||||||
IConfig startupConfig = Config.Configs["Startup"];
|
IConfig startupConfig = Config.Configs["Startup"];
|
||||||
IConfig networkConfig = Config.Configs["Network"];
|
IConfig networkConfig = Config.Configs["Network"];
|
||||||
|
|
||||||
|
int stpMinThreads = 2;
|
||||||
int stpMaxThreads = 15;
|
int stpMaxThreads = 15;
|
||||||
|
|
||||||
if (startupConfig != null)
|
if (startupConfig != null)
|
||||||
|
@ -112,12 +113,13 @@ namespace OpenSim
|
||||||
if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse<FireAndForgetMethod>(asyncCallMethodStr, out asyncCallMethod))
|
if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse<FireAndForgetMethod>(asyncCallMethodStr, out asyncCallMethod))
|
||||||
Util.FireAndForgetMethod = asyncCallMethod;
|
Util.FireAndForgetMethod = asyncCallMethod;
|
||||||
|
|
||||||
|
stpMinThreads = startupConfig.GetInt("MinPoolThreads", 15);
|
||||||
stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 15);
|
stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 15);
|
||||||
m_consolePrompt = startupConfig.GetString("ConsolePrompt", @"Region (\R) ");
|
m_consolePrompt = startupConfig.GetString("ConsolePrompt", @"Region (\R) ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
|
if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
|
||||||
Util.InitThreadPool(stpMaxThreads);
|
Util.InitThreadPool(stpMinThreads, stpMaxThreads);
|
||||||
|
|
||||||
m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod);
|
m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,13 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
/// </value>
|
/// </value>
|
||||||
public int DebugLevel { get; set; }
|
public int DebugLevel { get; set; }
|
||||||
|
|
||||||
|
// Viewer post requests timeout in 60 secs
|
||||||
|
// https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44
|
||||||
|
//
|
||||||
|
private const int VIEWER_TIMEOUT = 60 * 1000;
|
||||||
|
// Just to be safe, we work on a 10 sec shorter cycle
|
||||||
|
private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000);
|
||||||
|
|
||||||
protected Scene m_scene;
|
protected Scene m_scene;
|
||||||
|
|
||||||
private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
|
private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
|
||||||
|
@ -364,7 +371,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
|
|
||||||
caps.RegisterPollHandler(
|
caps.RegisterPollHandler(
|
||||||
"EventQueueGet",
|
"EventQueueGet",
|
||||||
new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000));
|
new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
|
||||||
|
|
||||||
Random rnd = new Random(Environment.TickCount);
|
Random rnd = new Random(Environment.TickCount);
|
||||||
lock (m_ids)
|
lock (m_ids)
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -357,7 +358,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
|
||||||
|
@ -485,6 +486,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);
|
||||||
|
@ -809,7 +811,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
|
handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
|
||||||
handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
|
handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
|
||||||
|
|
||||||
OutPacket(handshake, ThrottleOutPacketType.Task);
|
OutPacket(handshake, ThrottleOutPacketType.Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3776,6 +3778,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
ResendPrimUpdate(update);
|
ResendPrimUpdate(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
|
||||||
|
// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
|
||||||
|
// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
|
||||||
|
// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
|
||||||
|
//
|
||||||
|
// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
|
||||||
|
// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
|
||||||
|
// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
|
||||||
|
// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
|
||||||
|
|
||||||
|
|
||||||
private void ProcessEntityUpdates(int maxUpdates)
|
private void ProcessEntityUpdates(int maxUpdates)
|
||||||
{
|
{
|
||||||
OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
|
OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
|
||||||
|
@ -3788,6 +3801,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
|
OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
|
||||||
OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
|
OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
|
||||||
|
|
||||||
|
// objectUpdateBlocks.Value.Clear();
|
||||||
|
// compressedUpdateBlocks.Value.Clear();
|
||||||
|
// terseUpdateBlocks.Value.Clear();
|
||||||
|
// terseAgentUpdateBlocks.Value.Clear();
|
||||||
|
// objectUpdates.Value.Clear();
|
||||||
|
// compressedUpdates.Value.Clear();
|
||||||
|
// terseUpdates.Value.Clear();
|
||||||
|
// terseAgentUpdates.Value.Clear();
|
||||||
|
|
||||||
// Check to see if this is a flush
|
// Check to see if this is a flush
|
||||||
if (maxUpdates <= 0)
|
if (maxUpdates <= 0)
|
||||||
{
|
{
|
||||||
|
@ -4113,8 +4135,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;
|
||||||
|
@ -4140,6 +4168,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();
|
||||||
|
@ -4961,7 +5010,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
ScenePresence presence = (ScenePresence)entity;
|
ScenePresence presence = (ScenePresence)entity;
|
||||||
|
|
||||||
attachPoint = 0;
|
attachPoint = presence.State;
|
||||||
collisionPlane = presence.CollisionPlane;
|
collisionPlane = presence.CollisionPlane;
|
||||||
position = presence.OffsetPosition;
|
position = presence.OffsetPosition;
|
||||||
velocity = presence.Velocity;
|
velocity = presence.Velocity;
|
||||||
|
@ -4985,7 +5034,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);
|
||||||
|
@ -5013,7 +5062,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;
|
||||||
|
@ -5517,82 +5566,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.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);
|
||||||
|
|
||||||
|
@ -12441,7 +12545,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)
|
||||||
{
|
{
|
||||||
|
@ -12455,25 +12559,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>
|
||||||
|
@ -613,15 +616,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
|
||||||
|
@ -631,22 +657,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -182,6 +223,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// <summary>Flag to signal when clients should send pings</summary>
|
/// <summary>Flag to signal when clients should send pings</summary>
|
||||||
protected bool m_sendPing;
|
protected bool m_sendPing;
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
@ -459,6 +509,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(
|
||||||
|
@ -572,6 +635,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)
|
||||||
|
@ -706,6 +777,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)
|
||||||
|
@ -806,6 +890,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketPool.Instance.ReturnPacket(packet);
|
PacketPool.Instance.ReturnPacket(packet);
|
||||||
|
|
||||||
|
m_dataPresentEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1179,6 +1265,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (packet.Type == PacketType.CompleteAgentMovement)
|
||||||
|
{
|
||||||
|
// Send ack straight away to let the viewer know that we got it.
|
||||||
|
SendAckImmediate(endPoint, packet.Header.Sequence);
|
||||||
|
|
||||||
|
// We need to copy the endpoint so that it doesn't get changed when another thread reuses the
|
||||||
|
// buffer.
|
||||||
|
object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
|
||||||
|
|
||||||
|
Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine which agent this packet came from
|
// Determine which agent this packet came from
|
||||||
IClientAPI client;
|
IClientAPI client;
|
||||||
|
@ -1282,6 +1381,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)
|
||||||
|
@ -1499,6 +1617,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleCompleteMovementIntoRegion(object o)
|
||||||
|
{
|
||||||
|
IPEndPoint endPoint = null;
|
||||||
|
IClientAPI client = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object[] array = (object[])o;
|
||||||
|
endPoint = (IPEndPoint)array[0];
|
||||||
|
CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
|
||||||
|
|
||||||
|
// Determine which agent this packet came from
|
||||||
|
int count = 20;
|
||||||
|
bool ready = false;
|
||||||
|
while (!ready && count-- > 0)
|
||||||
|
{
|
||||||
|
// Let's make sure there is an active client attached to a scene presence,
|
||||||
|
// otherwise there won't be any handlers for this packet
|
||||||
|
if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null)
|
||||||
|
{
|
||||||
|
LLClientView llClientView = (LLClientView)client;
|
||||||
|
LLUDPClient udpClient = llClientView.UDPClient;
|
||||||
|
if (udpClient != null && udpClient.IsConnected)
|
||||||
|
ready = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)");
|
||||||
|
Thread.Sleep(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)");
|
||||||
|
Thread.Sleep(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IncomingPacket incomingPacket1;
|
||||||
|
|
||||||
|
// Inbox insertion
|
||||||
|
if (UsePools)
|
||||||
|
{
|
||||||
|
incomingPacket1 = m_incomingPacketPool.GetObject();
|
||||||
|
incomingPacket1.Client = (LLClientView)client;
|
||||||
|
incomingPacket1.Packet = packet;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
packetInbox.Enqueue(incomingPacket1);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
m_log.ErrorFormat(
|
||||||
|
"[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
|
||||||
|
endPoint != null ? endPoint.ToString() : "n/a",
|
||||||
|
client != null ? client.Name : "unknown",
|
||||||
|
client != null ? client.AgentId.ToString() : "unknown",
|
||||||
|
e.Message,
|
||||||
|
e.StackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send an ack immediately to the given endpoint.
|
/// Send an ack immediately to the given endpoint.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1718,8 +1904,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
// If nothing was sent, sleep for the minimum amount of time before a
|
// If nothing was sent, sleep for the minimum amount of time before a
|
||||||
// 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);
|
||||||
|
|
||||||
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);
|
||||||
|
@ -155,6 +187,8 @@ namespace OpenMetaverse
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void StartOutbound()
|
public void StartOutbound()
|
||||||
{
|
{
|
||||||
|
m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
|
||||||
|
|
||||||
IsRunningOutbound = true;
|
IsRunningOutbound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,10 +196,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();
|
||||||
}
|
}
|
||||||
|
@ -173,6 +205,8 @@ namespace OpenMetaverse
|
||||||
|
|
||||||
public void StopOutbound()
|
public void StopOutbound()
|
||||||
{
|
{
|
||||||
|
m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
|
||||||
|
|
||||||
IsRunningOutbound = false;
|
IsRunningOutbound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,6 +305,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)
|
||||||
|
@ -282,6 +318,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);
|
||||||
|
@ -289,6 +327,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) { }
|
||||||
|
@ -302,14 +357,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(
|
||||||
|
@ -323,7 +377,7 @@ namespace OpenMetaverse
|
||||||
}
|
}
|
||||||
catch (SocketException) { }
|
catch (SocketException) { }
|
||||||
catch (ObjectDisposedException) { }
|
catch (ObjectDisposedException) { }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncEndSend(IAsyncResult result)
|
void AsyncEndSend(IAsyncResult result)
|
||||||
|
@ -332,6 +386,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) { }
|
||||||
|
|
|
@ -684,6 +684,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
|
agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version.Equals("SIMULATION/0.2"))
|
||||||
|
TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason);
|
||||||
|
else
|
||||||
|
TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
|
||||||
|
IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, string version, out string reason)
|
||||||
|
{
|
||||||
|
ulong destinationHandle = finalDestination.RegionHandle;
|
||||||
|
AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
|
||||||
|
|
||||||
|
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Using TP V1");
|
||||||
// Let's create an agent there if one doesn't exist yet.
|
// Let's create an agent there if one doesn't exist yet.
|
||||||
// NOTE: logout will always be false for a non-HG teleport.
|
// NOTE: logout will always be false for a non-HG teleport.
|
||||||
bool logout = false;
|
bool logout = false;
|
||||||
|
@ -728,6 +742,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
sp.CloseChildAgents(newRegionX, newRegionY);
|
sp.CloseChildAgents(newRegionX, newRegionY);
|
||||||
|
|
||||||
IClientIPEndpoint ipepClient;
|
IClientIPEndpoint ipepClient;
|
||||||
|
string capsPath = String.Empty;
|
||||||
if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
|
if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
|
@ -778,10 +793,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
// Let's send a full update of the agent. This is a synchronous call.
|
// Let's send a full update of the agent. This is a synchronous call.
|
||||||
AgentData agent = new AgentData();
|
AgentData agent = new AgentData();
|
||||||
sp.CopyTo(agent);
|
sp.CopyTo(agent);
|
||||||
agent.Position = position;
|
agent.Position = agentCircuit.startpos;
|
||||||
SetCallbackURL(agent, sp.Scene.RegionInfo);
|
SetCallbackURL(agent, sp.Scene.RegionInfo);
|
||||||
|
|
||||||
//sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
|
|
||||||
|
|
||||||
// We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
|
// We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
|
||||||
// establish th econnection to the destination which makes it return true.
|
// establish th econnection to the destination which makes it return true.
|
||||||
|
@ -843,6 +857,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
// closes our existing agent which is still signalled as root.
|
// closes our existing agent which is still signalled as root.
|
||||||
sp.IsChildAgent = true;
|
sp.IsChildAgent = true;
|
||||||
|
|
||||||
|
// OK, send TPFinish to the client, so that it starts the process of contacting the destination region
|
||||||
if (m_eqModule != null)
|
if (m_eqModule != null)
|
||||||
{
|
{
|
||||||
m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID);
|
m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID);
|
||||||
|
@ -901,13 +916,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
|
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
|
||||||
{
|
{
|
||||||
// We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
|
// RED ALERT!!!!
|
||||||
// they regard the new region as the current region after receiving the AgentMovementComplete
|
// PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
|
||||||
// response. If close is sent before then, it will cause the viewer to quit instead.
|
// THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
|
||||||
//
|
// BEFORE THEY SETTLE IN THE NEW REGION.
|
||||||
// This sleep can be increased if necessary. However, whilst it's active,
|
// DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR
|
||||||
// an agent cannot teleport back to this region if it has teleported away.
|
// IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS.
|
||||||
Thread.Sleep(2000);
|
Thread.Sleep(5000);
|
||||||
|
|
||||||
sp.Scene.IncomingCloseAgent(sp.UUID, false);
|
sp.Scene.IncomingCloseAgent(sp.UUID, false);
|
||||||
}
|
}
|
||||||
|
@ -918,6 +933,134 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
|
||||||
|
IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, string version, out string reason)
|
||||||
|
{
|
||||||
|
ulong destinationHandle = finalDestination.RegionHandle;
|
||||||
|
AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
|
||||||
|
|
||||||
|
// Let's create an agent there if one doesn't exist yet.
|
||||||
|
// NOTE: logout will always be false for a non-HG teleport.
|
||||||
|
bool logout = false;
|
||||||
|
if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
|
||||||
|
{
|
||||||
|
m_interRegionTeleportFailures.Value++;
|
||||||
|
|
||||||
|
sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
|
||||||
|
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}",
|
||||||
|
sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Past this point we have to attempt clean up if the teleport fails, so update transfer state.
|
||||||
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
||||||
|
|
||||||
|
IClientIPEndpoint ipepClient;
|
||||||
|
string capsPath = String.Empty;
|
||||||
|
if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
|
||||||
|
{
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}",
|
||||||
|
finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
|
||||||
|
|
||||||
|
//sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
|
||||||
|
#region IP Translation for NAT
|
||||||
|
// Uses ipepClient above
|
||||||
|
if (sp.ClientView.TryGet(out ipepClient))
|
||||||
|
{
|
||||||
|
endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle);
|
||||||
|
capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
|
||||||
|
// where that neighbour simulator could otherwise request a child agent create on the source which then
|
||||||
|
// closes our existing agent which is still signalled as root.
|
||||||
|
//sp.IsChildAgent = true;
|
||||||
|
|
||||||
|
// New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid
|
||||||
|
if (m_eqModule != null)
|
||||||
|
m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID);
|
||||||
|
else
|
||||||
|
sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4,
|
||||||
|
teleportFlags, capsPath);
|
||||||
|
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
|
||||||
|
capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
|
||||||
|
|
||||||
|
// Let's send a full update of the agent.
|
||||||
|
AgentData agent = new AgentData();
|
||||||
|
sp.CopyTo(agent);
|
||||||
|
agent.Position = agentCircuit.startpos;
|
||||||
|
agent.SenderWantsToWaitForRoot = true;
|
||||||
|
//SetCallbackURL(agent, sp.Scene.RegionInfo);
|
||||||
|
|
||||||
|
// Send the Update. If this returns true, we know the client has contacted the destination
|
||||||
|
// via CompleteMovementIntoRegion, so we can let go.
|
||||||
|
// If it returns false, something went wrong, and we need to abort.
|
||||||
|
if (!UpdateAgent(reg, finalDestination, agent, sp))
|
||||||
|
{
|
||||||
|
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
|
||||||
|
{
|
||||||
|
m_interRegionTeleportAborts.Value++;
|
||||||
|
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
|
||||||
|
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.",
|
||||||
|
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
||||||
|
|
||||||
|
// May need to logout or other cleanup
|
||||||
|
AgentHasMovedAway(sp, logout);
|
||||||
|
|
||||||
|
// Well, this is it. The agent is over there.
|
||||||
|
KillEntity(sp.Scene, sp.LocalId);
|
||||||
|
|
||||||
|
// Now let's make it officially a child agent
|
||||||
|
sp.MakeChildAgent();
|
||||||
|
|
||||||
|
// OK, it got this agent. Let's close some child agents
|
||||||
|
sp.CloseChildAgents(newRegionX, newRegionY);
|
||||||
|
|
||||||
|
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
|
||||||
|
|
||||||
|
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
|
||||||
|
{
|
||||||
|
// RED ALERT!!!!
|
||||||
|
// PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
|
||||||
|
// THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
|
||||||
|
// BEFORE THEY SETTLE IN THE NEW REGION.
|
||||||
|
// DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR
|
||||||
|
// IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS.
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
sp.Scene.IncomingCloseAgent(sp.UUID, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// now we have a child agent in this region.
|
||||||
|
sp.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
|
/// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -931,11 +1074,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
{
|
{
|
||||||
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
||||||
|
|
||||||
sp.IsChildAgent = false;
|
if (sp.IsChildAgent) // We had set it to child before attempted TP (V1)
|
||||||
ReInstantiateScripts(sp);
|
{
|
||||||
|
sp.IsChildAgent = false;
|
||||||
EnableChildAgents(sp);
|
ReInstantiateScripts(sp);
|
||||||
|
|
||||||
|
EnableChildAgents(sp);
|
||||||
|
}
|
||||||
// Finally, kill the agent we just created at the destination.
|
// Finally, kill the agent we just created at the destination.
|
||||||
// XXX: Possibly this should be done asynchronously.
|
// XXX: Possibly this should be done asynchronously.
|
||||||
Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token);
|
Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -244,8 +244,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
||||||
if (inventoryURL != null && inventoryURL != string.Empty)
|
if (inventoryURL != null && inventoryURL != string.Empty)
|
||||||
{
|
{
|
||||||
inventoryURL = inventoryURL.Trim(new char[] { '/' });
|
inventoryURL = inventoryURL.Trim(new char[] { '/' });
|
||||||
m_InventoryURLs.Add(userID, inventoryURL);
|
lock (m_InventoryURLs)
|
||||||
m_log.DebugFormat("[HG INVENTORY CONNECTOR]: Added {0} to the cache of inventory URLs", inventoryURL);
|
if (!m_InventoryURLs.ContainsKey(userID))
|
||||||
|
{
|
||||||
|
m_InventoryURLs.Add(userID, inventoryURL);
|
||||||
|
m_log.DebugFormat("[HG INVENTORY CONNECTOR]: Added {0} to the cache of inventory URLs", inventoryURL);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
||||||
|
|
||||||
public void OnConnectionClose(IClientAPI client)
|
public void OnConnectionClose(IClientAPI client)
|
||||||
{
|
{
|
||||||
if (!client.SceneAgent.IsChildAgent)
|
if (client != null && client.SceneAgent != null && !client.SceneAgent.IsChildAgent)
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName);
|
// m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName);
|
||||||
m_PresenceService.LogoutAgent(client.SessionId);
|
m_PresenceService.LogoutAgent(client.SessionId);
|
||||||
|
|
|
@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of this service
|
/// Version of this service
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const string m_Version = "SIMULATION/0.1";
|
private const string m_Version = "SIMULATION/0.2";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Map region ID to scene.
|
/// Map region ID to scene.
|
||||||
|
|
|
@ -742,7 +742,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;
|
||||||
|
|
||||||
|
@ -2146,7 +2146,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)
|
||||||
|
@ -2155,7 +2155,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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -390,6 +390,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++)
|
||||||
{
|
{
|
||||||
|
@ -401,15 +402,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -230,6 +230,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public int MaxUndoCount { get; set; }
|
public int MaxUndoCount { get; set; }
|
||||||
|
|
||||||
|
public bool SeeIntoRegion { get; set; }
|
||||||
|
|
||||||
// Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
|
// Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
|
||||||
public bool LoginLock = false;
|
public bool LoginLock = false;
|
||||||
|
|
||||||
|
@ -839,6 +841,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
//Animation states
|
//Animation states
|
||||||
m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
|
m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
|
||||||
|
|
||||||
|
SeeIntoRegion = startupConfig.GetBoolean("see_into_region", true);
|
||||||
|
|
||||||
MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20);
|
MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20);
|
||||||
|
|
||||||
PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims);
|
PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims);
|
||||||
|
@ -3735,7 +3739,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!AuthorizeUser(agent, out reason))
|
if (!AuthorizeUser(agent, SeeIntoRegion, out reason))
|
||||||
{
|
{
|
||||||
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
|
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
|
||||||
return false;
|
return false;
|
||||||
|
@ -3975,7 +3979,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <param name="reason">outputs the reason to this string</param>
|
/// <param name="reason">outputs the reason to this string</param>
|
||||||
/// <returns>True if the region accepts this agent. False if it does not. False will
|
/// <returns>True if the region accepts this agent. False if it does not. False will
|
||||||
/// also return a reason.</returns>
|
/// also return a reason.</returns>
|
||||||
protected virtual bool AuthorizeUser(AgentCircuitData agent, out string reason)
|
protected virtual bool AuthorizeUser(AgentCircuitData agent, bool bypassAccessControl, out string reason)
|
||||||
{
|
{
|
||||||
reason = String.Empty;
|
reason = String.Empty;
|
||||||
|
|
||||||
|
@ -4010,52 +4014,59 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
|
m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UUID> agentGroups = new List<UUID>();
|
// We only test the things below when we want to cut off
|
||||||
|
// child agents from being present in the scene for which their root
|
||||||
if (m_groupsModule != null)
|
// agent isn't allowed. Otherwise, we allow child agents. The test for
|
||||||
|
// the root is done elsewhere (QueryAccess)
|
||||||
|
if (!bypassAccessControl)
|
||||||
{
|
{
|
||||||
GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID);
|
List<UUID> agentGroups = new List<UUID>();
|
||||||
|
|
||||||
if (GroupMembership != null)
|
if (m_groupsModule != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < GroupMembership.Length; i++)
|
GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID);
|
||||||
agentGroups.Add(GroupMembership[i].GroupID);
|
|
||||||
|
if (GroupMembership != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < GroupMembership.Length; i++)
|
||||||
|
agentGroups.Add(GroupMembership[i].GroupID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool groupAccess = false;
|
||||||
|
UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups;
|
||||||
|
|
||||||
|
if (estateGroups != null)
|
||||||
|
{
|
||||||
|
foreach (UUID group in estateGroups)
|
||||||
|
{
|
||||||
|
if (agentGroups.Contains(group))
|
||||||
|
{
|
||||||
|
groupAccess = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!");
|
m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool groupAccess = false;
|
if (!RegionInfo.EstateSettings.PublicAccess &&
|
||||||
UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups;
|
!RegionInfo.EstateSettings.HasAccess(agent.AgentID) &&
|
||||||
|
!groupAccess)
|
||||||
if (estateGroups != null)
|
|
||||||
{
|
|
||||||
foreach (UUID group in estateGroups)
|
|
||||||
{
|
{
|
||||||
if (agentGroups.Contains(group))
|
m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate",
|
||||||
{
|
agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
|
||||||
groupAccess = true;
|
reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
|
||||||
break;
|
RegionInfo.RegionName);
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RegionInfo.EstateSettings.PublicAccess &&
|
|
||||||
!RegionInfo.EstateSettings.HasAccess(agent.AgentID) &&
|
|
||||||
!groupAccess)
|
|
||||||
{
|
|
||||||
m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate",
|
|
||||||
agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
|
|
||||||
reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
|
|
||||||
RegionInfo.RegionName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: estate/region settings are not properly hooked up
|
// TODO: estate/region settings are not properly hooked up
|
||||||
// to ILandObject.isRestrictedFromLand()
|
// to ILandObject.isRestrictedFromLand()
|
||||||
|
@ -4203,13 +4214,23 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
if (childAgentUpdate != null)
|
if (childAgentUpdate != null)
|
||||||
{
|
{
|
||||||
if (cAgentData.SessionID != childAgentUpdate.ControllingClient.SessionId)
|
if (cAgentData.SessionID != childAgentUpdate.ControllingClient.SessionId)
|
||||||
{
|
|
||||||
m_log.WarnFormat("[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).", childAgentUpdate.UUID, cAgentData.SessionID);
|
m_log.WarnFormat("[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).", childAgentUpdate.UUID, cAgentData.SessionID);
|
||||||
Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}",
|
|
||||||
childAgentUpdate.UUID, childAgentUpdate.ControllingClient.SessionId, cAgentData.SessionID));
|
|
||||||
}
|
|
||||||
|
|
||||||
childAgentUpdate.ChildAgentDataUpdate(cAgentData);
|
childAgentUpdate.ChildAgentDataUpdate(cAgentData);
|
||||||
|
|
||||||
|
int ntimes = 20;
|
||||||
|
if (cAgentData.SenderWantsToWaitForRoot)
|
||||||
|
{
|
||||||
|
while (childAgentUpdate.IsChildAgent && ntimes-- > 0)
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCENE]: Found presence {0} {1} {2} in {3} after {4} waits",
|
||||||
|
childAgentUpdate.Name, childAgentUpdate.UUID, childAgentUpdate.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 20 - ntimes);
|
||||||
|
|
||||||
|
if (childAgentUpdate.IsChildAgent)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -4258,7 +4279,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <param name='agentID'></param>
|
/// <param name='agentID'></param>
|
||||||
protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
|
protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
|
||||||
{
|
{
|
||||||
int ntimes = 10;
|
int ntimes = 20;
|
||||||
ScenePresence sp = null;
|
ScenePresence sp = null;
|
||||||
while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0))
|
while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0))
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
|
@ -4267,10 +4288,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_log.WarnFormat(
|
m_log.WarnFormat(
|
||||||
"[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout",
|
"[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout",
|
||||||
agentID, RegionInfo.RegionName);
|
agentID, RegionInfo.RegionName);
|
||||||
// else
|
|
||||||
// m_log.DebugFormat(
|
|
||||||
// "[SCENE PRESENCE]: Found presence {0} {1} {2} in {3} after {4} waits",
|
|
||||||
// sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 10 - ntimes);
|
|
||||||
|
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
@ -5577,7 +5594,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!AuthorizeUser(aCircuit, out reason))
|
if (!AuthorizeUser(aCircuit, false, out reason))
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
|
// m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -29,7 +29,9 @@ using System;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
using Timer = System.Timers.Timer;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
|
@ -801,6 +803,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;
|
||||||
|
@ -1010,9 +1013,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// recorded, which stops the input from being processed.
|
// recorded, which stops the input from being processed.
|
||||||
MovementFlag = 0;
|
MovementFlag = 0;
|
||||||
|
|
||||||
// DIVA NOTE: I moved TriggerOnMakeRootAgent out of here and into the end of
|
m_scene.EventManager.TriggerOnMakeRootAgent(this);
|
||||||
// CompleteMovement. We don't want modules doing heavy computation before CompleteMovement
|
|
||||||
// is over.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetStateSource()
|
public int GetStateSource()
|
||||||
|
@ -1124,7 +1126,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>
|
||||||
|
@ -1291,6 +1312,26 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
PhysicsActor.Size = new Vector3(0.45f, 0.6f, height);
|
PhysicsActor.Size = new Vector3(0.45f, 0.6f, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool WaitForUpdateAgent(IClientAPI client)
|
||||||
|
{
|
||||||
|
// Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero
|
||||||
|
int count = 20;
|
||||||
|
while (m_originRegionID.Equals(UUID.Zero) && count-- > 0)
|
||||||
|
{
|
||||||
|
m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.RegionInfo.RegionName);
|
||||||
|
Thread.Sleep(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_originRegionID.Equals(UUID.Zero))
|
||||||
|
{
|
||||||
|
// Movement into region will fail
|
||||||
|
m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived", client.Name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Complete Avatar's movement into the region.
|
/// Complete Avatar's movement into the region.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1308,6 +1349,13 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
"[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}",
|
"[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}",
|
||||||
client.Name, Scene.RegionInfo.RegionName, AbsolutePosition);
|
client.Name, Scene.RegionInfo.RegionName, AbsolutePosition);
|
||||||
|
|
||||||
|
// Make sure it's not a login agent. We don't want to wait for updates during login
|
||||||
|
if ((m_teleportFlags & TeleportFlags.ViaLogin) == 0)
|
||||||
|
// Let's wait until UpdateAgent (called by departing region) is done
|
||||||
|
if (!WaitForUpdateAgent(client))
|
||||||
|
// The sending region never sent the UpdateAgent data, we have to refuse
|
||||||
|
return;
|
||||||
|
|
||||||
Vector3 look = Velocity;
|
Vector3 look = Velocity;
|
||||||
|
|
||||||
if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
|
if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
|
||||||
|
@ -1328,10 +1376,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
|
bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
|
||||||
MakeRootAgent(AbsolutePosition, flying);
|
MakeRootAgent(AbsolutePosition, flying);
|
||||||
|
|
||||||
|
// Tell the client that we're totally ready
|
||||||
ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
|
ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
|
||||||
|
|
||||||
// Remember in HandleUseCircuitCode, we delayed this to here
|
// Remember in HandleUseCircuitCode, we delayed this to here
|
||||||
// This will also send the initial data to clients when TP to a neighboring region.
|
|
||||||
// Not ideal, but until we know we're TP-ing from a neighboring region, there's not much we can do
|
|
||||||
if (m_teleportFlags > 0)
|
if (m_teleportFlags > 0)
|
||||||
SendInitialDataToMe();
|
SendInitialDataToMe();
|
||||||
|
|
||||||
|
@ -1387,10 +1436,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
|
// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
|
||||||
// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);
|
// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);
|
||||||
|
|
||||||
// DIVA NOTE: moved this here from MakeRoot. We don't want modules making heavy
|
|
||||||
// computations before CompleteMovement is over
|
|
||||||
m_scene.EventManager.TriggerOnMakeRootAgent(this);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1438,9 +1483,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)
|
||||||
{
|
{
|
||||||
|
@ -1448,10 +1493,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.
|
||||||
|
@ -1482,21 +1523,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
|
||||||
|
@ -1504,12 +1530,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// DrawDistance = agentData.Far;
|
// DrawDistance = agentData.Far;
|
||||||
DrawDistance = Scene.DefaultDrawDistance;
|
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_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0;
|
m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0;
|
||||||
m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0;
|
m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0;
|
||||||
|
|
||||||
|
@ -1529,17 +1549,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
StandUp();
|
StandUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
//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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint flagsForScripts = (uint)flags;
|
uint flagsForScripts = (uint)flags;
|
||||||
flags = RemoveIgnoredControls(flags, IgnoredControls);
|
flags = RemoveIgnoredControls(flags, IgnoredControls);
|
||||||
|
|
||||||
|
@ -1763,7 +1772,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -687,6 +687,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;
|
||||||
|
@ -1672,7 +1673,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));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,6 +258,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;
|
||||||
|
@ -1228,7 +1229,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopFlying(ISceneEntity presence)
|
public void SendAgentTerseUpdate(ISceneEntity presence)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ public class BSActorAvatarMove : BSActor
|
||||||
SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
|
SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
|
||||||
|
|
||||||
m_physicsScene.BeforeStep += Mover;
|
m_physicsScene.BeforeStep += Mover;
|
||||||
|
m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty;
|
||||||
|
|
||||||
m_walkingUpStairs = 0;
|
m_walkingUpStairs = 0;
|
||||||
}
|
}
|
||||||
|
@ -139,6 +140,7 @@ public class BSActorAvatarMove : BSActor
|
||||||
{
|
{
|
||||||
if (m_velocityMotor != null)
|
if (m_velocityMotor != null)
|
||||||
{
|
{
|
||||||
|
m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty;
|
||||||
m_physicsScene.BeforeStep -= Mover;
|
m_physicsScene.BeforeStep -= Mover;
|
||||||
m_velocityMotor = null;
|
m_velocityMotor = null;
|
||||||
}
|
}
|
||||||
|
@ -197,7 +199,7 @@ public class BSActorAvatarMove : BSActor
|
||||||
{
|
{
|
||||||
if (m_controllingPrim.Flying)
|
if (m_controllingPrim.Flying)
|
||||||
{
|
{
|
||||||
// Flying and not collising and velocity nearly zero.
|
// Flying and not colliding and velocity nearly zero.
|
||||||
m_controllingPrim.ZeroMotion(true /* inTaintTime */);
|
m_controllingPrim.ZeroMotion(true /* inTaintTime */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,6 +268,19 @@ public class BSActorAvatarMove : BSActor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called just as the property update is received from the physics engine.
|
||||||
|
// Do any mode necessary for avatar movement.
|
||||||
|
private void Process_OnPreUpdateProperty(ref EntityProperties entprop)
|
||||||
|
{
|
||||||
|
// Don't change position if standing on a stationary object.
|
||||||
|
if (m_controllingPrim.IsStationary)
|
||||||
|
{
|
||||||
|
entprop.Position = m_controllingPrim.RawPosition;
|
||||||
|
m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Decide if the character is colliding with a low object and compute a force to pop the
|
// Decide if the character is colliding with a low object and compute a force to pop the
|
||||||
// avatar up so it can walk up and over the low objects.
|
// avatar up so it can walk up and over the low objects.
|
||||||
private OMV.Vector3 WalkUpStairs()
|
private OMV.Vector3 WalkUpStairs()
|
||||||
|
|
|
@ -709,10 +709,10 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
// the world that things have changed.
|
// the world that things have changed.
|
||||||
public override void UpdateProperties(EntityProperties entprop)
|
public override void UpdateProperties(EntityProperties entprop)
|
||||||
{
|
{
|
||||||
// Don't change position if standing on a stationary object.
|
// Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
|
||||||
if (!IsStationary)
|
TriggerPreUpdatePropertyAction(ref entprop);
|
||||||
RawPosition = entprop.Position;
|
|
||||||
|
|
||||||
|
RawPosition = entprop.Position;
|
||||||
RawOrientation = entprop.Rotation;
|
RawOrientation = entprop.Rotation;
|
||||||
|
|
||||||
// Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
|
// Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
|
||||||
|
@ -740,7 +740,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
// Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
|
// Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
|
||||||
|
|
||||||
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
||||||
// base.RequestPhysicsterseUpdate();
|
// PhysScene.PostUpdate(this);
|
||||||
|
|
||||||
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
||||||
LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
|
LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -106,6 +106,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;
|
||||||
|
@ -1255,7 +1256,7 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopFlying(ISceneEntity presence)
|
public void SendAgentTerseUpdate(ISceneEntity presence)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,9 @@
|
||||||
;; from the selected region_info_source.
|
;; from the selected region_info_source.
|
||||||
allow_regionless = false
|
allow_regionless = false
|
||||||
|
|
||||||
|
;; Allow child agents to see into the region even if their root counterpart isn't allowed in here
|
||||||
|
see_into_region = true
|
||||||
|
|
||||||
; Maximum number of position, rotation and scale changes for each prim that the simulator will store for later undos
|
; Maximum number of position, rotation and scale changes for each prim that the simulator will store for later undos
|
||||||
; Increasing this number will increase memory usage.
|
; Increasing this number will increase memory usage.
|
||||||
MaxPrimUndos = 20
|
MaxPrimUndos = 20
|
||||||
|
|
Loading…
Reference in New Issue