Compare commits

...

65 Commits

Author SHA1 Message Date
Justin Clark-Casey (justincc)
ef39fcf465 Add basic regression test ThrottleTests.TestClientThrottleSetNoLimit 2014-10-08 20:52:17 +01:00
Justin Clark-Casey (justincc)
e8337d6a51 refactor: Move test clientstack setup code out of BasicCircuitTests into OpenSim.Tests.Common.ClientStackHelpers 2014-10-08 20:17:51 +01:00
Justin Clark-Casey (justincc)
90b31a2f54 Fix recent regression in "debug lludp throttles get" command that stopped it printing any information. Also fix max throttle displayed to be properly kbps 2014-10-08 00:46:24 +01:00
Justin Clark-Casey (justincc)
b40220885e minor: in "show server throttles", display unset if new client throttle value is not set rather than 0 2014-10-08 00:31:35 +01:00
Justin Clark-Casey (justincc)
649891a0d8 Add throttle-max option to "debug lludp throttles set" to allow runtime setting of default and existing client throttles.
Doesn't yet adjust until clients submit new throttle settings.
2014-10-07 18:34:08 +01:00
Justin Clark-Casey (justincc)
a529bc8f2a Change "debug lludp throttle *" commands to "debug lludp throttles" for consistency (and because I keep typing throttles).
This will still work with "debug lludp throttle" anyway.
2014-10-07 01:44:36 +01:00
Justin Clark-Casey (justincc)
16aca6ddbd small adjustment to commented out scene_throttle_max_bps and client_throttle_max_bps examples in OpenSimDefaults.ini
Make them actually reflect 20 mbit and 1.5 mbit respectively
2014-10-07 01:14:13 +01:00
Justin Clark-Casey (justincc)
38458d4be8 Change help text for client_throttle_max_bps in OpenSimDefaults.ini to state it is in bytes, not bits
This is the same as already done for scene_throttle_max_bps
Internally, the token buckets are in bytes and the other help text makes it clear that the number is bytes per second
(though with the wrong assumption that 1 mbit = 1024 * 1024 bits whereas 1 mbit = 1000 kbits = 1000000 bits)
2014-10-07 01:10:57 +01:00
Justin Clark-Casey (justincc)
9ee171f441 Fix console set and get of max scene rate. Was performing wrong calculation - throttle buckets are set in bytes, not bits 2014-10-07 01:08:22 +01:00
Justin Clark-Casey (justincc)
7ca4e2cb6f Eliminate 'max' throttle setting from server throttles report since this never applies. 2014-10-07 00:08:44 +01:00
Justin Clark-Casey (justincc)
523f0b8938 Allow "debug lludp throttle *" commands to work without a user name, in which case they apply to all users in the lludp server 2014-10-07 00:03:05 +01:00
Justin Clark-Casey (justincc)
4f04c0b560 minor: add apparant total to logging when client sets throttles 2014-10-06 23:39:52 +01:00
Justin Clark-Casey (justincc)
b7f78bf0f7 minor: fix bug in throttle logging where arguments were mismatched 2014-10-06 23:34:27 +01:00
Justin Clark-Casey (justincc)
5cb3b87b21 Add "debug lludp set scene-throttle-max <value>" console command to allow us to potentially set the scene max throttle on the fly. 2014-10-06 23:29:41 +01:00
Justin Clark-Casey (justincc)
97e25a0f45 Move information about "server agent rate" throttles into "show server throttles" command rather than "show throttles"
THis allows us to see the rates when no client is connected to the region.
2014-10-06 22:18:54 +01:00
Justin Clark-Casey (justincc)
026df644b5 Add "show server throttles" command for showing server specific information about throttles
This is separate from the user-oriented "show throttles" command since one will often only want to know about varying client throttle settings.
Currently displays max scene throttle and adaptive throttles config if set.
2014-10-06 20:34:17 +01:00
Justin Clark-Casey (justincc)
c3b1c72c33 refactor: Use simpler auto-implemented property for HttpPort in GridRegion 2014-10-03 01:22:25 +01:00
Justin Clark-Casey (justincc)
277dbb9acd minor: Remove compiler warning from GridRegion in IGridService 2014-10-03 00:43:04 +01:00
Justin Clark-Casey (justincc)
6cfebd66ec minor: remove compiler warning from OpenProfileClient 2014-10-03 00:38:48 +01:00
Justin Clark-Casey (justincc)
c9d7eb30db Add OutgoingPacketsQueuedCount clientstack stat.
This is the total of queued outgoing packets across all connections, as also seen in the "show queues" command.
Gives some early indication of whether the simulator can't send all outgoing packets fast enough.
Though then one would want to check that this isn't due to a few bad client connections.
2014-10-02 23:49:37 +01:00
Justin Clark-Casey (justincc)
db5de62394 minor: Remove compiler warnings from unused fields in TokenBucket 2014-10-02 23:20:39 +01:00
Justin Clark-Casey (justincc)
5c3f33bb48 refactor: Move LLUDPServer console commands into their own class. 2014-10-02 23:18:21 +01:00
Justin Clark-Casey (justincc)
d50f85dff6 minor: Comment out received seed caps request logging for now 2014-10-02 22:37:45 +01:00
BlueWall
b7abcd28e1 Fix key name in example Regions.ini file 2014-10-02 22:37:34 +01:00
AliciaRaven
d53703362e When a prim is bought through BuySellModule, the click action is not changed back from buy object. This means that after the object is bought, it still appears as if for sale which can be confusing. This sets it back to touch, the default after sale.
Signed-off-by: BlueWall <jamesh@bluewallgroup.com>
2014-10-02 22:37:25 +01:00
Justin Clark-Casey (justincc)
4e1f2ba1f4 Make "generate map" console command also trigger upload to maptiles as well as asset generation without performing tile generation twice. 2014-10-02 22:37:11 +01:00
Diva Canto
51951682e7 Fixed a hard-to-run-into bug in groups: at the time of creation of a group, the OwnerRoleID in the groups table was inconsistent with the roleID in the roles table. OpenSim core was not running into this bug, but 3rd party modules (like Wifi) were. 2014-10-02 22:36:23 +01:00
Justin Clark-Casey (justincc)
c5c387e838 refactor: rename "debug lludp throttle status" to "debug lludp throttle get" to match set command 2014-09-30 18:43:02 +01:00
Justin Clark-Casey (justincc)
f7fef5bc3b Add "debug lludp throttle set" command to allow setting of parameters at runtime
Can currently only set adaptive true|false, where adaptive = false
2014-09-30 18:41:04 +01:00
Justin Clark-Casey (justincc)
8e5a62c8e7 Add "debug lludp throttle status" command to return status information about a client's throttle (currently just whether adaptive is enabled). 2014-09-30 18:18:34 +01:00
Justin Clark-Casey (justincc)
ad15e06611 Add "debug lludp throttle log <level> <avatar-first-name> <avatar-last-name>" to control extra throttle related debug logging. 2014-09-30 18:12:51 +01:00
Justin Clark-Casey (justincc)
319c51b8a8 Don't unnecessarily remove from backup objects that were not directly attached from the scene.
These are never in region backup in the first place since recent 11830c43
Extend regression test to check backup status.
2014-09-29 23:18:18 +01:00
Justin Clark-Casey (justincc)
11830c4363 Do not add attachments to the region scene object backup list.
Attachment persistence is not handled in this way and this just results in a load of busy work until a check in each SOG terminates a backup check for attachments anyway.
2014-09-27 01:02:27 +01:00
Justin Clark-Casey (justincc)
2eece5b009 Move expired objects cleaning trigger to the maintenance thread of a region rather than it's main scene loop.
[Startup] default setting UpdateTempCleaningEveryNFrames becomes UpdateTempCleaningEveryNSeconds.
Default becomes 180s instead of effective 182s (which would also vary with any changes in frame time or extra long frames)
2014-09-27 00:30:42 +01:00
Roger Kirkman
528a7f3352 Add missing HGInventoryService responsible for creating My Suitcase to StandaloneHypergrid.ini 2014-09-27 00:30:33 +01:00
Justin Clark-Casey (justincc)
c02b33d592 Eliminate a few unnecessary calculations in the maintenance loop.
Also uses wait event instead of sleep for periodicity control.
2014-09-26 21:29:27 +01:00
Justin Clark-Casey (justincc)
07c6630c1c Fix recent minor regression where the default frame time wasn't being set if there was no startup config section.
Caused some regression tests to fail.
2014-09-26 21:22:41 +01:00
Justin Clark-Casey (justincc)
cfc95afc3d If Bullet is running on its own thread, use a reset event to control timing rather than a sleep.
In theory, there should be no difference between these mechanisms.
However, on at least Mono 3.2.8 waiting via an event appears to be much more accurate.
2014-09-26 20:56:22 +01:00
Justin Clark-Casey (justincc)
85e04198fe Improve frame time stability by taking a few unnecessary repeated calculations out of the main scene loop.
Also uses a wait event to sleep rather than a Thread.Sleep to allow the loop to be interrupted in a more controlled manner when necessary.
2014-09-26 20:05:22 +01:00
Justin Clark-Casey (justincc)
1256d643be Add "debug lludp data out" console command for logging outgoing data just before it's put on the wire.
Unlike "debug lludp packet" which logs at the point where OpenSim first asks the clientstack to send a certain outgoing packet, this logs immediately before the actual send.
For low-level debugging purposes.
2014-09-24 23:42:57 +01:00
Justin Clark-Casey (justincc)
f2715a5a2f Update libopenmetaverse to 0f4b361.
Primarily to get a small message logging improvement for pCampbot.
2014-09-24 23:22:05 +01:00
Justin Clark-Casey (justincc)
d2b8281df9 Add "debug lludp packet" command to pCampbot.
This allows one to log the packets received by a particular bot that are not duplicates of already received packets.
Similar to the OpenSimulator command at the same name but currently any positive level logs all received packets.
No facility yet for logging outgoing packets.
For debug purposes.
2014-09-24 23:03:39 +01:00
Justin Clark-Casey (justincc)
6b05cfce25 Remove an unnecessary check at the bottom of Scene.CloseAgent()
At this point sp != null so no check required.
2014-09-24 00:45:19 +01:00
Justin Clark-Casey (justincc)
0448935b1b Set appearance refresh to false by default.
This setting was originally added some time ago to deal with issues where appearance was not received properly by all users.
However, it does not scale well with large numbers of agents.
Disabling to see if the original problem has abated or whether this will have to be tackled in another way.
2014-09-23 18:11:05 +01:00
Justin Clark-Casey (justincc)
bc01c27c8a Replace two connecting bots state booleans in pCampbot with a single state machine.
Also adds "show status" command to pCampbot that currently just shows bot connecting state
2014-09-23 17:28:02 +01:00
Justin Clark-Casey (justincc)
95aade7fdb When osNpcMoveToTarget() is called for a sitting avatar then silently do nothing rather than throwing an error.
Resolves http://opensimulator.org/mantis/view.php?id=7311
2014-09-23 17:27:27 +01:00
Justin Clark-Casey (justincc)
7ff27e32bc Add cinderblocks and bobshaffer2 to contributors. 2014-09-23 17:27:22 +01:00
Justin Clark-Casey (justincc)
89c153ca7f Fix issues where setting llSetTextureAnim(FALSE... did not work properly).
I ended up amalgamating patches from http://opensimulator.org/mantis/view.php?id=7313 and http://opensimulator.org/mantis/view.php?id=7318
Thanks a lot to both bobshaffer2 and cinderblocks.
2014-09-23 17:27:18 +01:00
Justin Clark-Casey (justincc)
a6c79fe956 Fix regression from recent a02dae5 where stand positions are no longer correct when a sit target is specified.
Adjusts stand position using just avatar position relative to the root prim instead.
Fixes http://opensimulator.org/mantis/view.php?id=7315 and preserves previous fix for http://opensimulator.org/mantis/view.php?id=7299
2014-09-23 17:27:13 +01:00
Justin Clark-Casey (justincc)
1e5c3f26f0 Make BulletSim thread be ThreadPriority.Highest if running
Will only effect Windows or mono with a patch such as https://gist.github.com/justincc/31e52218d098529b4696 applied
For test purposes
2014-09-16 18:32:36 +01:00
Justin Clark-Casey (justincc)
e6df61fbe9 Make outboudn and packet inbox handling threads highest priority.
Will only have any affect under Windows or mono with a patch such as https://gist.github.com/justincc/31e52218d098529b4696 (not recommended) applied.
For assessment purposes.
2014-09-16 18:27:08 +01:00
Justin Clark-Casey (justincc)
5991a98d80 Set ThreadPriority on main scene thread to highest.
This will only have an effect on Windows systems or mono with the (not recommended) mono-3.2.8 debug patch https://gist.github.com/justincc/31e52218d098529b4696 applied
2014-09-16 18:17:05 +01:00
Justin Clark-Casey (justincc)
c4ed67aeee Make proper fix for last commit wrt Mantis 7317 by replacing disallowed c char and not literal 'c' 2014-09-09 18:55:38 +01:00
Justin Clark-Casey (justincc)
258de1f17f For stat names containing periods, replace with '#' rather than throw exception
In relation to http://opensimulator.org/mantis/view.php?id=7317
2014-09-09 18:52:07 +01:00
Justin Clark-Casey (justincc)
f8fa76c09f Add loglevel to jobengine that can be controlled via "debug jobengine loglevel <level>".
Defaults to 0
Level 1 currently does verbose logging about every queued and processed job.
2014-09-09 18:42:02 +01:00
Justin Clark-Casey (justincc)
0b7736b861 Temporarily add root agent rez attachments work to job engine if it is running rather than as a fire and forget.
Experiment to see if serializing attachment rez and send initial data jobs improves other parts of sim performance.
2014-09-09 18:26:41 +01:00
Justin Clark-Casey (justincc)
a086adf427 Add experimental job engine to see if queueing some existing async work during root agent entry to a region improves perf rather than always attempting to execute everything concurrently
Job engine is controlled via "debug jobengine start|stop|status".
Can only currently be enabled and disabled dynamically at runtime.
Currently only applies to code sending initial region data (objects, other avatar data) to a client.
2014-09-09 18:14:56 +01:00
Justin Clark-Casey (justincc)
e76cc35409 Merge branch 'master' into ghosts 2014-09-09 17:22:09 +01:00
Justin Clark-Casey (justincc)
a129e9e351 Merge branch 'master' into ghosts 2014-09-03 00:26:53 +01:00
Justin Clark-Casey (justincc)
3c7eacf39b Fix recent regression from 473c5594 where camera started to judder on moving vehicles.
Other parts of OpenSimulator are relying on SP.Velocity == 0 for vehicles.
So add and use SP.GetWorldVelocity() instead when we need vehicle velocity, along the same lines as existing SP.GetWorldRotation()
2014-09-02 23:35:03 +01:00
Justin Clark-Casey (justincc)
cd6f73392a Reinsert OpenMetaverse.dll from commit fbdf507 from an accidental replace in f1f935e
This only affected pCampbot.
2014-09-02 19:00:14 +01:00
Justin Clark-Casey (justincc)
1559a3a099 Merge branch 'master' into ghosts 2014-09-02 18:34:54 +01:00
Justin Clark-Casey (justincc)
6520065625 Merge branch 'master' into ghosts 2014-08-26 18:52:50 +01:00
Justin Clark-Casey (justincc)
693bfdc0fb Merge branch 'master' into ghosts 2014-08-26 18:26:27 +01:00
Justin Clark-Casey (justincc)
f3eaa6d81e Temporary hack to disable av to av collisions in bulletsim.
Need to do this for a test.  Final implementation will be properly controlled through a property.
2014-08-26 18:17:09 +01:00
46 changed files with 1874 additions and 636 deletions

View File

@@ -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)

View File

@@ -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;

View 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);
}
}
}
}

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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))
{

View File

@@ -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>
@@ -348,6 +415,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
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);
}
// Make sure none of the throttles are set below our packet MTU,
// otherwise a throttle could become permanently clogged
resend = Math.Max(resend, LLUDPServer.MTU);
@@ -365,8 +440,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;

View File

@@ -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();

View File

@@ -0,0 +1,694 @@
/*
* 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 throttles log",
"debug lludp throttles 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 throttles get",
"debug lludp throttles get [<avatar-first-name> <avatar-last-name>]",
"Return debug settings for throttles.",
HandleThrottleGetCommand);
m_console.Commands.AddCommand(
"Debug",
false,
"debug lludp throttles set",
"debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]",
"Set a throttle parameter for the given client.",
"Avaiable parameters are:\n"
+ "adaptive - true/false, control adaptive throttle setting\n"
+ "throttle-max - kbps, control maximum throttle setting for current and future clients\n",
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);
long maxSceneDripRate = m_udpServer.MaxTotalDripRate;
cdl.AddRow(
"Max scene throttle",
maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
int maxClientDripRate = m_udpServer.ThrottleRates.Total;
cdl.AddRow(
"Max new client throttle",
maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 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 throttles 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 throttles 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;
}
});
}
else if (param == "throttle-max")
{
int newValue;
if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
return;
int newThrottleMaxKbps = newValue * 1000 / 8;
m_udpServer.ThrottleRates.Total = newThrottleMaxKbps;
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.RequestedDripRate = newThrottleMaxKbps;
udpClient.FlowThrottle.MaxDripRate = newThrottleMaxKbps;
}
});
}
}
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 throttles 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))
{
m_console.OutputFormat(
"Status for {0} ({1}) in {2}",
sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
ConsoleDisplayList cdl = new ConsoleDisplayList();
cdl.AddRow("Adaptive throttle", udpClient.FlowThrottle.Enabled);
cdl.AddRow("Max throttle", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000));
m_console.Output(cdl.ToString());
}
});
}
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);
}
}
}

View File

@@ -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)
{

View File

@@ -217,6 +217,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void ProcessRequests()
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
try
{
while (IsRunning || m_requestQueue.Count > 0)

View File

@@ -47,7 +47,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public class BasicCircuitTests : OpenSimTestCase
{
private Scene m_scene;
private TestLLUDPServer m_udpServer;
[TestFixtureSetUp]
public void FixtureInit()
@@ -90,55 +89,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
return onp;
}
private void AddUdpServer()
{
AddUdpServer(new IniConfigSource());
}
private void AddUdpServer(IniConfigSource configSource)
{
uint port = 0;
AgentCircuitManager acm = m_scene.AuthenticateHandler;
m_udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm);
m_udpServer.AddScene(m_scene);
}
/// <summary>
/// Used by tests that aren't testing this stage.
/// </summary>
private ScenePresence AddClient()
{
UUID myAgentUuid = TestHelpers.ParseTail(0x1);
UUID mySessionUuid = TestHelpers.ParseTail(0x2);
uint myCircuitCode = 123456;
IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
UseCircuitCodePacket uccp = new UseCircuitCodePacket();
UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
= new UseCircuitCodePacket.CircuitCodeBlock();
uccpCcBlock.Code = myCircuitCode;
uccpCcBlock.ID = myAgentUuid;
uccpCcBlock.SessionID = mySessionUuid;
uccp.CircuitCode = uccpCcBlock;
byte[] uccpBytes = uccp.ToBytes();
UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length);
upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
AgentCircuitData acd = new AgentCircuitData();
acd.AgentID = myAgentUuid;
acd.SessionID = mySessionUuid;
m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
m_udpServer.PacketReceived(upb);
return m_scene.GetScenePresence(myAgentUuid);
}
/// <summary>
/// Test adding a client to the stack
/// </summary>
@@ -148,7 +98,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
AddUdpServer();
TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene);
UUID myAgentUuid = TestHelpers.ParseTail(0x1);
UUID mySessionUuid = TestHelpers.ParseTail(0x2);
@@ -169,7 +119,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
m_udpServer.PacketReceived(upb);
udpServer.PacketReceived(upb);
// Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet
Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null);
@@ -180,15 +130,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
m_udpServer.PacketReceived(upb);
udpServer.PacketReceived(upb);
// Should succeed now
ScenePresence sp = m_scene.GetScenePresence(myAgentUuid);
Assert.That(sp.UUID, Is.EqualTo(myAgentUuid));
Assert.That(m_udpServer.PacketsSent.Count, Is.EqualTo(1));
Assert.That(udpServer.PacketsSent.Count, Is.EqualTo(1));
Packet packet = m_udpServer.PacketsSent[0];
Packet packet = udpServer.PacketsSent[0];
Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket)));
PacketAckPacket ackPacket = packet as PacketAckPacket;
@@ -200,15 +150,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public void TestLogoutClientDueToAck()
{
TestHelpers.InMethod();
TestHelpers.EnableLogging();
// TestHelpers.EnableLogging();
IniConfigSource ics = new IniConfigSource();
IConfig config = ics.AddConfig("ClientStack.LindenUDP");
config.Set("AckTimeout", -1);
AddUdpServer(ics);
TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics);
ScenePresence sp = AddClient();
m_udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
ScenePresence sp
= ClientStackHelpers.AddChildClient(
m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
Assert.That(spAfterAckTimeout, Is.Null);

View File

@@ -0,0 +1,106 @@
/*
* 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 NUnit.Framework;
using OpenMetaverse.Packets;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Tests.Common;
namespace OpenSim.Region.ClientStack.LindenUDP.Tests
{
[TestFixture]
public class ThrottleTests : OpenSimTestCase
{
[TestFixtureSetUp]
public void FixtureInit()
{
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
}
[TestFixtureTearDown]
public void TearDown()
{
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
// threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
// tests really shouldn't).
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
}
[Test]
public void TestClientThrottleSetNoLimit()
{
TestHelpers.InMethod();
TestHelpers.EnableLogging();
Scene scene = new SceneHelpers().SetupScene();
TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
ScenePresence sp
= ClientStackHelpers.AddChildClient(
scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
// udpClient.ThrottleDebugLevel = 1;
byte[] throttles = new byte[28];
float resendBits = 10000;
float landBits = 20000;
float windBits = 30000;
float cloudBits = 40000;
float taskBits = 50000;
float textureBits = 60000;
float assetBits = 70000;
Array.Copy(BitConverter.GetBytes(resendBits), 0, throttles, 0, 4);
Array.Copy(BitConverter.GetBytes(landBits), 0, throttles, 4, 4);
Array.Copy(BitConverter.GetBytes(windBits), 0, throttles, 8, 4);
Array.Copy(BitConverter.GetBytes(cloudBits), 0, throttles, 12, 4);
Array.Copy(BitConverter.GetBytes(taskBits), 0, throttles, 16, 4);
Array.Copy(BitConverter.GetBytes(textureBits), 0, throttles, 20, 4);
Array.Copy(BitConverter.GetBytes(assetBits), 0, throttles, 24, 4);
// Console.WriteLine(BitConverter.ToString(throttles));
udpClient.SetThrottles(throttles);
ClientInfo ci = udpClient.GetClientInfo();
// We expect this to be lower because of the minimum bound set by MTU
float totalBits = LLUDPServer.MTU * 8 + landBits + windBits + cloudBits + taskBits + textureBits + assetBits;
Assert.AreEqual(LLUDPServer.MTU, ci.resendThrottle);
Assert.AreEqual(landBits / 8, ci.landThrottle);
Assert.AreEqual(windBits / 8, ci.windThrottle);
Assert.AreEqual(cloudBits / 8, ci.cloudThrottle);
Assert.AreEqual(taskBits / 8, ci.taskThrottle);
Assert.AreEqual(textureBits / 8, ci.textureThrottle);
Assert.AreEqual(assetBits / 8, ci.assetThrottle);
Assert.AreEqual(totalBits / 8, ci.totalThrottle);
}
}
}

View File

@@ -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>

View File

@@ -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();

View File

@@ -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));

View File

@@ -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.

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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();

View 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);
}
}

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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}",

View File

@@ -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(

View File

@@ -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

View File

@@ -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,

View File

@@ -300,7 +300,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
public void TestMove()
{
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
// TestHelpers.EnableLogging();
SetUpScene();

View File

@@ -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
{

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* 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.Net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenSim.Framework;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Tests.Common
{
/// <summary>
/// This class adds full UDP client classes and associated scene presence to scene.
/// </summary>
/// <remarks>
/// This is used for testing client stack code. For testing other code, use SceneHelper methods instead since
/// they operate without the burden of setting up UDP structures which should be unnecessary for testing scene
/// code.
/// </remarks>
public static class ClientStackHelpers
{
public static ScenePresence AddChildClient(
Scene scene, LLUDPServer udpServer, UUID agentId, UUID sessionId, uint circuitCode)
{
IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
UseCircuitCodePacket uccp = new UseCircuitCodePacket();
UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
= new UseCircuitCodePacket.CircuitCodeBlock();
uccpCcBlock.Code = circuitCode;
uccpCcBlock.ID = agentId;
uccpCcBlock.SessionID = sessionId;
uccp.CircuitCode = uccpCcBlock;
byte[] uccpBytes = uccp.ToBytes();
UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length);
upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
AgentCircuitData acd = new AgentCircuitData();
acd.AgentID = agentId;
acd.SessionID = sessionId;
scene.AuthenticateHandler.AddNewCircuit(circuitCode, acd);
udpServer.PacketReceived(upb);
return scene.GetScenePresence(agentId);
}
public static TestLLUDPServer AddUdpServer(Scene scene)
{
return AddUdpServer(scene, new IniConfigSource());
}
public static TestLLUDPServer AddUdpServer(Scene scene, IniConfigSource configSource)
{
uint port = 0;
AgentCircuitManager acm = scene.AuthenticateHandler;
TestLLUDPServer udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm);
udpServer.AddScene(scene);
return udpServer;
}
}
}

View File

@@ -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;
}

View File

@@ -32,8 +32,9 @@ using System.Net.Sockets;
using Nini.Config;
using OpenMetaverse.Packets;
using OpenSim.Framework;
using OpenSim.Region.ClientStack.LindenUDP;
namespace OpenSim.Region.ClientStack.LindenUDP.Tests
namespace OpenSim.Tests.Common
{
/// <summary>
/// This class enables regression testing of the LLUDPServer by allowing us to intercept outgoing data.

View File

@@ -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);
}
}
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -2765,6 +2765,7 @@
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Region.CoreModules"/>
<Reference name="OpenSim.Region.ClientStack.LindenCaps"/>
<Reference name="OpenSim.Region.ClientStack.LindenUDP"/>
<Reference name="OpenSim.Region.Framework"/>
<Reference name="OpenSim.Region.OptionalModules"/>
<Reference name="OpenSim.Region.Physics.Manager"/>