Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16aca6ddbd | ||
|
|
38458d4be8 | ||
|
|
9ee171f441 | ||
|
|
7ca4e2cb6f | ||
|
|
523f0b8938 | ||
|
|
4f04c0b560 | ||
|
|
b7f78bf0f7 | ||
|
|
5cb3b87b21 | ||
|
|
97e25a0f45 | ||
|
|
026df644b5 | ||
|
|
c3b1c72c33 | ||
|
|
277dbb9acd | ||
|
|
6cfebd66ec | ||
|
|
c9d7eb30db | ||
|
|
db5de62394 | ||
|
|
5c3f33bb48 | ||
|
|
d50f85dff6 | ||
|
|
b7abcd28e1 | ||
|
|
d53703362e | ||
|
|
4e1f2ba1f4 | ||
|
|
51951682e7 | ||
|
|
c5c387e838 | ||
|
|
f7fef5bc3b | ||
|
|
8e5a62c8e7 | ||
|
|
ad15e06611 | ||
|
|
319c51b8a8 | ||
|
|
11830c4363 | ||
|
|
2eece5b009 | ||
|
|
528a7f3352 | ||
|
|
c02b33d592 | ||
|
|
07c6630c1c | ||
|
|
cfc95afc3d | ||
|
|
85e04198fe | ||
|
|
1256d643be | ||
|
|
f2715a5a2f | ||
|
|
d2b8281df9 | ||
|
|
6b05cfce25 | ||
|
|
0448935b1b | ||
|
|
bc01c27c8a | ||
|
|
95aade7fdb | ||
|
|
7ff27e32bc | ||
|
|
89c153ca7f | ||
|
|
a6c79fe956 | ||
|
|
1e5c3f26f0 | ||
|
|
e6df61fbe9 | ||
|
|
5991a98d80 | ||
|
|
c4ed67aeee | ||
|
|
258de1f17f | ||
|
|
f8fa76c09f | ||
|
|
0b7736b861 | ||
|
|
a086adf427 | ||
|
|
e76cc35409 | ||
|
|
a129e9e351 | ||
|
|
3c7eacf39b | ||
|
|
cd6f73392a | ||
|
|
1559a3a099 | ||
|
|
6520065625 | ||
|
|
693bfdc0fb | ||
|
|
f3eaa6d81e |
@@ -72,10 +72,12 @@ what it is today.
|
||||
* Allen Kerensky
|
||||
* BigFootAg
|
||||
* BlueWall Slade
|
||||
* bobshaffer2
|
||||
* brianw/Sir_Ahzz
|
||||
* CharlieO
|
||||
* ChrisDown
|
||||
* Chris Yeoh (IBM)
|
||||
* cinderblocks
|
||||
* controlbreak
|
||||
* coyled
|
||||
* ctrlaltdavid (David Rowe)
|
||||
|
||||
@@ -150,7 +150,8 @@ namespace OpenSim.Groups
|
||||
data.Data["ShowInList"] = showInList ? "1" : "0";
|
||||
data.Data["AllowPublish"] = allowPublish ? "1" : "0";
|
||||
data.Data["MaturePublish"] = maturePublish ? "1" : "0";
|
||||
data.Data["OwnerRoleID"] = UUID.Random().ToString();
|
||||
UUID roleID = UUID.Random();
|
||||
data.Data["OwnerRoleID"] = roleID.ToString();
|
||||
|
||||
if (!m_Database.StoreGroup(data))
|
||||
return UUID.Zero;
|
||||
@@ -159,7 +160,6 @@ namespace OpenSim.Groups
|
||||
_AddOrUpdateGroupRole(RequestingAgentID, data.GroupID, UUID.Zero, "Everyone", "Everyone in the group", "Member of " + name, (ulong)DefaultEveryonePowers, true);
|
||||
|
||||
// Create Owner role
|
||||
UUID roleID = UUID.Random();
|
||||
_AddOrUpdateGroupRole(RequestingAgentID, data.GroupID, roleID, "Owners", "Owners of the group", "Owner of " + name, (ulong)OwnerPowers, true);
|
||||
|
||||
// Add founder to group
|
||||
@@ -247,6 +247,9 @@ namespace OpenSim.Groups
|
||||
if (group == null)
|
||||
return members;
|
||||
|
||||
// Unfortunately this doesn't quite work on legacy group data because of a bug
|
||||
// that's also being fixed here on CreateGroup. The OwnerRoleID sent to the DB was wrong.
|
||||
// See how to find the ownerRoleID a few lines below.
|
||||
UUID ownerRoleID = new UUID(group.Data["OwnerRoleID"]);
|
||||
|
||||
RoleData[] roles = m_Database.RetrieveRoles(GroupID);
|
||||
@@ -255,6 +258,11 @@ namespace OpenSim.Groups
|
||||
return members;
|
||||
List<RoleData> rolesList = new List<RoleData>(roles);
|
||||
|
||||
// Let's find the "real" ownerRoleID
|
||||
RoleData ownerRole = rolesList.Find(r => r.Data["Powers"] == ((long)OwnerPowers).ToString());
|
||||
if (ownerRole != null)
|
||||
ownerRoleID = ownerRole.RoleID;
|
||||
|
||||
// Check visibility?
|
||||
// When we don't want to check visibility, we pass it "all" as the requestingAgentID
|
||||
bool checkVisibility = !RequestingAgentID.Equals(UUID.Zero.ToString());
|
||||
@@ -291,17 +299,17 @@ namespace OpenSim.Groups
|
||||
{
|
||||
m.Title = selected.Data["Title"];
|
||||
m.AgentPowers = UInt64.Parse(selected.Data["Powers"]);
|
||||
|
||||
m.AgentID = d.PrincipalID;
|
||||
m.AcceptNotices = d.Data["AcceptNotices"] == "1" ? true : false;
|
||||
m.Contribution = Int32.Parse(d.Data["Contribution"]);
|
||||
m.ListInProfile = d.Data["ListInProfile"] == "1" ? true : false;
|
||||
|
||||
// Is this person an owner of the group?
|
||||
m.IsOwner = (rolemembershipsList.Find(r => r.RoleID == ownerRoleID) != null) ? true : false;
|
||||
|
||||
members.Add(m);
|
||||
}
|
||||
|
||||
m.AgentID = d.PrincipalID;
|
||||
m.AcceptNotices = d.Data["AcceptNotices"] == "1" ? true : false;
|
||||
m.Contribution = Int32.Parse(d.Data["Contribution"]);
|
||||
m.ListInProfile = d.Data["ListInProfile"] == "1" ? true : false;
|
||||
|
||||
// Is this person an owner of the group?
|
||||
m.IsOwner = (rolemembershipsList.Find(r => r.RoleID == ownerRoleID) != null) ? true : false;
|
||||
|
||||
members.Add(m);
|
||||
}
|
||||
|
||||
return members;
|
||||
|
||||
312
OpenSim/Framework/Monitoring/JobEngine.cs
Normal file
312
OpenSim/Framework/Monitoring/JobEngine.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenSim.Framework.Monitoring
|
||||
{
|
||||
public class Job
|
||||
{
|
||||
public string Name;
|
||||
public WaitCallback Callback;
|
||||
public object O;
|
||||
|
||||
public Job(string name, WaitCallback callback, object o)
|
||||
{
|
||||
Name = name;
|
||||
Callback = callback;
|
||||
O = o;
|
||||
}
|
||||
}
|
||||
|
||||
public class JobEngine
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public int LogLevel { get; set; }
|
||||
|
||||
public bool IsRunning { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The timeout in milliseconds to wait for at least one event to be written when the recorder is stopping.
|
||||
/// </summary>
|
||||
public int RequestProcessTimeoutOnStop { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controls whether we need to warn in the log about exceeding the max queue size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in
|
||||
/// order to avoid spamming the log with lots of warnings.
|
||||
/// </remarks>
|
||||
private bool m_warnOverMaxQueue = true;
|
||||
|
||||
private BlockingCollection<Job> m_requestQueue;
|
||||
|
||||
private CancellationTokenSource m_cancelSource = new CancellationTokenSource();
|
||||
|
||||
private Stat m_requestsWaitingStat;
|
||||
|
||||
private Job m_currentJob;
|
||||
|
||||
/// <summary>
|
||||
/// Used to signal that we are ready to complete stop.
|
||||
/// </summary>
|
||||
private ManualResetEvent m_finishedProcessingAfterStop = new ManualResetEvent(false);
|
||||
|
||||
public JobEngine()
|
||||
{
|
||||
RequestProcessTimeoutOnStop = 5000;
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug jobengine",
|
||||
"debug jobengine <start|stop|status>",
|
||||
"Start, stop or get status of the job engine.",
|
||||
"If stopped then all jobs are processed immediately.",
|
||||
HandleControlCommand);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (IsRunning)
|
||||
return;
|
||||
|
||||
IsRunning = true;
|
||||
|
||||
m_finishedProcessingAfterStop.Reset();
|
||||
|
||||
m_requestQueue = new BlockingCollection<Job>(new ConcurrentQueue<Job>(), 5000);
|
||||
|
||||
m_requestsWaitingStat =
|
||||
new Stat(
|
||||
"JobsWaiting",
|
||||
"Number of jobs waiting for processing.",
|
||||
"",
|
||||
"",
|
||||
"server",
|
||||
"jobengine",
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.None,
|
||||
stat => stat.Value = m_requestQueue.Count,
|
||||
StatVerbosity.Debug);
|
||||
|
||||
StatsManager.RegisterStat(m_requestsWaitingStat);
|
||||
|
||||
Watchdog.StartThread(
|
||||
ProcessRequests,
|
||||
"JobEngineThread",
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
int.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!IsRunning)
|
||||
return;
|
||||
|
||||
IsRunning = false;
|
||||
|
||||
int requestsLeft = m_requestQueue.Count;
|
||||
|
||||
if (requestsLeft <= 0)
|
||||
{
|
||||
m_cancelSource.Cancel();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.InfoFormat("[JOB ENGINE]: Waiting to write {0} events after stop.", requestsLeft);
|
||||
|
||||
while (requestsLeft > 0)
|
||||
{
|
||||
if (!m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop))
|
||||
{
|
||||
// After timeout no events have been written
|
||||
if (requestsLeft == m_requestQueue.Count)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[JOB ENGINE]: No requests processed after {0} ms wait. Discarding remaining {1} requests",
|
||||
RequestProcessTimeoutOnStop, requestsLeft);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
requestsLeft = m_requestQueue.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_cancelSource.Dispose();
|
||||
StatsManager.DeregisterStat(m_requestsWaitingStat);
|
||||
m_requestsWaitingStat = null;
|
||||
m_requestQueue = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool QueueRequest(string name, WaitCallback req, object o)
|
||||
{
|
||||
if (LogLevel >= 1)
|
||||
m_log.DebugFormat("[JOB ENGINE]: Queued job {0}", name);
|
||||
|
||||
if (m_requestQueue.Count < m_requestQueue.BoundedCapacity)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[OUTGOING QUEUE REFILL ENGINE]: Adding request for categories {0} for {1} in {2}",
|
||||
// categories, client.AgentID, m_udpServer.Scene.Name);
|
||||
|
||||
m_requestQueue.Add(new Job(name, req, o));
|
||||
|
||||
if (!m_warnOverMaxQueue)
|
||||
m_warnOverMaxQueue = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_warnOverMaxQueue)
|
||||
{
|
||||
// m_log.WarnFormat(
|
||||
// "[JOB ENGINE]: Request queue at maximum capacity, not recording request from {0} in {1}",
|
||||
// client.AgentID, m_udpServer.Scene.Name);
|
||||
|
||||
m_log.WarnFormat("[JOB ENGINE]: Request queue at maximum capacity, not recording job");
|
||||
|
||||
m_warnOverMaxQueue = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessRequests()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (IsRunning || m_requestQueue.Count > 0)
|
||||
{
|
||||
m_currentJob = m_requestQueue.Take(m_cancelSource.Token);
|
||||
|
||||
// QueueEmpty callback = req.Client.OnQueueEmpty;
|
||||
//
|
||||
// if (callback != null)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// callback(req.Categories);
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// m_log.Error("[OUTGOING QUEUE REFILL ENGINE]: ProcessRequests(" + req.Categories + ") threw an exception: " + e.Message, e);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (LogLevel >= 1)
|
||||
m_log.DebugFormat("[JOB ENGINE]: Processing job {0}", m_currentJob.Name);
|
||||
|
||||
m_currentJob.Callback.Invoke(m_currentJob.O);
|
||||
|
||||
if (LogLevel >= 1)
|
||||
m_log.DebugFormat("[JOB ENGINE]: Processed job {0}", m_currentJob.Name);
|
||||
|
||||
m_currentJob = null;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
|
||||
m_finishedProcessingAfterStop.Set();
|
||||
}
|
||||
|
||||
private void HandleControlCommand(string module, string[] args)
|
||||
{
|
||||
// if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
// return;
|
||||
|
||||
if (args.Length < 3)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug jobengine <stop|start|status|loglevel>");
|
||||
return;
|
||||
}
|
||||
|
||||
string subCommand = args[2];
|
||||
|
||||
if (subCommand == "stop")
|
||||
{
|
||||
Stop();
|
||||
MainConsole.Instance.OutputFormat("Stopped job engine.");
|
||||
}
|
||||
else if (subCommand == "start")
|
||||
{
|
||||
Start();
|
||||
MainConsole.Instance.OutputFormat("Started job engine.");
|
||||
}
|
||||
else if (subCommand == "status")
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Job engine running: {0}", IsRunning);
|
||||
MainConsole.Instance.OutputFormat("Current job {0}", m_currentJob != null ? m_currentJob.Name : "none");
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Jobs waiting: {0}", IsRunning ? m_requestQueue.Count.ToString() : "n/a");
|
||||
MainConsole.Instance.OutputFormat("Log Level: {0}", LogLevel);
|
||||
}
|
||||
|
||||
else if (subCommand == "loglevel")
|
||||
{
|
||||
// int logLevel;
|
||||
int logLevel = int.Parse(args[3]);
|
||||
// if (ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out logLevel))
|
||||
// {
|
||||
LogLevel = logLevel;
|
||||
MainConsole.Instance.OutputFormat("Set log level to {0}", LogLevel);
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Unrecognized job engine subcommand {0}", subCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,8 @@ namespace OpenSim.Framework.Monitoring
|
||||
foreach (char c in DisallowedShortNameCharacters)
|
||||
{
|
||||
if (shortName.IndexOf(c) != -1)
|
||||
throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
|
||||
shortName = shortName.Replace(c, '#');
|
||||
// throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
|
||||
}
|
||||
|
||||
ShortName = shortName;
|
||||
|
||||
@@ -133,6 +133,8 @@ namespace OpenSim.Framework.Monitoring
|
||||
/// /summary>
|
||||
public static event Action<ThreadWatchdogInfo> OnWatchdogTimeout;
|
||||
|
||||
public static JobEngine JobEngine { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this watchdog active?
|
||||
/// </summary>
|
||||
@@ -173,6 +175,7 @@ namespace OpenSim.Framework.Monitoring
|
||||
|
||||
static Watchdog()
|
||||
{
|
||||
JobEngine = new JobEngine();
|
||||
m_threads = new Dictionary<int, ThreadWatchdogInfo>();
|
||||
m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
|
||||
m_watchdogTimer.AutoReset = false;
|
||||
@@ -449,5 +452,20 @@ namespace OpenSim.Framework.Monitoring
|
||||
|
||||
m_watchdogTimer.Start();
|
||||
}
|
||||
|
||||
public static void RunWhenPossible(string jobType, WaitCallback callback, string name, object obj, bool log = false)
|
||||
{
|
||||
if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
|
||||
{
|
||||
Culture.SetCurrentCulture();
|
||||
callback(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (JobEngine.IsRunning)
|
||||
JobEngine.QueueRequest(name, callback, obj);
|
||||
else
|
||||
RunInThread(callback, name, obj, log);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,8 +268,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
public string SeedCapRequest(string request, string path, string param,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
|
||||
// m_log.DebugFormat(
|
||||
// "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
|
||||
|
||||
if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
|
||||
{
|
||||
|
||||
@@ -76,6 +76,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// or removed, this number must also change</summary>
|
||||
const int THROTTLE_CATEGORY_COUNT = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
|
||||
/// </summary>
|
||||
/// <remarks>Any level above 0 will turn on logging.</remarks>
|
||||
public int DebugDataOutLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
|
||||
/// </summary>
|
||||
/// <remarks>Any level above 0 will turn on logging.</remarks>
|
||||
public int ThrottleDebugLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_throttleDebugLevel;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
m_throttleDebugLevel = value;
|
||||
m_throttleClient.DebugLevel = m_throttleDebugLevel;
|
||||
m_throttleCategory.DebugLevel = m_throttleDebugLevel;
|
||||
foreach (TokenBucket tb in m_throttleCategories)
|
||||
tb.DebugLevel = m_throttleDebugLevel;
|
||||
}
|
||||
}
|
||||
private int m_throttleDebugLevel;
|
||||
|
||||
/// <summary>Fired when updated networking stats are produced for this client</summary>
|
||||
public event PacketStats OnPacketStats;
|
||||
/// <summary>Fired when the queue for a packet category is empty. This event can be
|
||||
@@ -201,9 +229,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_maxRTO = maxRTO;
|
||||
|
||||
// Create a token bucket throttle for this client that has the scene token bucket as a parent
|
||||
m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled);
|
||||
m_throttleClient
|
||||
= new AdaptiveTokenBucket(
|
||||
string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name),
|
||||
parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled);
|
||||
|
||||
// Create a token bucket throttle for the total category with the client bucket as a throttle
|
||||
m_throttleCategory = new TokenBucket(m_throttleClient, 0);
|
||||
m_throttleCategory
|
||||
= new TokenBucket(
|
||||
string.Format("total throttle for {0} in {1}", AgentID, server.Scene.Name),
|
||||
m_throttleClient, 0);
|
||||
|
||||
// Create an array of token buckets for this clients different throttle categories
|
||||
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
||||
|
||||
@@ -215,8 +251,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
// Initialize the packet outboxes, where packets sit while they are waiting for tokens
|
||||
m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
|
||||
|
||||
// Initialize the token buckets that control the throttling for each category
|
||||
m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
|
||||
m_throttleCategories[i]
|
||||
= new TokenBucket(
|
||||
string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name),
|
||||
m_throttleCategory, rates.GetRate(type));
|
||||
}
|
||||
|
||||
// Default the retransmission timeout to one second
|
||||
@@ -279,6 +319,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the total number of pakcets queued for this client.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetTotalPacketsQueuedCount()
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (int i = 0; i <= (int)ThrottleOutPacketType.Asset; i++)
|
||||
total += m_packetOutboxes[i].Count;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of packets queued for the given throttle type.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name="throttleType"></param>
|
||||
public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType)
|
||||
{
|
||||
if ((int)throttleType > 0)
|
||||
return m_packetOutboxes[(int)throttleType].Count;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return statistics information about client packet queues.
|
||||
/// </summary>
|
||||
@@ -365,8 +432,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
texture = (int)((1 - m_cannibalrate) * texture);
|
||||
|
||||
//int total = resend + land + wind + cloud + task + texture + asset;
|
||||
//m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
|
||||
// AgentID, resend, land, wind, cloud, task, texture, asset, total);
|
||||
|
||||
if (ThrottleDebugLevel > 0)
|
||||
{
|
||||
long total = resend + land + wind + cloud + task + texture + asset;
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
|
||||
AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
|
||||
}
|
||||
|
||||
// Update the token buckets with new throttle values
|
||||
TokenBucket bucket;
|
||||
|
||||
@@ -34,7 +34,6 @@ using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using NDesk.Options;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse.Packets;
|
||||
using OpenSim.Framework;
|
||||
@@ -222,6 +221,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// </summary>
|
||||
public int DefaultClientPacketDebugLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set then all inbound agent updates are discarded. For debugging purposes.
|
||||
/// discard agent update.
|
||||
/// </summary>
|
||||
public bool DiscardInboundAgentUpdates { get; set; }
|
||||
|
||||
/// <summary>The measured resolution of Environment.TickCount</summary>
|
||||
public readonly float TickCountResolution;
|
||||
|
||||
@@ -238,10 +243,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <summary>Incoming packets that are awaiting handling</summary>
|
||||
private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
|
||||
|
||||
/// <summary></summary>
|
||||
//private UDPClientCollection m_clients = new UDPClientCollection();
|
||||
/// <summary>Bandwidth throttle for this UDP server</summary>
|
||||
protected TokenBucket m_throttle;
|
||||
public TokenBucket Throttle { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum total drip rate allowed to all clients.
|
||||
/// </summary>
|
||||
public long MaxTotalDripRate { get { return Throttle.RequestedDripRate; } }
|
||||
|
||||
/// <summary>Bandwidth throttle rates for this UDP server</summary>
|
||||
public ThrottleRates ThrottleRates { get; private set; }
|
||||
@@ -434,7 +442,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
#endregion BinaryStats
|
||||
|
||||
m_throttle = new TokenBucket(null, sceneThrottleBps);
|
||||
// FIXME: Can't add info here because don't know scene yet.
|
||||
// m_throttle
|
||||
// = new TokenBucket(
|
||||
// string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps);
|
||||
|
||||
Throttle = new TokenBucket("server throttle bucket", null, sceneThrottleBps);
|
||||
|
||||
ThrottleRates = new ThrottleRates(configSource);
|
||||
|
||||
if (usePools)
|
||||
@@ -452,7 +466,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_elapsedMSSinceLastStatReport = Environment.TickCount;
|
||||
}
|
||||
|
||||
private void StartInbound()
|
||||
public void StartInbound()
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
|
||||
@@ -471,7 +485,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
private new void StartOutbound()
|
||||
public override void StartOutbound()
|
||||
{
|
||||
m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
|
||||
|
||||
@@ -495,7 +509,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
OqrEngine.Stop();
|
||||
}
|
||||
|
||||
protected override bool EnablePools()
|
||||
public override bool EnablePools()
|
||||
{
|
||||
if (!UsePools)
|
||||
{
|
||||
@@ -509,7 +523,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool DisablePools()
|
||||
public override bool DisablePools()
|
||||
{
|
||||
if (UsePools)
|
||||
{
|
||||
@@ -529,7 +543,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene
|
||||
/// stats.
|
||||
/// </summary>
|
||||
private void EnablePoolStats()
|
||||
protected internal void EnablePoolStats()
|
||||
{
|
||||
m_poolCountStat
|
||||
= new Stat(
|
||||
@@ -563,7 +577,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <summary>
|
||||
/// Disables pool stats.
|
||||
/// </summary>
|
||||
private void DisablePoolStats()
|
||||
protected internal void DisablePoolStats()
|
||||
{
|
||||
StatsManager.DeregisterStat(m_poolCountStat);
|
||||
m_poolCountStat = null;
|
||||
@@ -677,312 +691,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
StatType.Pull,
|
||||
stat => stat.Value = PacketPool.Instance.BlocksPooled,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"OutgoingPacketsQueuedCount",
|
||||
"Packets queued for outgoing send",
|
||||
"Number of queued outgoing packets across all connections",
|
||||
"",
|
||||
"clientstack",
|
||||
Scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = GetTotalQueuedOutgoingPackets(),
|
||||
StatVerbosity.Info));
|
||||
|
||||
// We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
|
||||
// scene name
|
||||
if (UsePools)
|
||||
EnablePoolStats();
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug", false, "debug lludp packet",
|
||||
"debug lludp packet [--default | --all] <level> [<avatar-first-name> <avatar-last-name>]",
|
||||
"Turn on packet debugging",
|
||||
"If level > 255 then all incoming and outgoing packets are logged.\n"
|
||||
+ "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
|
||||
+ "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
|
||||
+ "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
|
||||
+ "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
|
||||
+ "If level <= 0 then no packets are logged.\n"
|
||||
+ "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
|
||||
+ "If --all is specified then the level becomes the default logging level for all current and subsequent agents.\n"
|
||||
+ "In these cases, you cannot also specify an avatar name.\n"
|
||||
+ "If an avatar name is given then only packets from that avatar are logged.",
|
||||
HandlePacketCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug", false, "debug lludp drop",
|
||||
"debug lludp drop <in|out> <add|remove> <packet-name>",
|
||||
"Drop all in or outbound packets that match the given name",
|
||||
"For test purposes.",
|
||||
HandleDropCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp start",
|
||||
"debug lludp start <in|out|all>",
|
||||
"Control LLUDP packet processing.",
|
||||
"No effect if packet processing has already started.\n"
|
||||
+ "in - start inbound processing.\n"
|
||||
+ "out - start outbound processing.\n"
|
||||
+ "all - start in and outbound processing.\n",
|
||||
HandleStartCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp stop",
|
||||
"debug lludp stop <in|out|all>",
|
||||
"Stop LLUDP packet processing.",
|
||||
"No effect if packet processing has already stopped.\n"
|
||||
+ "in - stop inbound processing.\n"
|
||||
+ "out - stop outbound processing.\n"
|
||||
+ "all - stop in and outbound processing.\n",
|
||||
HandleStopCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp pool",
|
||||
"debug lludp pool <on|off>",
|
||||
"Turn object pooling within the lludp component on or off.",
|
||||
HandlePoolCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp status",
|
||||
"debug lludp status",
|
||||
"Return status of LLUDP packet processing.",
|
||||
HandleStatusCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp toggle agentupdate",
|
||||
"debug lludp toggle agentupdate",
|
||||
"Toggle whether agentupdate packets are processed or simply discarded.",
|
||||
HandleAgentUpdateCommand);
|
||||
}
|
||||
|
||||
private void HandlePacketCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
|
||||
return;
|
||||
|
||||
bool setAsDefaultLevel = false;
|
||||
bool setAll = false;
|
||||
OptionSet optionSet = new OptionSet()
|
||||
.Add("default", o => setAsDefaultLevel = (o != null))
|
||||
.Add("all", o => setAll = (o != null));
|
||||
List<string> filteredArgs = optionSet.Parse(args);
|
||||
|
||||
string name = null;
|
||||
|
||||
if (filteredArgs.Count == 6)
|
||||
{
|
||||
if (!(setAsDefaultLevel || setAll))
|
||||
{
|
||||
name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default/all logging level");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredArgs.Count > 3)
|
||||
{
|
||||
int newDebug;
|
||||
if (int.TryParse(filteredArgs[3], out newDebug))
|
||||
{
|
||||
if (setAsDefaultLevel || setAll)
|
||||
{
|
||||
DefaultClientPacketDebugLevel = newDebug;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug for {0} clients set to {1} in {2}",
|
||||
(setAll ? "all" : "future"), DefaultClientPacketDebugLevel, Scene.Name);
|
||||
|
||||
if (setAll)
|
||||
{
|
||||
Scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug for {0} ({1}) set to {2} in {3}",
|
||||
sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, Scene.Name);
|
||||
|
||||
sp.ControllingClient.DebugPacketLevel = newDebug;
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
if (name == null || sp.Name == name)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug for {0} ({1}) set to {2} in {3}",
|
||||
sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, Scene.Name);
|
||||
|
||||
sp.ControllingClient.DebugPacketLevel = newDebug;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp packet [--default | --all] 0..255 [<first-name> <last-name>]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDropCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 6)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp drop <in|out> <add|remove> <packet-name>");
|
||||
return;
|
||||
}
|
||||
|
||||
string direction = args[3];
|
||||
string subCommand = args[4];
|
||||
string packetName = args[5];
|
||||
|
||||
if (subCommand == "add")
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Adding packet {0} to {1} drop list for all connections in {2}", direction, packetName, Scene.Name);
|
||||
|
||||
Scene.ForEachScenePresence(
|
||||
sp =>
|
||||
{
|
||||
LLClientView llcv = (LLClientView)sp.ControllingClient;
|
||||
|
||||
if (direction == "in")
|
||||
llcv.AddInPacketToDropSet(packetName);
|
||||
else if (direction == "out")
|
||||
llcv.AddOutPacketToDropSet(packetName);
|
||||
}
|
||||
);
|
||||
}
|
||||
else if (subCommand == "remove")
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Removing packet {0} from {1} drop list for all connections in {2}", direction, packetName, Scene.Name);
|
||||
|
||||
Scene.ForEachScenePresence(
|
||||
sp =>
|
||||
{
|
||||
LLClientView llcv = (LLClientView)sp.ControllingClient;
|
||||
|
||||
if (direction == "in")
|
||||
llcv.RemoveInPacketFromDropSet(packetName);
|
||||
else if (direction == "out")
|
||||
llcv.RemoveOutPacketFromDropSet(packetName);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStartCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
|
||||
return;
|
||||
}
|
||||
|
||||
string subCommand = args[3];
|
||||
|
||||
if (subCommand == "in" || subCommand == "all")
|
||||
StartInbound();
|
||||
|
||||
if (subCommand == "out" || subCommand == "all")
|
||||
StartOutbound();
|
||||
}
|
||||
|
||||
private void HandleStopCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
|
||||
return;
|
||||
}
|
||||
|
||||
string subCommand = args[3];
|
||||
|
||||
if (subCommand == "in" || subCommand == "all")
|
||||
StopInbound();
|
||||
|
||||
if (subCommand == "out" || subCommand == "all")
|
||||
StopOutbound();
|
||||
}
|
||||
|
||||
private void HandlePoolCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
|
||||
return;
|
||||
}
|
||||
|
||||
string enabled = args[3];
|
||||
|
||||
if (enabled == "on")
|
||||
{
|
||||
if (EnablePools())
|
||||
{
|
||||
EnablePoolStats();
|
||||
MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", Scene.Name);
|
||||
}
|
||||
}
|
||||
else if (enabled == "off")
|
||||
{
|
||||
if (DisablePools())
|
||||
{
|
||||
DisablePoolStats();
|
||||
MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", Scene.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
|
||||
}
|
||||
}
|
||||
|
||||
bool m_discardAgentUpdates;
|
||||
|
||||
private void HandleAgentUpdateCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
|
||||
return;
|
||||
|
||||
m_discardAgentUpdates = !m_discardAgentUpdates;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, Scene.Name);
|
||||
}
|
||||
|
||||
private void HandleStatusCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
|
||||
return;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"IN LLUDP packet processing for {0} is {1}", Scene.Name, IsRunningInbound ? "enabled" : "disabled");
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"OUT LLUDP packet processing for {0} is {1}", Scene.Name, IsRunningOutbound ? "enabled" : "disabled");
|
||||
|
||||
MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", Scene.Name, UsePools ? "on" : "off");
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
|
||||
LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this);
|
||||
commands.Register();
|
||||
}
|
||||
|
||||
public bool HandlesRegion(Location x)
|
||||
@@ -990,6 +719,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return x == m_location;
|
||||
}
|
||||
|
||||
public int GetTotalQueuedOutgoingPackets()
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
foreach (ScenePresence sp in Scene.GetScenePresences())
|
||||
{
|
||||
LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
|
||||
total += udpClient.GetTotalPacketsQueuedCount();
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
|
||||
// {
|
||||
// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
|
||||
@@ -1360,6 +1102,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// is 100% correct
|
||||
PacketsSentCount++;
|
||||
|
||||
if (udpClient.DebugDataOutLevel > 0)
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Sending packet #{0} (rel: {1}, res: {2}) to {3} from {4}",
|
||||
outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name);
|
||||
|
||||
// Put the UDP payload on the wire
|
||||
AsyncBeginSend(buffer);
|
||||
|
||||
@@ -1604,7 +1351,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
if (packet.Type == PacketType.AgentUpdate)
|
||||
{
|
||||
if (m_discardAgentUpdates)
|
||||
if (DiscardInboundAgentUpdates)
|
||||
return;
|
||||
|
||||
((LLClientView)client).TotalAgentUpdates++;
|
||||
@@ -2012,7 +1759,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
if (!Scene.TryGetClient(agentID, out client))
|
||||
{
|
||||
LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
|
||||
LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
|
||||
|
||||
client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
|
||||
client.OnLogout += LogoutHandler;
|
||||
@@ -2055,6 +1802,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
private void IncomingPacketHandler()
|
||||
{
|
||||
Thread.CurrentThread.Priority = ThreadPriority.Highest;
|
||||
|
||||
// Set this culture for the thread that incoming packets are received
|
||||
// on to en-US to avoid number parsing issues
|
||||
Culture.SetCurrentCulture();
|
||||
@@ -2100,6 +1849,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
private void OutgoingPacketHandler()
|
||||
{
|
||||
Thread.CurrentThread.Priority = ThreadPriority.Highest;
|
||||
|
||||
// Set this culture for the thread that outgoing packets are sent
|
||||
// on to en-US to avoid number parsing issues
|
||||
Culture.SetCurrentCulture();
|
||||
|
||||
657
OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
Normal file
657
OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
Normal file
@@ -0,0 +1,657 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using NDesk.Options;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
public class LLUDPServerCommands
|
||||
{
|
||||
private ICommandConsole m_console;
|
||||
private LLUDPServer m_udpServer;
|
||||
|
||||
public LLUDPServerCommands(ICommandConsole console, LLUDPServer udpServer)
|
||||
{
|
||||
m_console = console;
|
||||
m_udpServer = udpServer;
|
||||
}
|
||||
|
||||
public void Register()
|
||||
{
|
||||
m_console.Commands.AddCommand(
|
||||
"Comms", false, "show server throttles",
|
||||
"show server throttles",
|
||||
"Show information about server throttles",
|
||||
HandleShowServerThrottlesCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug", false, "debug lludp packet",
|
||||
"debug lludp packet [--default | --all] <level> [<avatar-first-name> <avatar-last-name>]",
|
||||
"Turn on packet debugging. This logs information when the client stack hands a processed packet off to downstream code or when upstream code first requests that a certain packet be sent.",
|
||||
"If level > 255 then all incoming and outgoing packets are logged.\n"
|
||||
+ "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
|
||||
+ "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
|
||||
+ "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
|
||||
+ "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
|
||||
+ "If level <= 0 then no packets are logged.\n"
|
||||
+ "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
|
||||
+ "If --all is specified then the level becomes the default logging level for all current and subsequent agents.\n"
|
||||
+ "In these cases, you cannot also specify an avatar name.\n"
|
||||
+ "If an avatar name is given then only packets from that avatar are logged.",
|
||||
HandlePacketCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug", false, "debug lludp data out",
|
||||
"debug lludp data out <level> <avatar-first-name> <avatar-last-name>\"",
|
||||
"Turn on debugging for final outgoing data to the given user's client.",
|
||||
"This operates at a much lower level than the packet command and prints out available details when the data is actually sent.\n"
|
||||
+ "If level > 0 then information about all outgoing UDP data for this avatar is logged.\n"
|
||||
+ "If level <= 0 then no information about outgoing UDP data for this avatar is logged.",
|
||||
HandleDataCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug", false, "debug lludp drop",
|
||||
"debug lludp drop <in|out> <add|remove> <packet-name>",
|
||||
"Drop all in or outbound packets that match the given name",
|
||||
"For test purposes.",
|
||||
HandleDropCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp start",
|
||||
"debug lludp start <in|out|all>",
|
||||
"Control LLUDP packet processing.",
|
||||
"No effect if packet processing has already started.\n"
|
||||
+ "in - start inbound processing.\n"
|
||||
+ "out - start outbound processing.\n"
|
||||
+ "all - start in and outbound processing.\n",
|
||||
HandleStartCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp stop",
|
||||
"debug lludp stop <in|out|all>",
|
||||
"Stop LLUDP packet processing.",
|
||||
"No effect if packet processing has already stopped.\n"
|
||||
+ "in - stop inbound processing.\n"
|
||||
+ "out - stop outbound processing.\n"
|
||||
+ "all - stop in and outbound processing.\n",
|
||||
HandleStopCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp pool",
|
||||
"debug lludp pool <on|off>",
|
||||
"Turn object pooling within the lludp component on or off.",
|
||||
HandlePoolCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp status",
|
||||
"debug lludp status",
|
||||
"Return status of LLUDP packet processing.",
|
||||
HandleStatusCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp throttle log",
|
||||
"debug lludp throttle log <level> [<avatar-first-name> <avatar-last-name>]",
|
||||
"Change debug logging level for throttles.",
|
||||
"If level >= 0 then throttle debug logging is performed.\n"
|
||||
+ "If level <= 0 then no throttle debug logging is performed.",
|
||||
HandleThrottleCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp throttle get",
|
||||
"debug lludp throttle get [<avatar-first-name> <avatar-last-name>]",
|
||||
"Return debug settings for throttles.",
|
||||
HandleThrottleGetCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp throttle set",
|
||||
"debug lludp throttle set <param> <value> [<avatar-first-name> <avatar-last-name>]",
|
||||
"Set a throttle parameter for the given client.",
|
||||
"Only current setting is 'adaptive' which must be 'true' or 'false'",
|
||||
HandleThrottleSetCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp set",
|
||||
"debug lludp set <param> <value>",
|
||||
"Set a parameter for the server.",
|
||||
"Only current setting is 'scene-throttle-max' which sets the current max cumulative kbps provided for this scene to clients",
|
||||
HandleSetCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp toggle agentupdate",
|
||||
"debug lludp toggle agentupdate",
|
||||
"Toggle whether agentupdate packets are processed or simply discarded.",
|
||||
HandleAgentUpdateCommand);
|
||||
}
|
||||
|
||||
private void HandleShowServerThrottlesCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
m_console.OutputFormat("Throttles for {0}", m_udpServer.Scene.Name);
|
||||
ConsoleDisplayList cdl = new ConsoleDisplayList();
|
||||
cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled);
|
||||
cdl.AddRow(
|
||||
"Max scene throttle",
|
||||
m_udpServer.MaxTotalDripRate != 0 ? string.Format("{0} kbps", m_udpServer.MaxTotalDripRate * 8 / 1000) : "unset");
|
||||
|
||||
m_console.Output(cdl.ToString());
|
||||
|
||||
m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer));
|
||||
}
|
||||
|
||||
private string GetServerThrottlesReport(LLUDPServer udpServer)
|
||||
{
|
||||
StringBuilder report = new StringBuilder();
|
||||
|
||||
report.AppendFormat(
|
||||
"{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
|
||||
"Total",
|
||||
"Resend",
|
||||
"Land",
|
||||
"Wind",
|
||||
"Cloud",
|
||||
"Task",
|
||||
"Texture",
|
||||
"Asset");
|
||||
|
||||
report.AppendFormat(
|
||||
"{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
|
||||
"kb/s",
|
||||
"kb/s",
|
||||
"kb/s",
|
||||
"kb/s",
|
||||
"kb/s",
|
||||
"kb/s",
|
||||
"kb/s",
|
||||
"kb/s");
|
||||
|
||||
ThrottleRates throttleRates = udpServer.ThrottleRates;
|
||||
report.AppendFormat(
|
||||
"{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}",
|
||||
(throttleRates.Total * 8) / 1000,
|
||||
(throttleRates.Resend * 8) / 1000,
|
||||
(throttleRates.Land * 8) / 1000,
|
||||
(throttleRates.Wind * 8) / 1000,
|
||||
(throttleRates.Cloud * 8) / 1000,
|
||||
(throttleRates.Task * 8) / 1000,
|
||||
(throttleRates.Texture * 8) / 1000,
|
||||
(throttleRates.Asset * 8) / 1000);
|
||||
|
||||
return report.ToString();
|
||||
}
|
||||
|
||||
protected string GetColumnEntry(string entry, int maxLength, int columnPadding)
|
||||
{
|
||||
return string.Format(
|
||||
"{0,-" + maxLength + "}{1,-" + columnPadding + "}",
|
||||
entry.Length > maxLength ? entry.Substring(0, maxLength) : entry,
|
||||
"");
|
||||
}
|
||||
|
||||
private void HandleDataCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 7)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Usage: debug lludp data out <true|false> <avatar-first-name> <avatar-last-name>");
|
||||
return;
|
||||
}
|
||||
|
||||
int level;
|
||||
if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
|
||||
return;
|
||||
|
||||
string firstName = args[5];
|
||||
string lastName = args[6];
|
||||
|
||||
m_udpServer.Scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
if (sp.Firstname == firstName && sp.Lastname == lastName)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Data debug for {0} ({1}) set to {2} in {3}",
|
||||
sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name);
|
||||
|
||||
((LLClientView)sp.ControllingClient).UDPClient.DebugDataOutLevel = level;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleThrottleCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
bool all = args.Length == 5;
|
||||
bool one = args.Length == 7;
|
||||
|
||||
if (!all && !one)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Usage: debug lludp throttle log <level> [<avatar-first-name> <avatar-last-name>]");
|
||||
return;
|
||||
}
|
||||
|
||||
int level;
|
||||
if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out level))
|
||||
return;
|
||||
|
||||
string firstName = null;
|
||||
string lastName = null;
|
||||
|
||||
if (one)
|
||||
{
|
||||
firstName = args[5];
|
||||
lastName = args[6];
|
||||
}
|
||||
|
||||
m_udpServer.Scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Throttle log level for {0} ({1}) set to {2} in {3}",
|
||||
sp.Name, sp.IsChildAgent ? "child" : "root", level, m_udpServer.Scene.Name);
|
||||
|
||||
((LLClientView)sp.ControllingClient).UDPClient.ThrottleDebugLevel = level;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleThrottleSetCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
bool all = args.Length == 6;
|
||||
bool one = args.Length == 8;
|
||||
|
||||
if (!all && !one)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Usage: debug lludp throttle set <param> <value> [<avatar-first-name> <avatar-last-name>]");
|
||||
return;
|
||||
}
|
||||
|
||||
string param = args[4];
|
||||
string rawValue = args[5];
|
||||
|
||||
string firstName = null;
|
||||
string lastName = null;
|
||||
|
||||
if (one)
|
||||
{
|
||||
firstName = args[6];
|
||||
lastName = args[7];
|
||||
}
|
||||
|
||||
if (param == "adaptive")
|
||||
{
|
||||
bool newValue;
|
||||
if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
|
||||
return;
|
||||
|
||||
m_udpServer.Scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Setting param {0} to {1} for {2} ({3}) in {4}",
|
||||
param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
|
||||
|
||||
LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
|
||||
udpClient.FlowThrottle.Enabled = newValue;
|
||||
// udpClient.FlowThrottle.MaxDripRate = 0;
|
||||
// udpClient.FlowThrottle.AdjustedDripRate = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleThrottleGetCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
bool all = args.Length == 4;
|
||||
bool one = args.Length == 6;
|
||||
|
||||
if (!all && !one)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Usage: debug lludp throttle get [<avatar-first-name> <avatar-last-name>]");
|
||||
return;
|
||||
}
|
||||
|
||||
string firstName = null;
|
||||
string lastName = null;
|
||||
|
||||
if (one)
|
||||
{
|
||||
firstName = args[4];
|
||||
lastName = args[5];
|
||||
}
|
||||
|
||||
m_udpServer.Scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Status for {0} ({1}) in {2}",
|
||||
sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
|
||||
|
||||
LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
|
||||
MainConsole.Instance.OutputFormat("Adaptive throttle: {0}", udpClient.FlowThrottle.Enabled);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void HandleSetCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 5)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>");
|
||||
return;
|
||||
}
|
||||
|
||||
string param = args[3];
|
||||
string rawValue = args[4];
|
||||
|
||||
int newValue;
|
||||
|
||||
if (param == "scene-throttle-max")
|
||||
{
|
||||
if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
|
||||
return;
|
||||
|
||||
m_udpServer.Throttle.RequestedDripRate = newValue * 1000 / 8;
|
||||
}
|
||||
|
||||
m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name);
|
||||
}
|
||||
|
||||
private void HandlePacketCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
bool setAsDefaultLevel = false;
|
||||
bool setAll = false;
|
||||
OptionSet optionSet = new OptionSet()
|
||||
.Add("default", o => setAsDefaultLevel = (o != null))
|
||||
.Add("all", o => setAll = (o != null));
|
||||
List<string> filteredArgs = optionSet.Parse(args);
|
||||
|
||||
string name = null;
|
||||
|
||||
if (filteredArgs.Count == 6)
|
||||
{
|
||||
if (!(setAsDefaultLevel || setAll))
|
||||
{
|
||||
name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default/all logging level");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredArgs.Count > 3)
|
||||
{
|
||||
int newDebug;
|
||||
if (int.TryParse(filteredArgs[3], out newDebug))
|
||||
{
|
||||
if (setAsDefaultLevel || setAll)
|
||||
{
|
||||
m_udpServer.DefaultClientPacketDebugLevel = newDebug;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug for {0} clients set to {1} in {2}",
|
||||
(setAll ? "all" : "future"), m_udpServer.DefaultClientPacketDebugLevel, m_udpServer.Scene.Name);
|
||||
|
||||
if (setAll)
|
||||
{
|
||||
m_udpServer.Scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug for {0} ({1}) set to {2} in {3}",
|
||||
sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name);
|
||||
|
||||
sp.ControllingClient.DebugPacketLevel = newDebug;
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_udpServer.Scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
if (name == null || sp.Name == name)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug for {0} ({1}) set to {2} in {3}",
|
||||
sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_udpServer.Scene.Name);
|
||||
|
||||
sp.ControllingClient.DebugPacketLevel = newDebug;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp packet [--default | --all] 0..255 [<first-name> <last-name>]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDropCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 6)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp drop <in|out> <add|remove> <packet-name>");
|
||||
return;
|
||||
}
|
||||
|
||||
string direction = args[3];
|
||||
string subCommand = args[4];
|
||||
string packetName = args[5];
|
||||
|
||||
if (subCommand == "add")
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Adding packet {0} to {1} drop list for all connections in {2}",
|
||||
direction, packetName, m_udpServer.Scene.Name);
|
||||
|
||||
m_udpServer.Scene.ForEachScenePresence(
|
||||
sp =>
|
||||
{
|
||||
LLClientView llcv = (LLClientView)sp.ControllingClient;
|
||||
|
||||
if (direction == "in")
|
||||
llcv.AddInPacketToDropSet(packetName);
|
||||
else if (direction == "out")
|
||||
llcv.AddOutPacketToDropSet(packetName);
|
||||
}
|
||||
);
|
||||
}
|
||||
else if (subCommand == "remove")
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Removing packet {0} from {1} drop list for all connections in {2}",
|
||||
direction, packetName, m_udpServer.Scene.Name);
|
||||
|
||||
m_udpServer.Scene.ForEachScenePresence(
|
||||
sp =>
|
||||
{
|
||||
LLClientView llcv = (LLClientView)sp.ControllingClient;
|
||||
|
||||
if (direction == "in")
|
||||
llcv.RemoveInPacketFromDropSet(packetName);
|
||||
else if (direction == "out")
|
||||
llcv.RemoveOutPacketFromDropSet(packetName);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStartCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
|
||||
return;
|
||||
}
|
||||
|
||||
string subCommand = args[3];
|
||||
|
||||
if (subCommand == "in" || subCommand == "all")
|
||||
m_udpServer.StartInbound();
|
||||
|
||||
if (subCommand == "out" || subCommand == "all")
|
||||
m_udpServer.StartOutbound();
|
||||
}
|
||||
|
||||
private void HandleStopCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
|
||||
return;
|
||||
}
|
||||
|
||||
string subCommand = args[3];
|
||||
|
||||
if (subCommand == "in" || subCommand == "all")
|
||||
m_udpServer.StopInbound();
|
||||
|
||||
if (subCommand == "out" || subCommand == "all")
|
||||
m_udpServer.StopOutbound();
|
||||
}
|
||||
|
||||
private void HandlePoolCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
|
||||
return;
|
||||
}
|
||||
|
||||
string enabled = args[3];
|
||||
|
||||
if (enabled == "on")
|
||||
{
|
||||
if (m_udpServer.EnablePools())
|
||||
{
|
||||
m_udpServer.EnablePoolStats();
|
||||
MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_udpServer.Scene.Name);
|
||||
}
|
||||
}
|
||||
else if (enabled == "off")
|
||||
{
|
||||
if (m_udpServer.DisablePools())
|
||||
{
|
||||
m_udpServer.DisablePoolStats();
|
||||
MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_udpServer.Scene.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleAgentUpdateCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
m_udpServer.DiscardInboundAgentUpdates = !m_udpServer.DiscardInboundAgentUpdates;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Discard AgentUpdates now {0} for {1}", m_udpServer.DiscardInboundAgentUpdates, m_udpServer.Scene.Name);
|
||||
}
|
||||
|
||||
private void HandleStatusCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
|
||||
return;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"IN LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningInbound ? "enabled" : "disabled");
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"OUT LLUDP packet processing for {0} is {1}", m_udpServer.Scene.Name, m_udpServer.IsRunningOutbound ? "enabled" : "disabled");
|
||||
|
||||
MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_udpServer.Scene.Name, m_udpServer.UsePools ? "on" : "off");
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug level for new clients is {0}", m_udpServer.DefaultClientPacketDebugLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ namespace OpenMetaverse
|
||||
/// manner (not throwing an exception when the remote side resets the
|
||||
/// connection). This call is ignored on Mono where the flag is not
|
||||
/// necessary</remarks>
|
||||
public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
|
||||
public virtual void StartInbound(int recvBufferSize, bool asyncPacketHandling)
|
||||
{
|
||||
m_asyncPacketHandling = asyncPacketHandling;
|
||||
|
||||
@@ -185,14 +185,14 @@ namespace OpenMetaverse
|
||||
/// <summary>
|
||||
/// Start outbound UDP packet handling.
|
||||
/// </summary>
|
||||
public void StartOutbound()
|
||||
public virtual void StartOutbound()
|
||||
{
|
||||
m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
|
||||
|
||||
IsRunningOutbound = true;
|
||||
}
|
||||
|
||||
public void StopInbound()
|
||||
public virtual void StopInbound()
|
||||
{
|
||||
if (IsRunningInbound)
|
||||
{
|
||||
@@ -203,14 +203,14 @@ namespace OpenMetaverse
|
||||
}
|
||||
}
|
||||
|
||||
public void StopOutbound()
|
||||
public virtual void StopOutbound()
|
||||
{
|
||||
m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
|
||||
|
||||
IsRunningOutbound = false;
|
||||
}
|
||||
|
||||
protected virtual bool EnablePools()
|
||||
public virtual bool EnablePools()
|
||||
{
|
||||
if (!UsePools)
|
||||
{
|
||||
@@ -224,7 +224,7 @@ namespace OpenMetaverse
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual bool DisablePools()
|
||||
public virtual bool DisablePools()
|
||||
{
|
||||
if (UsePools)
|
||||
{
|
||||
|
||||
@@ -217,6 +217,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
private void ProcessRequests()
|
||||
{
|
||||
Thread.CurrentThread.Priority = ThreadPriority.Highest;
|
||||
|
||||
try
|
||||
{
|
||||
while (IsRunning || m_requestQueue.Count > 0)
|
||||
|
||||
@@ -42,9 +42,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
public class TokenBucket
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static Int32 m_counter = 0;
|
||||
|
||||
// private Int32 m_identifier;
|
||||
|
||||
public string Identifier { get; private set; }
|
||||
|
||||
public int DebugLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of ticks (ms) per quantum, drip rate and max burst
|
||||
@@ -165,16 +166,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
/// <param name="identifier">Identifier for this token bucket</param>
|
||||
/// <param name="parent">Parent bucket if this is a child bucket, or
|
||||
/// null if this is a root bucket</param>
|
||||
/// <param name="maxBurst">Maximum size of the bucket in bytes, or
|
||||
/// zero if this bucket has no maximum capacity</param>
|
||||
/// <param name="dripRate">Rate that the bucket fills, in bytes per
|
||||
/// second. If zero, the bucket always remains full</param>
|
||||
public TokenBucket(TokenBucket parent, Int64 dripRate)
|
||||
public TokenBucket(string identifier, TokenBucket parent, Int64 dripRate)
|
||||
{
|
||||
// m_identifier = m_counter++;
|
||||
m_counter++;
|
||||
Identifier = identifier;
|
||||
|
||||
Parent = parent;
|
||||
RequestedDripRate = dripRate;
|
||||
@@ -301,7 +300,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// with no drip rate...
|
||||
if (DripRate == 0)
|
||||
{
|
||||
m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0");
|
||||
m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -321,7 +320,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
public class AdaptiveTokenBucket : TokenBucket
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// The minimum rate for flow control. Minimum drip rate is one
|
||||
@@ -338,10 +337,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
public Int64 MaxDripRate
|
||||
{
|
||||
get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
|
||||
protected set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
|
||||
set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
|
||||
}
|
||||
|
||||
public bool Enabled { get; private set; }
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
// <summary>
|
||||
//
|
||||
@@ -360,13 +359,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// <summary>
|
||||
//
|
||||
// </summary>
|
||||
public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate)
|
||||
public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 maxDripRate, bool enabled)
|
||||
: base(identifier, parent, maxDripRate)
|
||||
{
|
||||
Enabled = enabled;
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
// m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled");
|
||||
// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
|
||||
MaxDripRate = maxDripRate;
|
||||
AdjustedDripRate = m_minimumFlow;
|
||||
}
|
||||
@@ -377,9 +377,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// </summary>
|
||||
public void ExpirePackets(Int32 count)
|
||||
{
|
||||
// m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
|
||||
if (Enabled)
|
||||
{
|
||||
if (DebugLevel > 0)
|
||||
m_log.WarnFormat(
|
||||
"[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}",
|
||||
AdjustedDripRate, count, Identifier);
|
||||
|
||||
AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
|
||||
}
|
||||
}
|
||||
|
||||
// <summary>
|
||||
|
||||
@@ -387,7 +387,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
if (!Enabled)
|
||||
return false;
|
||||
|
||||
return AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append);
|
||||
group.DetachFromBackup();
|
||||
|
||||
bool success = AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append);
|
||||
|
||||
if (!success)
|
||||
group.AttachToBackup();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -815,8 +822,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
"[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}",
|
||||
so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos);
|
||||
|
||||
so.DetachFromBackup();
|
||||
|
||||
// Remove from database and parcel prim count
|
||||
m_scene.DeleteFromStorage(so.UUID);
|
||||
m_scene.EventManager.TriggerParcelPrimCountTainted();
|
||||
|
||||
@@ -199,6 +199,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
string attName = "att";
|
||||
|
||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
|
||||
Assert.That(so.Backup, Is.True);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false);
|
||||
@@ -213,6 +214,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
Assert.That(attSo.Backup, Is.False);
|
||||
|
||||
// Check item status
|
||||
Assert.That(
|
||||
@@ -385,7 +387,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
public void TestRezAttachmentFromInventory()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
@@ -407,6 +409,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
Assert.IsFalse(attSo.Backup);
|
||||
|
||||
// Check appearance status
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
@@ -601,7 +604,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItem.ID)), Is.Null);
|
||||
|
||||
// Check object in scene
|
||||
Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
|
||||
SceneObjectGroup soInScene = scene.GetSceneObjectGroup("att");
|
||||
Assert.That(soInScene, Is.Not.Null);
|
||||
Assert.IsTrue(soInScene.Backup);
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
@@ -755,6 +760,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
Assert.IsFalse(attSo.Backup);
|
||||
|
||||
// Check appearance status
|
||||
List<AvatarAttachment> retreivedAttachments = presence.Appearance.GetAttachments();
|
||||
@@ -884,6 +890,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0];
|
||||
Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name));
|
||||
Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest));
|
||||
Assert.IsFalse(actualSceneBAtt.Backup);
|
||||
|
||||
Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
@@ -994,6 +1001,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0];
|
||||
Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name));
|
||||
Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest));
|
||||
Assert.IsFalse(actualSceneBAtt.Backup);
|
||||
|
||||
Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
|
||||
@@ -912,7 +912,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
// one full update during the attachment
|
||||
// process causes some clients to fail to display the
|
||||
// attachment properly.
|
||||
m_Scene.AddNewSceneObject(group, true, false);
|
||||
m_Scene.AddNewSceneObject(group, !attachment, false);
|
||||
|
||||
// if attachment we set it's asset id so object updates
|
||||
// can reflect that, if not, we set it's position in world.
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
|
||||
/// </remarks>
|
||||
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MapImageServiceModule")]
|
||||
public class MapImageServiceModule : ISharedRegionModule
|
||||
public class MapImageServiceModule : IMapImageUploadModule, ISharedRegionModule
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
@@ -152,6 +152,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
|
||||
m_scenes[scene.RegionInfo.RegionID] = scene;
|
||||
|
||||
scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) UploadMapTile(s); };
|
||||
|
||||
scene.RegisterModuleInterface<IMapImageUploadModule>(this);
|
||||
}
|
||||
|
||||
///<summary>
|
||||
@@ -198,14 +200,53 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
|
||||
m_lastrefresh = Util.EnvironmentTickCount();
|
||||
}
|
||||
|
||||
public void UploadMapTile(IScene scene, Bitmap mapTile)
|
||||
{
|
||||
m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.Name);
|
||||
|
||||
// mapTile.Save( // DEBUG DEBUG
|
||||
// String.Format("maptiles/raw-{0}-{1}-{2}.jpg", regionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY),
|
||||
// ImageFormat.Jpeg);
|
||||
// If the region/maptile is legacy sized, just upload the one tile like it has always been done
|
||||
if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize)
|
||||
{
|
||||
ConvertAndUploadMaptile(mapTile,
|
||||
scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
|
||||
scene.RegionInfo.RegionName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For larger regions (varregion) we must cut the region image into legacy sized
|
||||
// pieces since that is how the maptile system works.
|
||||
// Note the assumption that varregions are always a multiple of legacy size.
|
||||
for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize)
|
||||
{
|
||||
for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize)
|
||||
{
|
||||
// Images are addressed from the upper left corner so have to do funny
|
||||
// math to pick out the sub-tile since regions are numbered from
|
||||
// the lower left.
|
||||
Rectangle rect = new Rectangle(
|
||||
(int)xx,
|
||||
mapTile.Height - (int)yy - (int)Constants.RegionSize,
|
||||
(int)Constants.RegionSize, (int)Constants.RegionSize);
|
||||
using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat))
|
||||
{
|
||||
ConvertAndUploadMaptile(subMapTile,
|
||||
scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize),
|
||||
scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize),
|
||||
scene.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///
|
||||
///</summary>
|
||||
private void UploadMapTile(IScene scene)
|
||||
{
|
||||
m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.RegionInfo.RegionName);
|
||||
string regionName = scene.RegionInfo.RegionName;
|
||||
|
||||
// Create a JPG map tile and upload it to the AddMapTile API
|
||||
IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
|
||||
if (tileGenerator == null)
|
||||
@@ -213,46 +254,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
|
||||
m_log.WarnFormat("{0} Cannot upload map tile without an ImageGenerator", LogHeader);
|
||||
return;
|
||||
}
|
||||
|
||||
using (Bitmap mapTile = tileGenerator.CreateMapTile())
|
||||
{
|
||||
if (mapTile != null)
|
||||
{
|
||||
// mapTile.Save( // DEBUG DEBUG
|
||||
// String.Format("maptiles/raw-{0}-{1}-{2}.jpg", regionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY),
|
||||
// ImageFormat.Jpeg);
|
||||
// If the region/maptile is legacy sized, just upload the one tile like it has always been done
|
||||
if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize)
|
||||
{
|
||||
ConvertAndUploadMaptile(mapTile,
|
||||
scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
|
||||
scene.RegionInfo.RegionName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For larger regions (varregion) we must cut the region image into legacy sized
|
||||
// pieces since that is how the maptile system works.
|
||||
// Note the assumption that varregions are always a multiple of legacy size.
|
||||
for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize)
|
||||
{
|
||||
for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize)
|
||||
{
|
||||
// Images are addressed from the upper left corner so have to do funny
|
||||
// math to pick out the sub-tile since regions are numbered from
|
||||
// the lower left.
|
||||
Rectangle rect = new Rectangle(
|
||||
(int)xx,
|
||||
mapTile.Height - (int)yy - (int)Constants.RegionSize,
|
||||
(int)Constants.RegionSize, (int)Constants.RegionSize);
|
||||
using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat))
|
||||
{
|
||||
ConvertAndUploadMaptile(subMapTile,
|
||||
scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize),
|
||||
scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize),
|
||||
regionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UploadMapTile(scene, mapTile);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -141,6 +141,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
|
||||
|
||||
part.ObjectSaleType = 0;
|
||||
part.SalePrice = 10;
|
||||
part.ClickAction = Convert.ToByte(0);
|
||||
|
||||
group.HasGroupChanged = true;
|
||||
part.SendPropertiesToClient(remoteClient);
|
||||
|
||||
@@ -68,6 +68,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
private static readonly UUID STOP_UUID = UUID.Random();
|
||||
private static readonly string m_mapLayerPath = "0001/";
|
||||
|
||||
private IMapImageGenerator m_mapImageGenerator;
|
||||
private IMapImageUploadModule m_mapImageServiceModule;
|
||||
|
||||
private OpenSim.Framework.BlockingQueue<MapRequestState> requests = new OpenSim.Framework.BlockingQueue<MapRequestState>();
|
||||
|
||||
protected Scene m_scene;
|
||||
@@ -100,7 +103,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
= Util.GetConfigVarFromSections<int>(config, "BlacklistTimeout", configSections, 10 * 60) * 1000;
|
||||
}
|
||||
|
||||
public virtual void AddRegion (Scene scene)
|
||||
public virtual void AddRegion(Scene scene)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
@@ -144,8 +147,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
return;
|
||||
|
||||
m_ServiceThrottle = scene.RequestModuleInterface<IServiceThrottleModule>();
|
||||
}
|
||||
|
||||
m_mapImageGenerator = m_scene.RequestModuleInterface<IMapImageGenerator>();
|
||||
m_mapImageServiceModule = m_scene.RequestModuleInterface<IMapImageUploadModule>();
|
||||
}
|
||||
|
||||
public virtual void Close()
|
||||
{
|
||||
@@ -1315,7 +1320,17 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
if (consoleScene != null && consoleScene != m_scene)
|
||||
return;
|
||||
|
||||
GenerateMaptile();
|
||||
if (m_mapImageGenerator == null)
|
||||
{
|
||||
Console.WriteLine("No map image generator available for {0}", m_scene.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
|
||||
{
|
||||
GenerateMaptile(mapbmp);
|
||||
m_mapImageServiceModule.UploadMapTile(m_scene, mapbmp);
|
||||
}
|
||||
}
|
||||
|
||||
public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
|
||||
@@ -1444,16 +1459,25 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
if (m_scene.Heightmap == null)
|
||||
return;
|
||||
|
||||
//create a texture asset of the terrain
|
||||
IMapImageGenerator terrain = m_scene.RequestModuleInterface<IMapImageGenerator>();
|
||||
if (terrain == null)
|
||||
return;
|
||||
m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.Name);
|
||||
|
||||
m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName);
|
||||
using (Bitmap mapbmp = m_mapImageGenerator.CreateMapTile())
|
||||
GenerateMaptile(mapbmp);
|
||||
}
|
||||
|
||||
byte[] data = terrain.WriteJpeg2000Image();
|
||||
if (data == null)
|
||||
private void GenerateMaptile(Bitmap mapbmp)
|
||||
{
|
||||
byte[] data;
|
||||
|
||||
try
|
||||
{
|
||||
data = OpenJPEG.EncodeFromImage(mapbmp, true);
|
||||
}
|
||||
catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
|
||||
{
|
||||
m_log.Error("[WORLD MAP]: Failed generating terrain map: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] overlay = GenerateOverlay();
|
||||
|
||||
|
||||
37
OpenSim/Region/Framework/Interfaces/IMapImageUploadModule.cs
Normal file
37
OpenSim/Region/Framework/Interfaces/IMapImageUploadModule.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Drawing;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenSim.Region.Framework.Interfaces
|
||||
{
|
||||
public interface IMapImageUploadModule
|
||||
{
|
||||
void UploadMapTile(IScene scene, Bitmap mapTile);
|
||||
}
|
||||
}
|
||||
@@ -360,30 +360,52 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public uint MaintenanceRun { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The minimum length of time in seconds that will be taken for a scene frame. If the frame takes less time then we
|
||||
/// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
|
||||
/// will sleep for the remaining period.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
|
||||
/// occur too quickly (viewer 1) or with even more slide (viewer 2).
|
||||
/// </remarks>
|
||||
public float MinFrameTime { get; private set; }
|
||||
public int MinFrameTicks
|
||||
{
|
||||
get { return m_minFrameTicks; }
|
||||
private set
|
||||
{
|
||||
m_minFrameTicks = value;
|
||||
MinFrameSeconds = (float)m_minFrameTicks / 1000;
|
||||
}
|
||||
}
|
||||
private int m_minFrameTicks;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum length of time in seconds that will be taken for a maintenance run.
|
||||
/// The minimum length of time in seconds that will be taken for a scene frame.
|
||||
/// </summary>
|
||||
public float MinMaintenanceTime { get; private set; }
|
||||
/// <remarks>
|
||||
/// Always derived from MinFrameTicks.
|
||||
/// </remarks>
|
||||
public float MinFrameSeconds { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
|
||||
/// will sleep for the remaining period.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
|
||||
/// occur too quickly (viewer 1) or with even more slide (viewer 2).
|
||||
/// </remarks>
|
||||
public int MinMaintenanceTicks { get; set; }
|
||||
|
||||
private int m_update_physics = 1;
|
||||
private int m_update_entitymovement = 1;
|
||||
private int m_update_objects = 1;
|
||||
private int m_update_temp_cleaning = 1000;
|
||||
private int m_update_presences = 1; // Update scene presence movements
|
||||
private int m_update_events = 1;
|
||||
private int m_update_backup = 200;
|
||||
private int m_update_terrain = 50;
|
||||
// private int m_update_land = 1;
|
||||
private int m_update_coarse_locations = 50;
|
||||
private int m_update_temp_cleaning = 180;
|
||||
|
||||
private int agentMS;
|
||||
private int frameMS;
|
||||
@@ -412,8 +434,16 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// asynchronously from the update loop.
|
||||
/// </summary>
|
||||
private bool m_cleaningTemps = false;
|
||||
|
||||
/// <summary>
|
||||
/// Used to control main scene thread looping time when not updating via timer.
|
||||
/// </summary>
|
||||
private ManualResetEvent m_updateWaitEvent = new ManualResetEvent(false);
|
||||
|
||||
// private Object m_heartbeatLock = new Object();
|
||||
/// <summary>
|
||||
/// Used to control maintenance thread runs.
|
||||
/// </summary>
|
||||
private ManualResetEvent m_maintenanceWaitEvent = new ManualResetEvent(false);
|
||||
|
||||
// TODO: Possibly stop other classes being able to manipulate this directly.
|
||||
private SceneGraph m_sceneGraph;
|
||||
@@ -782,8 +812,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
: this(regInfo, physicsScene)
|
||||
{
|
||||
m_config = config;
|
||||
MinFrameTime = 0.089f;
|
||||
MinMaintenanceTime = 1;
|
||||
MinFrameTicks = 89;
|
||||
MinMaintenanceTicks = 1000;
|
||||
SeeIntoRegion = true;
|
||||
|
||||
Random random = new Random();
|
||||
@@ -1005,7 +1035,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime);
|
||||
if (startupConfig.Contains("MinFrameTime"))
|
||||
MinFrameTicks = (int)(startupConfig.GetFloat("MinFrameTime") * 1000);
|
||||
|
||||
m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup);
|
||||
m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
|
||||
m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement);
|
||||
@@ -1014,11 +1046,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics);
|
||||
m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences);
|
||||
m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
|
||||
m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning);
|
||||
m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNSeconds", m_update_temp_cleaning);
|
||||
}
|
||||
|
||||
// FIXME: Ultimately this should be in a module.
|
||||
SendPeriodicAppearanceUpdates = true;
|
||||
SendPeriodicAppearanceUpdates = false;
|
||||
|
||||
IConfig appearanceConfig = m_config.Configs["Appearance"];
|
||||
if (appearanceConfig != null)
|
||||
@@ -1444,13 +1476,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
if (UpdateOnTimer)
|
||||
{
|
||||
m_sceneUpdateTimer = new Timer(MinFrameTime * 1000);
|
||||
m_sceneUpdateTimer = new Timer(MinFrameTicks);
|
||||
m_sceneUpdateTimer.AutoReset = true;
|
||||
m_sceneUpdateTimer.Elapsed += Update;
|
||||
m_sceneUpdateTimer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.CurrentThread.Priority = ThreadPriority.Highest;
|
||||
Update(-1);
|
||||
Watchdog.RemoveThread();
|
||||
m_isRunning = false;
|
||||
@@ -1490,7 +1523,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public void DoMaintenance(int runs)
|
||||
{
|
||||
long? endRun = null;
|
||||
int runtc;
|
||||
int runtc, tmpMS;
|
||||
int previousMaintenanceTick;
|
||||
|
||||
if (runs >= 0)
|
||||
@@ -1504,6 +1537,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
runtc = Util.EnvironmentTickCount();
|
||||
++MaintenanceRun;
|
||||
|
||||
// m_log.DebugFormat("[SCENE]: Maintenance run {0} in {1}", MaintenanceRun, Name);
|
||||
|
||||
// Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client)
|
||||
if (MaintenanceRun % (m_update_coarse_locations / 10) == 0)
|
||||
{
|
||||
@@ -1525,24 +1560,39 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
// Delete temp-on-rez stuff
|
||||
if (MaintenanceRun % m_update_temp_cleaning == 0 && !m_cleaningTemps)
|
||||
{
|
||||
// m_log.DebugFormat("[SCENE]: Running temp-on-rez cleaning in {0}", Name);
|
||||
tmpMS = Util.EnvironmentTickCount();
|
||||
m_cleaningTemps = true;
|
||||
|
||||
Watchdog.RunInThread(
|
||||
delegate { CleanTempObjects(); m_cleaningTemps = false; },
|
||||
string.Format("CleanTempObjects ({0})", Name),
|
||||
null);
|
||||
|
||||
tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS);
|
||||
}
|
||||
|
||||
Watchdog.UpdateThread();
|
||||
|
||||
previousMaintenanceTick = m_lastMaintenanceTick;
|
||||
m_lastMaintenanceTick = Util.EnvironmentTickCount();
|
||||
runtc = Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, runtc);
|
||||
runtc = (int)(MinMaintenanceTime * 1000) - runtc;
|
||||
runtc = MinMaintenanceTicks - runtc;
|
||||
|
||||
if (runtc > 0)
|
||||
Thread.Sleep(runtc);
|
||||
m_maintenanceWaitEvent.WaitOne(runtc);
|
||||
|
||||
// Optionally warn if a frame takes double the amount of time that it should.
|
||||
if (DebugUpdates
|
||||
&& Util.EnvironmentTickCountSubtract(
|
||||
m_lastMaintenanceTick, previousMaintenanceTick) > (int)(MinMaintenanceTime * 1000 * 2))
|
||||
m_lastMaintenanceTick, previousMaintenanceTick) > MinMaintenanceTicks * 2)
|
||||
m_log.WarnFormat(
|
||||
"[SCENE]: Maintenance took {0} ms (desired max {1} ms) in {2}",
|
||||
Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, previousMaintenanceTick),
|
||||
MinMaintenanceTime * 1000,
|
||||
MinMaintenanceTicks,
|
||||
RegionInfo.RegionName);
|
||||
}
|
||||
}
|
||||
@@ -1563,7 +1613,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
// m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName);
|
||||
|
||||
agentMS = tempOnRezMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0;
|
||||
agentMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -1594,7 +1644,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (Frame % m_update_physics == 0)
|
||||
{
|
||||
if (PhysicsEnabled)
|
||||
physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime);
|
||||
physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameSeconds);
|
||||
|
||||
if (SynchronizeScene != null)
|
||||
SynchronizeScene(this);
|
||||
@@ -1616,21 +1666,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (Frame % m_update_presences == 0)
|
||||
m_sceneGraph.UpdatePresences();
|
||||
|
||||
agentMS += Util.EnvironmentTickCountSubtract(tmpMS);
|
||||
|
||||
// Delete temp-on-rez stuff
|
||||
if (Frame % m_update_temp_cleaning == 0 && !m_cleaningTemps)
|
||||
{
|
||||
tmpMS = Util.EnvironmentTickCount();
|
||||
m_cleaningTemps = true;
|
||||
|
||||
Watchdog.RunInThread(
|
||||
delegate { CleanTempObjects(); m_cleaningTemps = false; },
|
||||
string.Format("CleanTempObjects ({0})", Name),
|
||||
null);
|
||||
|
||||
tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS);
|
||||
}
|
||||
agentMS += Util.EnvironmentTickCountSubtract(tmpMS);
|
||||
|
||||
if (Frame % m_update_events == 0)
|
||||
{
|
||||
@@ -1700,24 +1736,22 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
|
||||
EventManager.TriggerRegionHeartbeatEnd(this);
|
||||
otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS;
|
||||
otherMS = eventMS + backupMS + terrainMS + landMS;
|
||||
|
||||
if (!UpdateOnTimer)
|
||||
{
|
||||
Watchdog.UpdateThread();
|
||||
|
||||
tmpMS = Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), m_lastFrameTick);
|
||||
tmpMS = (int)(MinFrameTime * 1000) - tmpMS;
|
||||
spareMS = MinFrameTicks - Util.EnvironmentTickCountSubtract(m_lastFrameTick);
|
||||
|
||||
if (tmpMS > 0)
|
||||
{
|
||||
spareMS = tmpMS;
|
||||
Thread.Sleep(tmpMS);
|
||||
}
|
||||
if (spareMS > 0)
|
||||
m_updateWaitEvent.WaitOne(spareMS);
|
||||
else
|
||||
spareMS = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
spareMS = Math.Max(0, (int)(MinFrameTime * 1000) - physicsMS2 - agentMS - physicsMS -otherMS);
|
||||
spareMS = Math.Max(0, MinFrameTicks - physicsMS2 - agentMS - physicsMS - otherMS);
|
||||
}
|
||||
|
||||
previousFrameTick = m_lastFrameTick;
|
||||
@@ -1740,11 +1774,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// Optionally warn if a frame takes double the amount of time that it should.
|
||||
if (DebugUpdates
|
||||
&& Util.EnvironmentTickCountSubtract(
|
||||
m_lastFrameTick, previousFrameTick) > (int)(MinFrameTime * 1000 * 2))
|
||||
m_lastFrameTick, previousFrameTick) > MinFrameTicks * 2)
|
||||
m_log.WarnFormat(
|
||||
"[SCENE]: Frame took {0} ms (desired max {1} ms) in {2}",
|
||||
Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick),
|
||||
MinFrameTime * 1000,
|
||||
MinFrameTicks,
|
||||
RegionInfo.RegionName);
|
||||
}
|
||||
|
||||
@@ -4466,14 +4500,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
sp.LifecycleState = ScenePresenceState.Removing;
|
||||
}
|
||||
|
||||
if (sp != null)
|
||||
{
|
||||
sp.ControllingClient.Close(force);
|
||||
return true;
|
||||
}
|
||||
sp.ControllingClient.Close(force);
|
||||
|
||||
// Agent not here
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -943,8 +943,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
if (CanBeBackedUp)
|
||||
{
|
||||
//m_log.DebugFormat(
|
||||
// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
|
||||
|
||||
if (!Backup)
|
||||
m_scene.EventManager.OnBackup += ProcessBackup;
|
||||
|
||||
@@ -1589,20 +1589,29 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim)
|
||||
{
|
||||
byte[] data = new byte[16];
|
||||
int pos = 0;
|
||||
byte[] data;
|
||||
|
||||
// The flags don't like conversion from uint to byte, so we have to do
|
||||
// it the crappy way. See the above function :(
|
||||
if (pTexAnim.Flags == Primitive.TextureAnimMode.ANIM_OFF)
|
||||
{
|
||||
data = Utils.EmptyBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = new byte[16];
|
||||
int pos = 0;
|
||||
|
||||
data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++;
|
||||
data[pos] = (byte)pTexAnim.Face; pos++;
|
||||
data[pos] = (byte)pTexAnim.SizeX; pos++;
|
||||
data[pos] = (byte)pTexAnim.SizeY; pos++;
|
||||
// The flags don't like conversion from uint to byte, so we have to do
|
||||
// it the crappy way. See the above function :(
|
||||
|
||||
Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos);
|
||||
Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4);
|
||||
Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8);
|
||||
data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++;
|
||||
data[pos] = (byte)pTexAnim.Face; pos++;
|
||||
data[pos] = (byte)pTexAnim.SizeX; pos++;
|
||||
data[pos] = (byte)pTexAnim.SizeY; pos++;
|
||||
|
||||
Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos);
|
||||
Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4);
|
||||
Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8);
|
||||
}
|
||||
|
||||
m_TextureAnimation = data;
|
||||
}
|
||||
|
||||
@@ -1228,10 +1228,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// viewers without (e.g. v1 viewers) will not, so we still need to make this call.
|
||||
if (Scene.AttachmentsModule != null)
|
||||
{
|
||||
Util.FireAndForget(o =>
|
||||
{
|
||||
Scene.AttachmentsModule.RezAttachments(this);
|
||||
});
|
||||
if (Watchdog.JobEngine.IsRunning)
|
||||
Watchdog.RunWhenPossible(
|
||||
"RezAttachments",
|
||||
o => Scene.AttachmentsModule.RezAttachments(this),
|
||||
string.Format("Rez attachments for {0} in {1}", Name, Scene.Name),
|
||||
null);
|
||||
else
|
||||
Util.FireAndForget(o => Scene.AttachmentsModule.RezAttachments(this));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2618,7 +2622,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 sitPartWorldPosition = part.GetWorldPosition();
|
||||
ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
|
||||
|
||||
ParentID = 0;
|
||||
@@ -2647,13 +2650,13 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
// Vector3 standPositionAdjustment
|
||||
// = part.SitTargetPosition + new Vector3(0.5f, 0f, m_sitAvatarHeight / 2f);
|
||||
Vector3 adjustmentForSitPosition = (part.SitTargetPosition + OffsetPosition) * part.GetWorldRotation();
|
||||
Vector3 adjustmentForSitPosition = (OffsetPosition - SIT_TARGET_ADJUSTMENT) * part.GetWorldRotation();
|
||||
|
||||
// XXX: This is based on the physics capsule sizes. Need to find a better way to read this rather than
|
||||
// hardcoding here.
|
||||
Vector3 adjustmentForSitPose = new Vector3(0.74f, 0f, 0f) * standRotation;
|
||||
|
||||
Vector3 standPos = sitPartWorldPosition + adjustmentForSitPosition + adjustmentForSitPose;
|
||||
Vector3 standPos = part.ParentGroup.AbsolutePosition + adjustmentForSitPosition + adjustmentForSitPose;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE PRESENCE]: Setting stand to pos {0}, (adjustmentForSitPosition {1}, adjustmentForSitPose {2}) rotation {3} for {4} in {5}",
|
||||
@@ -3363,7 +3366,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
SentInitialDataToClient = true;
|
||||
|
||||
// Send all scene object to the new client
|
||||
Watchdog.RunInThread(delegate
|
||||
Watchdog.RunWhenPossible("SendInitialDataToClient", delegate
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE PRESENCE]: Sending initial data to {0} agent {1} in {2}, tp flags {3}",
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public SimStatsReporter(Scene scene)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_reportedFpsCorrectionFactor = scene.MinFrameTime * m_nominalReportedFps;
|
||||
m_reportedFpsCorrectionFactor = scene.MinFrameSeconds * m_nominalReportedFps;
|
||||
m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000);
|
||||
ReportingRegion = scene.RegionInfo;
|
||||
|
||||
@@ -239,7 +239,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
/// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit
|
||||
/// longer than ideal (which in itself is a concern).
|
||||
SlowFramesStatReportThreshold = (int)Math.Ceiling(m_scene.MinFrameTime * 1000 * 1.2);
|
||||
SlowFramesStatReportThreshold = (int)Math.Ceiling(scene.MinFrameTicks * 1.2);
|
||||
|
||||
SlowFramesStat
|
||||
= new Stat(
|
||||
|
||||
@@ -513,8 +513,6 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
|
||||
|
||||
report.AppendLine();
|
||||
|
||||
bool firstClient = true;
|
||||
|
||||
lock (m_scenes)
|
||||
{
|
||||
foreach (Scene scene in m_scenes.Values)
|
||||
@@ -526,12 +524,6 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
|
||||
{
|
||||
LLClientView llClient = client as LLClientView;
|
||||
|
||||
if (firstClient)
|
||||
{
|
||||
report.AppendLine(GetServerThrottlesReport(llClient.UDPServer));
|
||||
firstClient = false;
|
||||
}
|
||||
|
||||
bool isChild = client.SceneAgent.IsChildAgent;
|
||||
if (isChild && !showChildren)
|
||||
return;
|
||||
@@ -569,37 +561,6 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
|
||||
|
||||
return report.ToString();
|
||||
}
|
||||
|
||||
protected string GetServerThrottlesReport(LLUDPServer udpServer)
|
||||
{
|
||||
StringBuilder report = new StringBuilder();
|
||||
|
||||
int columnPadding = 2;
|
||||
int maxNameLength = 18;
|
||||
int maxRegionNameLength = 14;
|
||||
int maxTypeLength = 4;
|
||||
|
||||
string name = "SERVER AGENT RATES";
|
||||
|
||||
report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
|
||||
report.Append(GetColumnEntry("-", maxRegionNameLength, columnPadding));
|
||||
report.Append(GetColumnEntry("-", maxTypeLength, columnPadding));
|
||||
|
||||
ThrottleRates throttleRates = udpServer.ThrottleRates;
|
||||
report.AppendFormat(
|
||||
"{0,8} {1,7} {2,8} {3,7} {4,7} {5,7} {6,7} {7,9} {8,7}",
|
||||
"-",
|
||||
(throttleRates.Total * 8) / 1000,
|
||||
(throttleRates.Resend * 8) / 1000,
|
||||
(throttleRates.Land * 8) / 1000,
|
||||
(throttleRates.Wind * 8) / 1000,
|
||||
(throttleRates.Cloud * 8) / 1000,
|
||||
(throttleRates.Task * 8) / 1000,
|
||||
(throttleRates.Texture * 8) / 1000,
|
||||
(throttleRates.Asset * 8) / 1000);
|
||||
|
||||
return report.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show client stats data
|
||||
|
||||
@@ -234,6 +234,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||
ScenePresence sp;
|
||||
if (scene.TryGetScenePresence(agentID, out sp))
|
||||
{
|
||||
if (sp.IsSatOnObject || sp.SitGround)
|
||||
return false;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}",
|
||||
// sp.Name, pos, scene.RegionInfo.RegionName,
|
||||
|
||||
@@ -300,7 +300,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
|
||||
public void TestMove()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
SetUpScene();
|
||||
|
||||
|
||||
@@ -130,6 +130,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||
internal int m_maxUpdatesPerFrame;
|
||||
internal EntityProperties[] m_updateArray;
|
||||
|
||||
/// <summary>
|
||||
/// Used to control physics simulation timing if Bullet is running on its own thread.
|
||||
/// </summary>
|
||||
private ManualResetEvent m_updateWaitEvent;
|
||||
|
||||
public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
|
||||
public const uint GROUNDPLANE_ID = 1;
|
||||
public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
|
||||
@@ -838,6 +843,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||
|
||||
public void BulletSPluginPhysicsThread()
|
||||
{
|
||||
Thread.CurrentThread.Priority = ThreadPriority.Highest;
|
||||
m_updateWaitEvent = new ManualResetEvent(false);
|
||||
|
||||
while (m_initialized)
|
||||
{
|
||||
int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
|
||||
@@ -851,8 +859,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||
if (simulationTimeVsRealtimeDifferenceMS > 0)
|
||||
{
|
||||
// The simulation of the time interval took less than realtime.
|
||||
// Do a sleep for the rest of realtime.
|
||||
Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
|
||||
// Do a wait for the rest of realtime.
|
||||
m_updateWaitEvent.WaitOne(simulationTimeVsRealtimeDifferenceMS);
|
||||
//Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -231,7 +231,7 @@ public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeM
|
||||
{ CollisionType.Avatar,
|
||||
new CollisionTypeFilterGroup(CollisionType.Avatar,
|
||||
(uint)CollisionFilterGroups.BCharacterGroup,
|
||||
(uint)CollisionFilterGroups.BAllGroup)
|
||||
(uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup))
|
||||
},
|
||||
{ CollisionType.Groundplane,
|
||||
new CollisionTypeFilterGroup(CollisionType.Groundplane,
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace OpenSim.Services.Interfaces
|
||||
|
||||
public class GridRegion
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
#pragma warning disable 414
|
||||
private static readonly string LogHeader = "[GRID REGION]";
|
||||
@@ -135,12 +135,7 @@ namespace OpenSim.Services.Interfaces
|
||||
/// <summary>
|
||||
/// The port by which http communication occurs with the region
|
||||
/// </summary>
|
||||
public uint HttpPort
|
||||
{
|
||||
get { return m_httpPort; }
|
||||
set { m_httpPort = value; }
|
||||
}
|
||||
protected uint m_httpPort;
|
||||
public uint HttpPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A well-formed URI for the host region server (namely "http://" + ExternalHostName)
|
||||
@@ -151,10 +146,10 @@ namespace OpenSim.Services.Interfaces
|
||||
if (!String.IsNullOrEmpty(m_serverURI)) {
|
||||
return m_serverURI;
|
||||
} else {
|
||||
if (m_httpPort == 0)
|
||||
if (HttpPort == 0)
|
||||
return "http://" + m_externalHostName + "/";
|
||||
else
|
||||
return "http://" + m_externalHostName + ":" + m_httpPort + "/";
|
||||
return "http://" + m_externalHostName + ":" + HttpPort + "/";
|
||||
}
|
||||
}
|
||||
set {
|
||||
@@ -290,7 +285,7 @@ namespace OpenSim.Services.Interfaces
|
||||
RegionSizeY = (int)ConvertFrom.RegionSizeY;
|
||||
m_internalEndPoint = ConvertFrom.InternalEndPoint;
|
||||
m_externalHostName = ConvertFrom.ExternalHostName;
|
||||
m_httpPort = ConvertFrom.HttpPort;
|
||||
HttpPort = ConvertFrom.HttpPort;
|
||||
RegionID = ConvertFrom.RegionID;
|
||||
ServerURI = ConvertFrom.ServerURI;
|
||||
TerrainImage = ConvertFrom.RegionSettings.TerrainImageID;
|
||||
@@ -310,7 +305,7 @@ namespace OpenSim.Services.Interfaces
|
||||
RegionSizeY = ConvertFrom.RegionSizeY;
|
||||
m_internalEndPoint = ConvertFrom.InternalEndPoint;
|
||||
m_externalHostName = ConvertFrom.ExternalHostName;
|
||||
m_httpPort = ConvertFrom.HttpPort;
|
||||
HttpPort = ConvertFrom.HttpPort;
|
||||
RegionID = ConvertFrom.RegionID;
|
||||
ServerURI = ConvertFrom.ServerURI;
|
||||
TerrainImage = ConvertFrom.TerrainImage;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace OpenSim.Services.UserProfilesService
|
||||
/// </remarks>
|
||||
public class OpenProfileClient
|
||||
{
|
||||
static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private string m_serverURI;
|
||||
|
||||
@@ -60,8 +60,7 @@ namespace OpenSim.Services.UserProfilesService
|
||||
{
|
||||
m_serverURI = serverURI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets an avatar's profile using the OpenProfile protocol.
|
||||
/// </summary>
|
||||
@@ -132,4 +131,4 @@ namespace OpenSim.Services.UserProfilesService
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -611,7 +611,7 @@ namespace OpenSim.Tests.Common
|
||||
//part.UpdatePrimFlags(false, false, true);
|
||||
//part.ObjectFlags |= (uint)PrimFlags.Phantom;
|
||||
|
||||
scene.AddNewSceneObject(so, false);
|
||||
scene.AddNewSceneObject(so, true);
|
||||
|
||||
return so;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ using System.Timers;
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Assets;
|
||||
using OpenMetaverse.Packets;
|
||||
using Nini.Config;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Console;
|
||||
@@ -56,6 +57,27 @@ namespace pCampBot
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public int PacketDebugLevel
|
||||
{
|
||||
get { return m_packetDebugLevel; }
|
||||
set
|
||||
{
|
||||
if (value == m_packetDebugLevel)
|
||||
return;
|
||||
|
||||
m_packetDebugLevel = value;
|
||||
|
||||
if (Client != null)
|
||||
{
|
||||
if (m_packetDebugLevel <= 0)
|
||||
Client.Network.UnregisterCallback(PacketType.Default, PacketReceivedDebugHandler);
|
||||
else
|
||||
Client.Network.RegisterCallback(PacketType.Default, PacketReceivedDebugHandler, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
private int m_packetDebugLevel;
|
||||
|
||||
public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events
|
||||
|
||||
/// <summary>
|
||||
@@ -231,6 +253,9 @@ namespace pCampBot
|
||||
|
||||
if (Client != null)
|
||||
{
|
||||
// Remove any registered debug handlers
|
||||
Client.Network.UnregisterCallback(PacketType.Default, PacketReceivedDebugHandler);
|
||||
|
||||
newClient.Settings.LOGIN_SERVER = Client.Settings.LOGIN_SERVER;
|
||||
newClient.Settings.ALWAYS_DECODE_OBJECTS = Client.Settings.ALWAYS_DECODE_OBJECTS;
|
||||
newClient.Settings.AVATAR_TRACKING = Client.Settings.AVATAR_TRACKING;
|
||||
@@ -273,6 +298,9 @@ namespace pCampBot
|
||||
newClient.Network.Disconnected += Network_OnDisconnected;
|
||||
newClient.Objects.ObjectUpdate += Objects_NewPrim;
|
||||
|
||||
if (m_packetDebugLevel > 0)
|
||||
newClient.Network.RegisterCallback(PacketType.Default, PacketReceivedDebugHandler);
|
||||
|
||||
Client = newClient;
|
||||
}
|
||||
|
||||
@@ -705,5 +733,16 @@ namespace pCampBot
|
||||
// SaveAsset((AssetWearable) asset);
|
||||
// }
|
||||
}
|
||||
|
||||
private void PacketReceivedDebugHandler(object o, PacketReceivedEventArgs args)
|
||||
{
|
||||
Packet p = args.Packet;
|
||||
Header h = p.Header;
|
||||
Simulator s = args.Simulator;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[BOT]: Bot {0} received from {1} packet {2} #{3}, rel {4}, res {5}",
|
||||
Name, s.Name, p.Type, h.Sequence, h.Reliable, h.Resent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,14 @@ using pCampBot.Interfaces;
|
||||
|
||||
namespace pCampBot
|
||||
{
|
||||
public enum BotManagerBotConnectingState
|
||||
{
|
||||
Initializing,
|
||||
Ready,
|
||||
Connecting,
|
||||
Disconnecting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thread/Bot manager for the application
|
||||
/// </summary>
|
||||
@@ -53,14 +61,14 @@ namespace pCampBot
|
||||
public const int DefaultLoginDelay = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Is pCampbot in the process of connecting bots?
|
||||
/// Is pCampbot ready to connect or currently in the process of connecting or disconnecting bots?
|
||||
/// </summary>
|
||||
public bool ConnectingBots { get; private set; }
|
||||
public BotManagerBotConnectingState BotConnectingState { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is pCampbot in the process of disconnecting bots?
|
||||
/// Used to control locking as we can't lock an enum.
|
||||
/// </summary>
|
||||
public bool DisconnectingBots { get; private set; }
|
||||
private object BotConnectingStateChangeObject = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Delay between logins of multiple bots.
|
||||
@@ -239,12 +247,25 @@ namespace pCampBot
|
||||
"Bots", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Bots", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus);
|
||||
"Bots", false, "show bots", "show bots", "Shows the status of all bots.", HandleShowBotsStatus);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Bots", false, "show bot", "show bot <bot-number>",
|
||||
"Shows the detailed status and settings of a particular bot.", HandleShowBotStatus);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp packet",
|
||||
"debug lludp packet <level> <avatar-first-name> <avatar-last-name>",
|
||||
"Turn on received packet logging.",
|
||||
"If level > 0 then all received packets that are not duplicates are logged.\n"
|
||||
+ "If level <= 0 then no received packets are logged.",
|
||||
HandleDebugLludpPacketCommand);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Bots", false, "show status", "show status", "Shows pCampbot status.", HandleShowStatus);
|
||||
|
||||
m_bots = new List<Bot>();
|
||||
|
||||
Watchdog.Enabled = true;
|
||||
@@ -254,6 +275,8 @@ namespace pCampBot
|
||||
m_serverStatsCollector.Initialise(null);
|
||||
m_serverStatsCollector.Enabled = true;
|
||||
m_serverStatsCollector.Start();
|
||||
|
||||
BotConnectingState = BotManagerBotConnectingState.Ready;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -335,7 +358,17 @@ namespace pCampBot
|
||||
|
||||
public void ConnectBots(int botcount)
|
||||
{
|
||||
ConnectingBots = true;
|
||||
lock (BotConnectingStateChangeObject)
|
||||
{
|
||||
if (BotConnectingState != BotManagerBotConnectingState.Ready)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Bot connecting status is {0}. Please wait for previous process to complete.", BotConnectingState);
|
||||
return;
|
||||
}
|
||||
|
||||
BotConnectingState = BotManagerBotConnectingState.Connecting;
|
||||
}
|
||||
|
||||
Thread connectBotThread = new Thread(o => ConnectBotsInternal(botcount));
|
||||
|
||||
@@ -373,11 +406,14 @@ namespace pCampBot
|
||||
|
||||
foreach (Bot bot in botsToConnect)
|
||||
{
|
||||
if (!ConnectingBots)
|
||||
lock (BotConnectingStateChangeObject)
|
||||
{
|
||||
MainConsole.Instance.Output(
|
||||
"[BOT MANAGER]: Aborting bot connection due to user-initiated disconnection");
|
||||
break;
|
||||
if (BotConnectingState != BotManagerBotConnectingState.Connecting)
|
||||
{
|
||||
MainConsole.Instance.Output(
|
||||
"[BOT MANAGER]: Aborting bot connection due to user-initiated disconnection");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bot.Connect();
|
||||
@@ -386,7 +422,11 @@ namespace pCampBot
|
||||
Thread.Sleep(LoginDelay);
|
||||
}
|
||||
|
||||
ConnectingBots = false;
|
||||
lock (BotConnectingStateChangeObject)
|
||||
{
|
||||
if (BotConnectingState == BotManagerBotConnectingState.Connecting)
|
||||
BotConnectingState = BotManagerBotConnectingState.Ready;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -491,13 +531,7 @@ namespace pCampBot
|
||||
}
|
||||
|
||||
private void HandleConnect(string module, string[] cmd)
|
||||
{
|
||||
if (ConnectingBots)
|
||||
{
|
||||
MainConsole.Instance.Output("Still connecting bots. Please wait for previous process to complete.");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
lock (m_bots)
|
||||
{
|
||||
int botsToConnect;
|
||||
@@ -653,7 +687,8 @@ namespace pCampBot
|
||||
botsToDisconnectCount = Math.Min(botsToDisconnectCount, connectedBots.Count);
|
||||
}
|
||||
|
||||
DisconnectingBots = true;
|
||||
lock (BotConnectingStateChangeObject)
|
||||
BotConnectingState = BotManagerBotConnectingState.Disconnecting;
|
||||
|
||||
Thread disconnectBotThread = new Thread(o => DisconnectBotsInternal(connectedBots, botsToDisconnectCount));
|
||||
|
||||
@@ -662,9 +697,7 @@ namespace pCampBot
|
||||
}
|
||||
|
||||
private void DisconnectBotsInternal(List<Bot> connectedBots, int disconnectCount)
|
||||
{
|
||||
ConnectingBots = false;
|
||||
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Disconnecting {0} bots", disconnectCount);
|
||||
|
||||
int disconnectedBots = 0;
|
||||
@@ -683,7 +716,8 @@ namespace pCampBot
|
||||
}
|
||||
}
|
||||
|
||||
DisconnectingBots = false;
|
||||
lock (BotConnectingStateChangeObject)
|
||||
BotConnectingState = BotManagerBotConnectingState.Ready;
|
||||
}
|
||||
|
||||
private void HandleSit(string module, string[] cmd)
|
||||
@@ -760,6 +794,38 @@ namespace pCampBot
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDebugLludpPacketCommand(string module, string[] args)
|
||||
{
|
||||
if (args.Length != 6)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Usage: debug lludp packet <level> <bot-first-name> <bot-last-name>");
|
||||
return;
|
||||
}
|
||||
|
||||
int level;
|
||||
|
||||
if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[3], out level))
|
||||
return;
|
||||
|
||||
string botFirstName = args[4];
|
||||
string botLastName = args[5];
|
||||
|
||||
Bot bot;
|
||||
|
||||
lock (m_bots)
|
||||
bot = m_bots.FirstOrDefault(b => b.FirstName == botFirstName && b.LastName == botLastName);
|
||||
|
||||
if (bot == null)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("No bot named {0} {1}", botFirstName, botLastName);
|
||||
return;
|
||||
}
|
||||
|
||||
bot.PacketDebugLevel = level;
|
||||
|
||||
MainConsole.Instance.OutputFormat("Set debug level of {0} to {1}", bot.Name, bot.PacketDebugLevel);
|
||||
}
|
||||
|
||||
private void HandleShowRegions(string module, string[] cmd)
|
||||
{
|
||||
string outputFormat = "{0,-30} {1, -20} {2, -5} {3, -5}";
|
||||
@@ -775,6 +841,14 @@ namespace pCampBot
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleShowStatus(string module, string[] cmd)
|
||||
{
|
||||
ConsoleDisplayList cdl = new ConsoleDisplayList();
|
||||
cdl.AddRow("Bot connecting state", BotConnectingState);
|
||||
|
||||
MainConsole.Instance.Output(cdl.ToString());
|
||||
}
|
||||
|
||||
private void HandleShowBotsStatus(string module, string[] cmd)
|
||||
{
|
||||
ConsoleDisplayTable cdt = new ConsoleDisplayTable();
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -170,10 +170,6 @@
|
||||
; This must be a whole number
|
||||
UpdatePhysicsEveryNFrames = 1;
|
||||
|
||||
; Clean up temp on rez objects.
|
||||
; This must be a whole number
|
||||
UpdateTempCleaningEveryNFrames = 1000;
|
||||
|
||||
; Send out the on frame event to modules and other listeners. This should probably never deviate from 1.
|
||||
; This must be a whole number
|
||||
UpdateEventsEveryNFrames = 1;
|
||||
@@ -186,6 +182,10 @@
|
||||
; This must be a whole number
|
||||
UpdateStorageEveryNFrames = 200;
|
||||
|
||||
; Clean up temp on rez objects.
|
||||
; This must be a whole number
|
||||
UpdateTempCleaningEveryNSeconds = 180;
|
||||
|
||||
; ##
|
||||
; ## PRIM STORAGE
|
||||
; ##
|
||||
@@ -521,14 +521,14 @@
|
||||
; 0, meaning no throttling at the scene level. The example given here is
|
||||
; 20 megabits
|
||||
;
|
||||
;scene_throttle_max_bps = 2621440
|
||||
;scene_throttle_max_bps = 2500000
|
||||
|
||||
; Maximum bits per second to send to any single client. This will override
|
||||
; Maximum bytes per second to send to any single client. This will override
|
||||
; the user's viewer preference settings. The default value is 0, meaning no
|
||||
; aggregate throttling on clients (only per-category throttling). The
|
||||
; example given here is 1.5 megabits
|
||||
;
|
||||
;client_throttle_max_bps = 196608
|
||||
;client_throttle_max_bps = 187500
|
||||
|
||||
; Adaptive throttling attempts to limit network overload when multiple
|
||||
; clients login by starting each connection more slowly. Disabled by
|
||||
@@ -762,7 +762,7 @@
|
||||
; If true, avatar appearance information is resent to other avatars in the simulator every 60 seconds.
|
||||
; This may help with some situations where avatars are persistently grey, though it will not help
|
||||
; in other situations (e.g. appearance baking failures where the avatar only appears as a cloud to others).
|
||||
ResendAppearanceUpdates = true
|
||||
ResendAppearanceUpdates = false
|
||||
|
||||
; Turning this on responds to CachedTexture packets to possibly avoid rebaking the avatar
|
||||
; on every login
|
||||
|
||||
@@ -36,7 +36,7 @@ ExternalHostName = "SYSTEMIP"
|
||||
; * This allows limiting the sizes of prims and the region prim count
|
||||
; *
|
||||
|
||||
; NonphysicalPrimMax = 256
|
||||
; NonPhysicalPrimMax = 256
|
||||
; PhysicalPrimMax = 64
|
||||
; ClampPrimSize = False
|
||||
; MaxPrims = 15000
|
||||
|
||||
@@ -135,6 +135,10 @@
|
||||
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"
|
||||
FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService"
|
||||
|
||||
; This inventory service will be used to initialize the user's inventory
|
||||
HGInventoryServicePlugin = "OpenSim.Services.HypergridService.dll:HGSuitcaseInventoryService"
|
||||
HGInventoryServiceConstructorArg = "HGInventoryService"
|
||||
|
||||
[MapImageService]
|
||||
LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user