Merge branch 'master' into careminster
Conflicts: OpenSim/Region/Application/OpenSimBase.cs OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs OpenSim/Region/Framework/Scenes/Scene.cs OpenSim/Region/Framework/Scenes/ScenePresence.csavinationmerge
commit
ad1b2902f2
|
@ -34,142 +34,6 @@ using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Monitoring
|
namespace OpenSim.Framework.Monitoring
|
||||||
{
|
{
|
||||||
// Create a time histogram of events. The histogram is built in a wrap-around
|
|
||||||
// array of equally distributed buckets.
|
|
||||||
// For instance, a minute long histogram of second sized buckets would be:
|
|
||||||
// new EventHistogram(60, 1000)
|
|
||||||
public class EventHistogram
|
|
||||||
{
|
|
||||||
private int m_timeBase;
|
|
||||||
private int m_numBuckets;
|
|
||||||
private int m_bucketMilliseconds;
|
|
||||||
private int m_lastBucket;
|
|
||||||
private int m_totalHistogramMilliseconds;
|
|
||||||
private long[] m_histogram;
|
|
||||||
private object histoLock = new object();
|
|
||||||
|
|
||||||
public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
|
|
||||||
{
|
|
||||||
m_numBuckets = numberOfBuckets;
|
|
||||||
m_bucketMilliseconds = millisecondsPerBucket;
|
|
||||||
m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
|
|
||||||
|
|
||||||
m_histogram = new long[m_numBuckets];
|
|
||||||
Zero();
|
|
||||||
m_lastBucket = 0;
|
|
||||||
m_timeBase = Util.EnvironmentTickCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Event()
|
|
||||||
{
|
|
||||||
this.Event(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record an event at time 'now' in the histogram.
|
|
||||||
public void Event(int cnt)
|
|
||||||
{
|
|
||||||
lock (histoLock)
|
|
||||||
{
|
|
||||||
// The time as displaced from the base of the histogram
|
|
||||||
int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
|
|
||||||
|
|
||||||
// If more than the total time of the histogram, we just start over
|
|
||||||
if (bucketTime > m_totalHistogramMilliseconds)
|
|
||||||
{
|
|
||||||
Zero();
|
|
||||||
m_lastBucket = 0;
|
|
||||||
m_timeBase = Util.EnvironmentTickCount();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// To which bucket should we add this event?
|
|
||||||
int bucket = bucketTime / m_bucketMilliseconds;
|
|
||||||
|
|
||||||
// Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
|
|
||||||
while (bucket != m_lastBucket)
|
|
||||||
{
|
|
||||||
// Zero from just after the last bucket to the new bucket or the end
|
|
||||||
for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
|
|
||||||
{
|
|
||||||
m_histogram[jj] = 0;
|
|
||||||
}
|
|
||||||
m_lastBucket = bucket;
|
|
||||||
// If the new bucket is off the end, wrap around to the beginning
|
|
||||||
if (bucket > m_numBuckets)
|
|
||||||
{
|
|
||||||
bucket -= m_numBuckets;
|
|
||||||
m_lastBucket = 0;
|
|
||||||
m_histogram[m_lastBucket] = 0;
|
|
||||||
m_timeBase += m_totalHistogramMilliseconds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_histogram[m_lastBucket] += cnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a copy of the current histogram
|
|
||||||
public long[] GetHistogram()
|
|
||||||
{
|
|
||||||
long[] ret = new long[m_numBuckets];
|
|
||||||
lock (histoLock)
|
|
||||||
{
|
|
||||||
int indx = m_lastBucket + 1;
|
|
||||||
for (int ii = 0; ii < m_numBuckets; ii++, indx++)
|
|
||||||
{
|
|
||||||
if (indx >= m_numBuckets)
|
|
||||||
indx = 0;
|
|
||||||
ret[ii] = m_histogram[indx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OSDMap GetHistogramAsOSDMap()
|
|
||||||
{
|
|
||||||
OSDMap ret = new OSDMap();
|
|
||||||
|
|
||||||
ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
|
|
||||||
ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
|
|
||||||
ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
|
|
||||||
|
|
||||||
// Compute a number for the first bucket in the histogram.
|
|
||||||
// This will allow readers to know how this histogram relates to any previously read histogram.
|
|
||||||
int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
|
|
||||||
ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
|
|
||||||
|
|
||||||
ret.Add("Values", GetHistogramAsOSDArray());
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
// Get a copy of the current histogram
|
|
||||||
public OSDArray GetHistogramAsOSDArray()
|
|
||||||
{
|
|
||||||
OSDArray ret = new OSDArray(m_numBuckets);
|
|
||||||
lock (histoLock)
|
|
||||||
{
|
|
||||||
int indx = m_lastBucket + 1;
|
|
||||||
for (int ii = 0; ii < m_numBuckets; ii++, indx++)
|
|
||||||
{
|
|
||||||
if (indx >= m_numBuckets)
|
|
||||||
indx = 0;
|
|
||||||
ret[ii] = OSD.FromLong(m_histogram[indx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zero out the histogram
|
|
||||||
public void Zero()
|
|
||||||
{
|
|
||||||
lock (histoLock)
|
|
||||||
{
|
|
||||||
for (int ii = 0; ii < m_numBuckets; ii++)
|
|
||||||
m_histogram[ii] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A statistic that wraps a counter.
|
// A statistic that wraps a counter.
|
||||||
// Built this way mostly so histograms and history can be created.
|
// Built this way mostly so histograms and history can be created.
|
||||||
public class CounterStat : Stat
|
public class CounterStat : Stat
|
||||||
|
@ -236,12 +100,18 @@ public class CounterStat : Stat
|
||||||
// If there are any histograms, add a new field that is an array of histograms as OSDMaps
|
// If there are any histograms, add a new field that is an array of histograms as OSDMaps
|
||||||
if (m_histograms.Count > 0)
|
if (m_histograms.Count > 0)
|
||||||
{
|
{
|
||||||
OSDArray histos = new OSDArray();
|
lock (counterLock)
|
||||||
foreach (EventHistogram histo in m_histograms.Values)
|
|
||||||
{
|
{
|
||||||
histos.Add(histo.GetHistogramAsOSDMap());
|
if (m_histograms.Count > 0)
|
||||||
|
{
|
||||||
|
OSDArray histos = new OSDArray();
|
||||||
|
foreach (EventHistogram histo in m_histograms.Values)
|
||||||
|
{
|
||||||
|
histos.Add(histo.GetHistogramAsOSDMap());
|
||||||
|
}
|
||||||
|
map.Add("Histograms", histos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
map.Add("Histograms", histos);
|
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* 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.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
|
namespace OpenSim.Framework.Monitoring
|
||||||
|
{
|
||||||
|
// Create a time histogram of events. The histogram is built in a wrap-around
|
||||||
|
// array of equally distributed buckets.
|
||||||
|
// For instance, a minute long histogram of second sized buckets would be:
|
||||||
|
// new EventHistogram(60, 1000)
|
||||||
|
public class EventHistogram
|
||||||
|
{
|
||||||
|
private int m_timeBase;
|
||||||
|
private int m_numBuckets;
|
||||||
|
private int m_bucketMilliseconds;
|
||||||
|
private int m_lastBucket;
|
||||||
|
private int m_totalHistogramMilliseconds;
|
||||||
|
private long[] m_histogram;
|
||||||
|
private object histoLock = new object();
|
||||||
|
|
||||||
|
public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
|
||||||
|
{
|
||||||
|
m_numBuckets = numberOfBuckets;
|
||||||
|
m_bucketMilliseconds = millisecondsPerBucket;
|
||||||
|
m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
|
||||||
|
|
||||||
|
m_histogram = new long[m_numBuckets];
|
||||||
|
Zero();
|
||||||
|
m_lastBucket = 0;
|
||||||
|
m_timeBase = Util.EnvironmentTickCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Event()
|
||||||
|
{
|
||||||
|
this.Event(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record an event at time 'now' in the histogram.
|
||||||
|
public void Event(int cnt)
|
||||||
|
{
|
||||||
|
lock (histoLock)
|
||||||
|
{
|
||||||
|
// The time as displaced from the base of the histogram
|
||||||
|
int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
|
||||||
|
|
||||||
|
// If more than the total time of the histogram, we just start over
|
||||||
|
if (bucketTime > m_totalHistogramMilliseconds)
|
||||||
|
{
|
||||||
|
Zero();
|
||||||
|
m_lastBucket = 0;
|
||||||
|
m_timeBase = Util.EnvironmentTickCount();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// To which bucket should we add this event?
|
||||||
|
int bucket = bucketTime / m_bucketMilliseconds;
|
||||||
|
|
||||||
|
// Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
|
||||||
|
while (bucket != m_lastBucket)
|
||||||
|
{
|
||||||
|
// Zero from just after the last bucket to the new bucket or the end
|
||||||
|
for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
|
||||||
|
{
|
||||||
|
m_histogram[jj] = 0;
|
||||||
|
}
|
||||||
|
m_lastBucket = bucket;
|
||||||
|
// If the new bucket is off the end, wrap around to the beginning
|
||||||
|
if (bucket > m_numBuckets)
|
||||||
|
{
|
||||||
|
bucket -= m_numBuckets;
|
||||||
|
m_lastBucket = 0;
|
||||||
|
m_histogram[m_lastBucket] = 0;
|
||||||
|
m_timeBase += m_totalHistogramMilliseconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_histogram[m_lastBucket] += cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a copy of the current histogram
|
||||||
|
public long[] GetHistogram()
|
||||||
|
{
|
||||||
|
long[] ret = new long[m_numBuckets];
|
||||||
|
lock (histoLock)
|
||||||
|
{
|
||||||
|
int indx = m_lastBucket + 1;
|
||||||
|
for (int ii = 0; ii < m_numBuckets; ii++, indx++)
|
||||||
|
{
|
||||||
|
if (indx >= m_numBuckets)
|
||||||
|
indx = 0;
|
||||||
|
ret[ii] = m_histogram[indx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OSDMap GetHistogramAsOSDMap()
|
||||||
|
{
|
||||||
|
OSDMap ret = new OSDMap();
|
||||||
|
|
||||||
|
ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
|
||||||
|
ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
|
||||||
|
ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
|
||||||
|
|
||||||
|
// Compute a number for the first bucket in the histogram.
|
||||||
|
// This will allow readers to know how this histogram relates to any previously read histogram.
|
||||||
|
int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
|
||||||
|
ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
|
||||||
|
|
||||||
|
ret.Add("Values", GetHistogramAsOSDArray());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// Get a copy of the current histogram
|
||||||
|
public OSDArray GetHistogramAsOSDArray()
|
||||||
|
{
|
||||||
|
OSDArray ret = new OSDArray(m_numBuckets);
|
||||||
|
lock (histoLock)
|
||||||
|
{
|
||||||
|
int indx = m_lastBucket + 1;
|
||||||
|
for (int ii = 0; ii < m_numBuckets; ii++, indx++)
|
||||||
|
{
|
||||||
|
if (indx >= m_numBuckets)
|
||||||
|
indx = 0;
|
||||||
|
ret[ii] = OSD.FromLong(m_histogram[indx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero out the histogram
|
||||||
|
public void Zero()
|
||||||
|
{
|
||||||
|
lock (histoLock)
|
||||||
|
{
|
||||||
|
for (int ii = 0; ii < m_numBuckets; ii++)
|
||||||
|
m_histogram[ii] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -29,6 +29,8 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Monitoring
|
namespace OpenSim.Framework.Monitoring
|
||||||
{
|
{
|
||||||
public class PercentageStat : Stat
|
public class PercentageStat : Stat
|
||||||
|
@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PercentageStat is a basic stat plus percent calc
|
||||||
|
public override OSDMap ToOSDMap()
|
||||||
|
{
|
||||||
|
// Get the foundational instance
|
||||||
|
OSDMap map = base.ToOSDMap();
|
||||||
|
|
||||||
|
map["StatType"] = "PercentageStat";
|
||||||
|
|
||||||
|
map.Add("Antecedent", OSD.FromLong(Antecedent));
|
||||||
|
map.Add("Consequent", OSD.FromLong(Consequent));
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -241,6 +241,8 @@ namespace OpenSim.Framework.Monitoring
|
||||||
public virtual OSDMap ToOSDMap()
|
public virtual OSDMap ToOSDMap()
|
||||||
{
|
{
|
||||||
OSDMap ret = new OSDMap();
|
OSDMap ret = new OSDMap();
|
||||||
|
ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
|
||||||
|
|
||||||
ret.Add("Category", OSD.FromString(Category));
|
ret.Add("Category", OSD.FromString(Category));
|
||||||
ret.Add("Container", OSD.FromString(Container));
|
ret.Add("Container", OSD.FromString(Container));
|
||||||
ret.Add("ShortName", OSD.FromString(ShortName));
|
ret.Add("ShortName", OSD.FromString(ShortName));
|
||||||
|
@ -248,26 +250,36 @@ namespace OpenSim.Framework.Monitoring
|
||||||
ret.Add("Description", OSD.FromString(Description));
|
ret.Add("Description", OSD.FromString(Description));
|
||||||
ret.Add("UnitName", OSD.FromString(UnitName));
|
ret.Add("UnitName", OSD.FromString(UnitName));
|
||||||
ret.Add("Value", OSD.FromReal(Value));
|
ret.Add("Value", OSD.FromReal(Value));
|
||||||
ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
|
|
||||||
|
double lastChangeOverTime, averageChangeOverTime;
|
||||||
|
if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
|
||||||
|
{
|
||||||
|
ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime));
|
||||||
|
ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime));
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void AppendMeasuresOfInterest(StringBuilder sb)
|
// Compute the averages over time and return same.
|
||||||
|
// Return 'true' if averages were actually computed. 'false' if no average info.
|
||||||
|
public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime)
|
||||||
{
|
{
|
||||||
if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime)
|
bool ret = false;
|
||||||
== MeasuresOfInterest.AverageChangeOverTime)
|
lastChangeOverTime = 0;
|
||||||
|
averageChangeOverTime = 0;
|
||||||
|
|
||||||
|
if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
|
||||||
{
|
{
|
||||||
double totalChange = 0;
|
double totalChange = 0;
|
||||||
double lastChangeOverTime = 0;
|
|
||||||
double? penultimateSample = null;
|
double? penultimateSample = null;
|
||||||
double? lastSample = null;
|
double? lastSample = null;
|
||||||
|
|
||||||
lock (m_samples)
|
lock (m_samples)
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[STAT]: Samples for {0} are {1}",
|
// "[STAT]: Samples for {0} are {1}",
|
||||||
// Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
|
// Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
|
||||||
|
|
||||||
foreach (double s in m_samples)
|
foreach (double s in m_samples)
|
||||||
{
|
{
|
||||||
|
@ -280,13 +292,27 @@ namespace OpenSim.Framework.Monitoring
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastSample != null && penultimateSample != null)
|
if (lastSample != null && penultimateSample != null)
|
||||||
lastChangeOverTime
|
{
|
||||||
|
lastChangeOverTime
|
||||||
= ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
|
= ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
|
int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
|
||||||
|
|
||||||
double averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
|
averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AppendMeasuresOfInterest(StringBuilder sb)
|
||||||
|
{
|
||||||
|
double lastChangeOverTime = 0;
|
||||||
|
double averageChangeOverTime = 0;
|
||||||
|
|
||||||
|
if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
|
||||||
|
{
|
||||||
sb.AppendFormat(
|
sb.AppendFormat(
|
||||||
", {0:0.##}{1}/s, {2:0.##}{3}/s",
|
", {0:0.##}{1}/s, {2:0.##}{3}/s",
|
||||||
lastChangeOverTime,
|
lastChangeOverTime,
|
||||||
|
|
|
@ -26,10 +26,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
using OpenMetaverse.StructuredData;
|
using OpenMetaverse.StructuredData;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Monitoring
|
namespace OpenSim.Framework.Monitoring
|
||||||
|
@ -262,6 +264,41 @@ namespace OpenSim.Framework.Monitoring
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Hashtable HandleStatsRequest(Hashtable request)
|
||||||
|
{
|
||||||
|
Hashtable responsedata = new Hashtable();
|
||||||
|
string regpath = request["uri"].ToString();
|
||||||
|
int response_code = 200;
|
||||||
|
string contenttype = "text/json";
|
||||||
|
|
||||||
|
string pCategoryName = StatsManager.AllSubCommand;
|
||||||
|
string pContainerName = StatsManager.AllSubCommand;
|
||||||
|
string pStatName = StatsManager.AllSubCommand;
|
||||||
|
|
||||||
|
if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString();
|
||||||
|
if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString();
|
||||||
|
if (request.ContainsKey("stat")) pStatName = request["cat"].ToString();
|
||||||
|
|
||||||
|
string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString();
|
||||||
|
|
||||||
|
// If requestor wants it as a callback function, build response as a function rather than just the JSON string.
|
||||||
|
if (request.ContainsKey("callback"))
|
||||||
|
{
|
||||||
|
strOut = request["callback"].ToString() + "(" + strOut + ");";
|
||||||
|
}
|
||||||
|
|
||||||
|
// m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}",
|
||||||
|
// LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut);
|
||||||
|
|
||||||
|
responsedata["int_response_code"] = response_code;
|
||||||
|
responsedata["content_type"] = contenttype;
|
||||||
|
responsedata["keepalive"] = false;
|
||||||
|
responsedata["str_response_string"] = strOut;
|
||||||
|
responsedata["access_control_allow_origin"] = "*";
|
||||||
|
|
||||||
|
return responsedata;
|
||||||
|
}
|
||||||
|
|
||||||
// /// <summary>
|
// /// <summary>
|
||||||
// /// Start collecting statistics related to assets.
|
// /// Start collecting statistics related to assets.
|
||||||
// /// Should only be called once.
|
// /// Should only be called once.
|
||||||
|
|
|
@ -55,11 +55,18 @@ namespace OpenSim.Framework.Tests
|
||||||
Location TestLocation2 = new Location(1095216660736000);
|
Location TestLocation2 = new Location(1095216660736000);
|
||||||
Assert.That(TestLocation1 == TestLocation2);
|
Assert.That(TestLocation1 == TestLocation2);
|
||||||
|
|
||||||
|
Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor");
|
||||||
Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided");
|
Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided");
|
||||||
|
|
||||||
Assert.That(TestLocation2.RegionHandle == 1095216660736000,
|
Assert.That(TestLocation2.RegionHandle == 1095216660736000,
|
||||||
"Location RegionHandle Property didn't match regionhandle provided in constructor");
|
"Location RegionHandle Property didn't match regionhandle provided in constructor");
|
||||||
|
|
||||||
|
ulong RegionHandle = TestLocation1.RegionHandle;
|
||||||
|
Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor");
|
||||||
|
|
||||||
|
TestLocation2 = new Location(RegionHandle);
|
||||||
|
Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor");
|
||||||
|
|
||||||
|
|
||||||
TestLocation1 = new Location(255001, 256001);
|
TestLocation1 = new Location(255001, 256001);
|
||||||
TestLocation2 = new Location(1095216660736000);
|
TestLocation2 = new Location(1095216660736000);
|
||||||
|
|
|
@ -282,5 +282,87 @@ namespace OpenSim.Framework.Tests
|
||||||
String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i]));
|
String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FakeParcelIDTests()
|
||||||
|
{
|
||||||
|
byte[] hexBytes8 = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
|
||||||
|
byte[] hexBytes16 = {
|
||||||
|
0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
|
||||||
|
0x77, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f };
|
||||||
|
UInt64 var64Bit = (UInt64)0xfedcba9876543210;
|
||||||
|
|
||||||
|
//Region handle is for location 255000,256000.
|
||||||
|
ulong regionHandle1 = 1095216660736000;
|
||||||
|
uint x1 = 100;
|
||||||
|
uint y1 = 200;
|
||||||
|
uint z1 = 22;
|
||||||
|
ulong regionHandle2;
|
||||||
|
uint x2, y2, z2;
|
||||||
|
UUID fakeParcelID1, fakeParcelID2, uuid;
|
||||||
|
|
||||||
|
ulong bigInt64 = Util.BytesToUInt64Big(hexBytes8);
|
||||||
|
Assert.AreEqual(var64Bit, bigInt64,
|
||||||
|
"BytesToUint64Bit conversion of 8 bytes to UInt64 failed.");
|
||||||
|
|
||||||
|
//Test building and decoding using some typical input values
|
||||||
|
fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1);
|
||||||
|
Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2);
|
||||||
|
Assert.AreEqual(regionHandle1, regionHandle2,
|
||||||
|
"region handle decoded from FakeParcelID wth X/Y failed.");
|
||||||
|
Assert.AreEqual(x1, x2,
|
||||||
|
"X coordinate decoded from FakeParcelID wth X/Y failed.");
|
||||||
|
Assert.AreEqual(y1, y2,
|
||||||
|
"Y coordinate decoded from FakeParcelID wth X/Y failed.");
|
||||||
|
|
||||||
|
fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1, z1);
|
||||||
|
Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2);
|
||||||
|
Assert.AreEqual(regionHandle1, regionHandle2,
|
||||||
|
"region handle decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
Assert.AreEqual(x1, x2,
|
||||||
|
"X coordinate decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
Assert.AreEqual(y1, y2,
|
||||||
|
"Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
Assert.AreEqual(z1, z2,
|
||||||
|
"Z coordinate decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
|
||||||
|
//Do some more extreme tests to check the encoding and decoding
|
||||||
|
x1 = 0x55aa;
|
||||||
|
y1 = 0x9966;
|
||||||
|
z1 = 0x5a96;
|
||||||
|
|
||||||
|
fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1);
|
||||||
|
Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2);
|
||||||
|
Assert.AreEqual(var64Bit, regionHandle2,
|
||||||
|
"region handle decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
Assert.AreEqual(x1, x2,
|
||||||
|
"X coordinate decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
Assert.AreEqual(y1, y2,
|
||||||
|
"Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
|
||||||
|
fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1, z1);
|
||||||
|
Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2);
|
||||||
|
Assert.AreEqual(var64Bit, regionHandle2,
|
||||||
|
"region handle decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
Assert.AreEqual(x1, x2,
|
||||||
|
"X coordinate decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
Assert.AreEqual(y1, y2,
|
||||||
|
"Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
Assert.AreEqual(z1, z2,
|
||||||
|
"Z coordinate decoded from FakeParcelID with X/Y/Z failed.");
|
||||||
|
|
||||||
|
|
||||||
|
x1 = 64;
|
||||||
|
y1 = 192;
|
||||||
|
fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1);
|
||||||
|
Util.FakeParcelIDToGlobalPosition(fakeParcelID1, out x2, out y2);
|
||||||
|
Assert.AreEqual(255000+x1, x2,
|
||||||
|
"Global X coordinate decoded from regionHandle failed.");
|
||||||
|
Assert.AreEqual(256000+y1, y2,
|
||||||
|
"Global Y coordinate decoded from regionHandle failed.");
|
||||||
|
|
||||||
|
uuid = new UUID("00dd0700-00d1-0700-3800-000032000000");
|
||||||
|
Util.FakeParcelIDToGlobalPosition(uuid, out x2, out y2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1259,7 +1259,7 @@ namespace OpenSim.Framework
|
||||||
byte[] bytes =
|
byte[] bytes =
|
||||||
{
|
{
|
||||||
(byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
|
(byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
|
||||||
(byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56),
|
(byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
|
||||||
(byte)x, (byte)(x >> 8), 0, 0,
|
(byte)x, (byte)(x >> 8), 0, 0,
|
||||||
(byte)y, (byte)(y >> 8), 0, 0 };
|
(byte)y, (byte)(y >> 8), 0, 0 };
|
||||||
return new UUID(bytes, 0);
|
return new UUID(bytes, 0);
|
||||||
|
@ -1270,7 +1270,7 @@ namespace OpenSim.Framework
|
||||||
byte[] bytes =
|
byte[] bytes =
|
||||||
{
|
{
|
||||||
(byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
|
(byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
|
||||||
(byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56),
|
(byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
|
||||||
(byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8),
|
(byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8),
|
||||||
(byte)y, (byte)(y >> 8), 0, 0 };
|
(byte)y, (byte)(y >> 8), 0, 0 };
|
||||||
return new UUID(bytes, 0);
|
return new UUID(bytes, 0);
|
||||||
|
|
|
@ -142,19 +142,19 @@ namespace OpenSim
|
||||||
if (iocpThreads < iocpThreadsMin)
|
if (iocpThreads < iocpThreadsMin)
|
||||||
{
|
{
|
||||||
iocpThreads = iocpThreadsMin;
|
iocpThreads = iocpThreadsMin;
|
||||||
m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IO completion threads to {0}",iocpThreads);
|
m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IOCP threads to {0}",iocpThreads);
|
||||||
}
|
}
|
||||||
// Make sure we don't overallocate IOCP threads and thrash system resources
|
// Make sure we don't overallocate IOCP threads and thrash system resources
|
||||||
if ( iocpThreads > iocpThreadsMax )
|
if ( iocpThreads > iocpThreadsMax )
|
||||||
{
|
{
|
||||||
iocpThreads = iocpThreadsMax;
|
iocpThreads = iocpThreadsMax;
|
||||||
m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IO completion threads to {0}",iocpThreads);
|
m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IOCP completion threads to {0}",iocpThreads);
|
||||||
}
|
}
|
||||||
// set the resulting worker and IO completion thread counts back to ThreadPool
|
// set the resulting worker and IO completion thread counts back to ThreadPool
|
||||||
if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) )
|
if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) )
|
||||||
{
|
{
|
||||||
m_log.InfoFormat(
|
m_log.InfoFormat(
|
||||||
"[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IO completion threads",
|
"[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IOCP threads",
|
||||||
workerThreads, iocpThreads);
|
workerThreads, iocpThreads);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -172,6 +172,13 @@ namespace OpenSim
|
||||||
if (userStatsURI != String.Empty)
|
if (userStatsURI != String.Empty)
|
||||||
MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this));
|
MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this));
|
||||||
|
|
||||||
|
if (managedStatsURI != String.Empty)
|
||||||
|
{
|
||||||
|
string urlBase = String.Format("/{0}/", managedStatsURI);
|
||||||
|
MainServer.Instance.AddHTTPHandler(urlBase, StatsManager.HandleStatsRequest);
|
||||||
|
m_log.InfoFormat("[OPENSIM] Enabling remote managed stats fetch. URL = {0}", urlBase);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_console is RemoteConsole)
|
if (m_console is RemoteConsole)
|
||||||
{
|
{
|
||||||
if (m_consolePort == 0)
|
if (m_consolePort == 0)
|
||||||
|
@ -348,18 +355,6 @@ namespace OpenSim
|
||||||
m_console.Commands.AddCommand("Regions", false, "delete-region",
|
m_console.Commands.AddCommand("Regions", false, "delete-region",
|
||||||
"delete-region <name>",
|
"delete-region <name>",
|
||||||
"Delete a region from disk", RunCommand);
|
"Delete a region from disk", RunCommand);
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "modules list",
|
|
||||||
"modules list",
|
|
||||||
"List modules", HandleModules);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "modules load",
|
|
||||||
"modules load <name>",
|
|
||||||
"Load a module", HandleModules);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "modules unload",
|
|
||||||
"modules unload <name>",
|
|
||||||
"Unload a module", HandleModules);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ShutdownSpecific()
|
protected override void ShutdownSpecific()
|
||||||
|
@ -556,34 +551,6 @@ namespace OpenSim
|
||||||
regInfo.EstateSettings.Save();
|
regInfo.EstateSettings.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Load, Unload, and list Region modules in use
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="module"></param>
|
|
||||||
/// <param name="cmd"></param>
|
|
||||||
private void HandleModules(string module, string[] cmd)
|
|
||||||
{
|
|
||||||
List<string> args = new List<string>(cmd);
|
|
||||||
args.RemoveAt(0);
|
|
||||||
string[] cmdparams = args.ToArray();
|
|
||||||
|
|
||||||
if (cmdparams.Length > 0)
|
|
||||||
{
|
|
||||||
switch (cmdparams[0].ToLower())
|
|
||||||
{
|
|
||||||
case "list":
|
|
||||||
//TODO: Convert to new region modules
|
|
||||||
break;
|
|
||||||
case "unload":
|
|
||||||
//TODO: Convert to new region modules
|
|
||||||
break;
|
|
||||||
case "load":
|
|
||||||
//TODO: Convert to new region modules
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs commands issued by the server console from the operator
|
/// Runs commands issued by the server console from the operator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -75,6 +75,7 @@ namespace OpenSim
|
||||||
protected int proxyOffset = 0;
|
protected int proxyOffset = 0;
|
||||||
|
|
||||||
public string userStatsURI = String.Empty;
|
public string userStatsURI = String.Empty;
|
||||||
|
public string managedStatsURI = String.Empty;
|
||||||
|
|
||||||
protected bool m_autoCreateClientStack = true;
|
protected bool m_autoCreateClientStack = true;
|
||||||
|
|
||||||
|
@ -197,6 +198,8 @@ namespace OpenSim
|
||||||
|
|
||||||
string permissionModules = startupConfig.GetString("permissionmodules", "DefaultPermissionsModule");
|
string permissionModules = startupConfig.GetString("permissionmodules", "DefaultPermissionsModule");
|
||||||
m_permsModules = new List<string>(permissionModules.Split(','));
|
m_permsModules = new List<string>(permissionModules.Split(','));
|
||||||
|
|
||||||
|
managedStatsURI = startupConfig.GetString("ManagedStatsRemoteFetchURI", String.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the simulation data service
|
// Load the simulation data service
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||||
public void RemoveForClient()
|
public void RemoveForClient()
|
||||||
{
|
{
|
||||||
TestHelpers.InMethod();
|
TestHelpers.InMethod();
|
||||||
// log4net.Config.XmlConfigurator.Configure();
|
// TestHelpers.EnableLogging();
|
||||||
|
|
||||||
UUID spId = TestHelpers.ParseTail(0x1);
|
UUID spId = TestHelpers.ParseTail(0x1);
|
||||||
|
|
||||||
|
|
|
@ -337,6 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
private bool m_VelocityInterpolate = false;
|
private bool m_VelocityInterpolate = false;
|
||||||
private const uint MaxTransferBytesPerPacket = 600;
|
private const uint MaxTransferBytesPerPacket = 600;
|
||||||
|
|
||||||
|
private volatile bool m_justEditedTerrain = false;
|
||||||
|
|
||||||
/// <value>
|
/// <value>
|
||||||
/// List used in construction of data blocks for an object update packet. This is to stop us having to
|
/// List used in construction of data blocks for an object update packet. This is to stop us having to
|
||||||
|
@ -536,7 +537,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// We still perform a force close inside the sync lock since this is intended to attempt close where
|
// We still perform a force close inside the sync lock since this is intended to attempt close where
|
||||||
// there is some unidentified connection problem, not where we have issues due to deadlock
|
// there is some unidentified connection problem, not where we have issues due to deadlock
|
||||||
if (!IsActive && !force)
|
if (!IsActive && !force)
|
||||||
|
{
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
|
||||||
|
Name, m_scene.Name);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IsActive = false;
|
IsActive = false;
|
||||||
CloseWithoutChecks(sendStop);
|
CloseWithoutChecks(sendStop);
|
||||||
|
@ -1231,9 +1238,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
LLHeightFieldMoronize(map);
|
LLHeightFieldMoronize(map);
|
||||||
|
|
||||||
LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
|
LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
|
||||||
layerpack.Header.Reliable = true;
|
|
||||||
|
// When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
|
||||||
|
// To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
|
||||||
|
// We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area
|
||||||
|
// invalidating previous packets for that area.
|
||||||
|
|
||||||
OutPacket(layerpack, ThrottleOutPacketType.Task);
|
// It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a
|
||||||
|
// tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower.
|
||||||
|
|
||||||
|
// One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will
|
||||||
|
// have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain
|
||||||
|
// patches.
|
||||||
|
|
||||||
|
// m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss.
|
||||||
|
if (m_justEditedTerrain)
|
||||||
|
{
|
||||||
|
layerpack.Header.Reliable = false;
|
||||||
|
OutPacket(layerpack,
|
||||||
|
ThrottleOutPacketType.Unknown );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
layerpack.Header.Reliable = true;
|
||||||
|
OutPacket(layerpack,
|
||||||
|
ThrottleOutPacketType.Task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -6367,6 +6397,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
//m_log.Info("[LAND]: LAND:" + modify.ToString());
|
//m_log.Info("[LAND]: LAND:" + modify.ToString());
|
||||||
if (modify.ParcelData.Length > 0)
|
if (modify.ParcelData.Length > 0)
|
||||||
{
|
{
|
||||||
|
// Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
|
||||||
|
// a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
|
||||||
|
m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
|
||||||
if (OnModifyTerrain != null)
|
if (OnModifyTerrain != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < modify.ParcelData.Length; i++)
|
for (int i = 0; i < modify.ParcelData.Length; i++)
|
||||||
|
@ -6382,6 +6415,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1871,9 +1871,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
if (!client.SceneAgent.IsChildAgent)
|
if (!client.SceneAgent.IsChildAgent)
|
||||||
client.Kick("Simulator logged you out due to connection timeout.");
|
client.Kick("Simulator logged you out due to connection timeout.");
|
||||||
|
|
||||||
client.CloseWithoutChecks(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_scene.IncomingCloseAgent(client.AgentId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void IncomingPacketHandler()
|
private void IncomingPacketHandler()
|
||||||
|
@ -2216,7 +2216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (!client.IsLoggingOut)
|
if (!client.IsLoggingOut)
|
||||||
{
|
{
|
||||||
client.IsLoggingOut = true;
|
client.IsLoggingOut = true;
|
||||||
client.Close(false, false);
|
m_scene.IncomingCloseAgent(client.AgentId, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||||
public void TestLogoutClientDueToAck()
|
public void TestLogoutClientDueToAck()
|
||||||
{
|
{
|
||||||
TestHelpers.InMethod();
|
TestHelpers.InMethod();
|
||||||
// TestHelpers.EnableLogging();
|
TestHelpers.EnableLogging();
|
||||||
|
|
||||||
IniConfigSource ics = new IniConfigSource();
|
IniConfigSource ics = new IniConfigSource();
|
||||||
IConfig config = ics.AddConfig("ClientStack.LindenUDP");
|
IConfig config = ics.AddConfig("ClientStack.LindenUDP");
|
||||||
|
|
|
@ -1069,8 +1069,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
// Now let's make it officially a child agent
|
// Now let's make it officially a child agent
|
||||||
sp.MakeChildAgent();
|
sp.MakeChildAgent();
|
||||||
|
|
||||||
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
|
// May still need to signal neighbours whether child agents may need closing irrespective of whether this
|
||||||
|
// one needed closing. Neighbour regions also contain logic to prevent a close if a subsequent move or
|
||||||
|
// teleport re-established the child connection.
|
||||||
|
//
|
||||||
|
// It may be possible to also close child agents after a pause but one needs to be very careful about
|
||||||
|
// race conditions between different regions on rapid teleporting (e.g. from A1 to a non-neighbour B, back
|
||||||
|
// to a neighbour A2 then off to a non-neighbour C. Also, closing child agents early may be more compatible
|
||||||
|
// with complicated scenarios where there a mixture of V1 and V2 teleports, though this is conjecture. It's
|
||||||
|
// easier to close immediately and greatly reduce the scope of race conditions if possible.
|
||||||
|
sp.CloseChildAgents(newRegionX, newRegionY);
|
||||||
|
|
||||||
|
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
|
||||||
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
|
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
|
||||||
{
|
{
|
||||||
sp.DoNotCloseAfterTeleport = false;
|
sp.DoNotCloseAfterTeleport = false;
|
||||||
|
@ -1086,14 +1096,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (!sp.DoNotCloseAfterTeleport)
|
if (!sp.DoNotCloseAfterTeleport)
|
||||||
{
|
{
|
||||||
// OK, it got this agent. Let's close everything
|
// OK, it got this agent. Let's close everything
|
||||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.Name);
|
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing agent {0} in {1}", sp.Name, Scene.Name);
|
||||||
sp.CloseChildAgents(newRegionX, newRegionY);
|
|
||||||
sp.Scene.IncomingCloseAgent(sp.UUID, false);
|
sp.Scene.IncomingCloseAgent(sp.UUID, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.Name);
|
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {1}", sp.Name, Scene.Name);
|
||||||
sp.DoNotCloseAfterTeleport = false;
|
sp.DoNotCloseAfterTeleport = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1836,10 +1844,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
|
List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
|
||||||
List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
|
List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
|
||||||
|
|
||||||
//Dump("Current Neighbors", neighbourHandles);
|
// Dump("Current Neighbors", neighbourHandles);
|
||||||
//Dump("Previous Neighbours", previousRegionNeighbourHandles);
|
// Dump("Previous Neighbours", previousRegionNeighbourHandles);
|
||||||
//Dump("New Neighbours", newRegions);
|
// Dump("New Neighbours", newRegions);
|
||||||
//Dump("Old Neighbours", oldRegions);
|
// Dump("Old Neighbours", oldRegions);
|
||||||
|
|
||||||
/// Update the scene presence's known regions here on this region
|
/// Update the scene presence's known regions here on this region
|
||||||
sp.DropOldNeighbours(oldRegions);
|
sp.DropOldNeighbours(oldRegions);
|
||||||
|
@ -1847,8 +1855,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
/// Collect as many seeds as possible
|
/// Collect as many seeds as possible
|
||||||
Dictionary<ulong, string> seeds;
|
Dictionary<ulong, string> seeds;
|
||||||
if (sp.Scene.CapsModule != null)
|
if (sp.Scene.CapsModule != null)
|
||||||
seeds
|
seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
|
||||||
= new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID));
|
|
||||||
else
|
else
|
||||||
seeds = new Dictionary<ulong, string>();
|
seeds = new Dictionary<ulong, string>();
|
||||||
|
|
||||||
|
@ -1918,6 +1925,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
newAgent = true;
|
newAgent = true;
|
||||||
else
|
else
|
||||||
newAgent = false;
|
newAgent = false;
|
||||||
|
// continue;
|
||||||
|
|
||||||
if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
|
if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle)
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,6 +45,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log =
|
private static readonly ILog m_log =
|
||||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
private static string LogHeader = "[MODULE COMMS]";
|
||||||
|
|
||||||
private Dictionary<string,object> m_constants = new Dictionary<string,object>();
|
private Dictionary<string,object> m_constants = new Dictionary<string,object>();
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
|
||||||
MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true);
|
MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true);
|
||||||
if (mi == null)
|
if (mi == null)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", meth);
|
m_log.WarnFormat("{0} Failed to register method {1}", LogHeader, meth);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name);
|
// m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name);
|
||||||
|
|
||||||
Type delegateType;
|
Type delegateType = typeof(void);
|
||||||
List<Type> typeArgs = mi.GetParameters()
|
List<Type> typeArgs = mi.GetParameters()
|
||||||
.Select(p => p.ParameterType)
|
.Select(p => p.ParameterType)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
@ -176,8 +177,16 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
typeArgs.Add(mi.ReturnType);
|
try
|
||||||
delegateType = Expression.GetFuncType(typeArgs.ToArray());
|
{
|
||||||
|
typeArgs.Add(mi.ReturnType);
|
||||||
|
delegateType = Expression.GetFuncType(typeArgs.ToArray());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
m_log.ErrorFormat("{0} Failed to create function signature. Most likely more than 5 parameters. Method={1}. Error={2}",
|
||||||
|
LogHeader, mi.Name, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Delegate fcall;
|
Delegate fcall;
|
||||||
|
|
|
@ -76,6 +76,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
" that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.",
|
" that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.",
|
||||||
consoleSetTerrainHeights);
|
consoleSetTerrainHeights);
|
||||||
|
|
||||||
|
m_module.Scene.AddCommand("Regions", m_module, "set water height",
|
||||||
|
"set water height <height> [<x>] [<y>]",
|
||||||
|
"Sets the water height in meters. If <x> and <y> are specified, it will only set it on regions with a matching coordinate. " +
|
||||||
|
"Specify -1 in <x> or <y> to wildcard that coordinate.",
|
||||||
|
consoleSetWaterHeight);
|
||||||
|
|
||||||
|
|
||||||
m_module.Scene.AddCommand(
|
m_module.Scene.AddCommand(
|
||||||
"Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand);
|
"Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +128,29 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
protected void consoleSetWaterHeight(string module, string[] args)
|
||||||
|
{
|
||||||
|
string heightstring = args[3];
|
||||||
|
|
||||||
|
int x = (args.Length > 4 ? int.Parse(args[4]) : -1);
|
||||||
|
int y = (args.Length > 5 ? int.Parse(args[5]) : -1);
|
||||||
|
|
||||||
|
if (x == -1 || m_module.Scene.RegionInfo.RegionLocX == x)
|
||||||
|
{
|
||||||
|
if (y == -1 || m_module.Scene.RegionInfo.RegionLocY == y)
|
||||||
|
{
|
||||||
|
double selectedheight = double.Parse(heightstring);
|
||||||
|
|
||||||
|
m_log.Debug("[ESTATEMODULE]: Setting water height in " + m_module.Scene.RegionInfo.RegionName + " to " +
|
||||||
|
string.Format(" {0}", selectedheight));
|
||||||
|
m_module.Scene.RegionInfo.RegionSettings.WaterHeight = selectedheight;
|
||||||
|
|
||||||
|
m_module.Scene.RegionInfo.RegionSettings.Save();
|
||||||
|
m_module.TriggerRegionInfoChange();
|
||||||
|
m_module.sendRegionHandshakeToAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
protected void consoleSetTerrainHeights(string module, string[] args)
|
protected void consoleSetTerrainHeights(string module, string[] args)
|
||||||
{
|
{
|
||||||
string num = args[3];
|
string num = args[3];
|
||||||
|
|
|
@ -572,7 +572,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
if (!Scene.TeleportClientHome(user, s.ControllingClient))
|
if (!Scene.TeleportClientHome(user, s.ControllingClient))
|
||||||
{
|
{
|
||||||
s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
|
s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
|
||||||
s.ControllingClient.Close();
|
Scene.IncomingCloseAgent(s.UUID, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,7 +807,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
if (!Scene.TeleportClientHome(prey, s.ControllingClient))
|
if (!Scene.TeleportClientHome(prey, s.ControllingClient))
|
||||||
{
|
{
|
||||||
s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
|
s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
|
||||||
s.ControllingClient.Close();
|
Scene.IncomingCloseAgent(s.UUID, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -830,7 +830,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient))
|
if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient))
|
||||||
{
|
{
|
||||||
p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
|
p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
|
||||||
p.ControllingClient.Close();
|
Scene.IncomingCloseAgent(p.UUID, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,7 +151,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
public SynchronizeSceneHandler SynchronizeScene;
|
public SynchronizeSceneHandler SynchronizeScene;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other.
|
/// Used to prevent simultaneous calls to code that adds and removes agents.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object m_removeClientLock = new object();
|
private object m_removeClientLock = new object();
|
||||||
|
|
||||||
|
@ -1338,7 +1338,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
Thread.Sleep(500);
|
Thread.Sleep(500);
|
||||||
|
|
||||||
// Stop all client threads.
|
// Stop all client threads.
|
||||||
ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); });
|
ForEachScenePresence(delegate(ScenePresence avatar) { IncomingCloseAgent(avatar.UUID, false); });
|
||||||
|
|
||||||
m_log.Debug("[SCENE]: TriggerSceneShuttingDown");
|
m_log.Debug("[SCENE]: TriggerSceneShuttingDown");
|
||||||
EventManager.TriggerSceneShuttingDown(this);
|
EventManager.TriggerSceneShuttingDown(this);
|
||||||
|
@ -3127,7 +3127,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
if (sp != null)
|
if (sp != null)
|
||||||
{
|
{
|
||||||
PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
|
PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
|
||||||
sp.ControllingClient.Close();
|
|
||||||
|
IncomingCloseAgent(sp.UUID, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BANG! SLASH!
|
// BANG! SLASH!
|
||||||
|
@ -3541,47 +3542,48 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public override void RemoveClient(UUID agentID, bool closeChildAgents)
|
public override void RemoveClient(UUID agentID, bool closeChildAgents)
|
||||||
{
|
{
|
||||||
// CheckHeartbeat();
|
AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
|
||||||
bool isChildAgent = false;
|
|
||||||
AgentCircuitData acd;
|
|
||||||
|
|
||||||
lock (m_removeClientLock)
|
// Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
|
||||||
|
// in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
|
||||||
|
// However, will keep for now just in case.
|
||||||
|
if (acd == null)
|
||||||
{
|
{
|
||||||
acd = m_authenticateHandler.GetAgentCircuitData(agentID);
|
m_log.ErrorFormat(
|
||||||
|
"[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name);
|
||||||
|
|
||||||
if (acd == null)
|
return;
|
||||||
{
|
}
|
||||||
m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
|
else
|
||||||
return;
|
{
|
||||||
}
|
m_authenticateHandler.RemoveCircuit(agentID);
|
||||||
else
|
|
||||||
{
|
|
||||||
// We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred
|
|
||||||
// simultaneously.
|
|
||||||
// We also need to remove by agent ID since NPCs will have no circuit code.
|
|
||||||
m_authenticateHandler.RemoveCircuit(agentID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Can we now remove this lock?
|
||||||
lock (acd)
|
lock (acd)
|
||||||
{
|
{
|
||||||
|
bool isChildAgent = false;
|
||||||
|
|
||||||
ScenePresence avatar = GetScenePresence(agentID);
|
ScenePresence avatar = GetScenePresence(agentID);
|
||||||
|
|
||||||
|
// Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
|
||||||
|
// in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
|
||||||
|
// However, will keep for now just in case.
|
||||||
if (avatar == null)
|
if (avatar == null)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat(
|
m_log.ErrorFormat(
|
||||||
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
|
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
isChildAgent = avatar.IsChildAgent;
|
isChildAgent = avatar.IsChildAgent;
|
||||||
|
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[SCENE]: Removing {0} agent {1} {2} from {3}",
|
"[SCENE]: Removing {0} agent {1} {2} from {3}",
|
||||||
(isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
|
isChildAgent ? "child" : "root", avatar.Name, agentID, Name);
|
||||||
|
|
||||||
// Don't do this to root agents, it's not nice for the viewer
|
// Don't do this to root agents, it's not nice for the viewer
|
||||||
if (closeChildAgents && isChildAgent)
|
if (closeChildAgents && isChildAgent)
|
||||||
|
@ -3745,13 +3747,13 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
|
/// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
|
||||||
/// the LLUDP stack).
|
/// the LLUDP stack).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="agent">CircuitData of the agent who is connecting</param>
|
/// <param name="acd">CircuitData of the agent who is connecting</param>
|
||||||
/// <param name="reason">Outputs the reason for the false response on this string</param>
|
/// <param name="reason">Outputs the reason for the false response on this string</param>
|
||||||
/// <param name="requirePresenceLookup">True for normal presence. False for NPC
|
/// <param name="requirePresenceLookup">True for normal presence. False for NPC
|
||||||
/// or other applications where a full grid/Hypergrid presence may not be required.</param>
|
/// or other applications where a full grid/Hypergrid presence may not be required.</param>
|
||||||
/// <returns>True if the region accepts this agent. False if it does not. False will
|
/// <returns>True if the region accepts this agent. False if it does not. False will
|
||||||
/// also return a reason.</returns>
|
/// also return a reason.</returns>
|
||||||
public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup)
|
public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, out string reason, bool requirePresenceLookup)
|
||||||
{
|
{
|
||||||
bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
|
bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
|
||||||
(teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
|
(teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
|
||||||
|
@ -3771,15 +3773,15 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})",
|
"[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})",
|
||||||
RegionInfo.RegionName,
|
RegionInfo.RegionName,
|
||||||
(agent.child ? "child" : "root"),
|
(acd.child ? "child" : "root"),
|
||||||
agent.firstname,
|
acd.firstname,
|
||||||
agent.lastname,
|
acd.lastname,
|
||||||
agent.AgentID,
|
acd.AgentID,
|
||||||
agent.circuitcode,
|
acd.circuitcode,
|
||||||
agent.IPAddress,
|
acd.IPAddress,
|
||||||
agent.Viewer,
|
acd.Viewer,
|
||||||
((TPFlags)teleportFlags).ToString(),
|
((TPFlags)teleportFlags).ToString(),
|
||||||
agent.startpos
|
acd.startpos
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!LoginsEnabled)
|
if (!LoginsEnabled)
|
||||||
|
@ -3797,7 +3799,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
foreach (string viewer in m_AllowedViewers)
|
foreach (string viewer in m_AllowedViewers)
|
||||||
{
|
{
|
||||||
if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower())
|
if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower())
|
||||||
{
|
{
|
||||||
ViewerDenied = false;
|
ViewerDenied = false;
|
||||||
break;
|
break;
|
||||||
|
@ -3814,7 +3816,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
foreach (string viewer in m_BannedViewers)
|
foreach (string viewer in m_BannedViewers)
|
||||||
{
|
{
|
||||||
if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower())
|
if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower())
|
||||||
{
|
{
|
||||||
ViewerDenied = true;
|
ViewerDenied = true;
|
||||||
break;
|
break;
|
||||||
|
@ -3826,61 +3828,115 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[SCENE]: Access denied for {0} {1} using {2}",
|
"[SCENE]: Access denied for {0} {1} using {2}",
|
||||||
agent.firstname, agent.lastname, agent.Viewer);
|
acd.firstname, acd.lastname, acd.Viewer);
|
||||||
reason = "Access denied, your viewer is banned by the region owner";
|
reason = "Access denied, your viewer is banned by the region owner";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (agent)
|
ILandObject land;
|
||||||
|
ScenePresence sp;
|
||||||
|
|
||||||
|
lock (m_removeClientLock)
|
||||||
{
|
{
|
||||||
ScenePresence sp = GetScenePresence(agent.AgentID);
|
sp = GetScenePresence(acd.AgentID);
|
||||||
|
|
||||||
if (sp != null)
|
// We need to ensure that we are not already removing the scene presence before we ask it not to be
|
||||||
|
// closed.
|
||||||
|
if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running)
|
||||||
{
|
{
|
||||||
if (!sp.IsChildAgent)
|
m_log.DebugFormat(
|
||||||
{
|
"[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name);
|
||||||
// We have a root agent. Is it in transit?
|
|
||||||
if (!EntityTransferModule.IsInTransit(sp.UUID))
|
|
||||||
{
|
|
||||||
// We have a zombie from a crashed session.
|
|
||||||
// Or the same user is trying to be root twice here, won't work.
|
|
||||||
// Kill it.
|
|
||||||
m_log.WarnFormat(
|
|
||||||
"[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
|
|
||||||
sp.Name, sp.UUID, RegionInfo.RegionName);
|
|
||||||
|
|
||||||
if (sp.ControllingClient != null)
|
// In the case where, for example, an A B C D region layout, an avatar may
|
||||||
sp.ControllingClient.Close(true, true);
|
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
|
||||||
|
// renews the lease on the child agent at B, we must make sure that the close from A does not succeed.
|
||||||
sp = null;
|
if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle))
|
||||||
}
|
|
||||||
//else
|
|
||||||
// m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// We have a child agent here
|
m_log.DebugFormat(
|
||||||
|
"[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.",
|
||||||
|
sp.Name, Name);
|
||||||
|
|
||||||
sp.DoNotCloseAfterTeleport = true;
|
sp.DoNotCloseAfterTeleport = true;
|
||||||
//m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName);
|
|
||||||
}
|
}
|
||||||
|
else if (EntityTransferModule.IsInTransit(sp.UUID))
|
||||||
|
{
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt previous end-of-teleport close.",
|
||||||
|
sp.Name, Name);
|
||||||
|
|
||||||
|
sp.DoNotCloseAfterTeleport = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to poll here in case we are currently deleting an sp. Letting threads run over each other will
|
||||||
|
// allow unpredictable things to happen.
|
||||||
|
if (sp != null)
|
||||||
|
{
|
||||||
|
const int polls = 10;
|
||||||
|
const int pollInterval = 1000;
|
||||||
|
int pollsLeft = polls;
|
||||||
|
|
||||||
|
while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0)
|
||||||
|
Thread.Sleep(pollInterval);
|
||||||
|
|
||||||
|
if (sp.LifecycleState == ScenePresenceState.Removing)
|
||||||
|
{
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.",
|
||||||
|
sp.Name, Name, polls * pollInterval / 1000);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (polls != pollsLeft)
|
||||||
|
{
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.",
|
||||||
|
sp.Name, Name, polls * pollInterval / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: can we remove this lock?
|
||||||
|
lock (acd)
|
||||||
|
{
|
||||||
|
if (sp != null && !sp.IsChildAgent)
|
||||||
|
{
|
||||||
|
// We have a root agent. Is it in transit?
|
||||||
|
if (!EntityTransferModule.IsInTransit(sp.UUID))
|
||||||
|
{
|
||||||
|
// We have a zombie from a crashed session.
|
||||||
|
// Or the same user is trying to be root twice here, won't work.
|
||||||
|
// Kill it.
|
||||||
|
m_log.WarnFormat(
|
||||||
|
"[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
|
||||||
|
sp.Name, sp.UUID, RegionInfo.RegionName);
|
||||||
|
|
||||||
|
if (sp.ControllingClient != null)
|
||||||
|
IncomingCloseAgent(sp.UUID, true);
|
||||||
|
|
||||||
|
sp = null;
|
||||||
|
}
|
||||||
|
//else
|
||||||
|
// m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
|
// Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
|
||||||
// We need the circuit data here for some of the subsequent checks. (groups, for example)
|
// We need the circuit data here for some of the subsequent checks. (groups, for example)
|
||||||
// If the checks fail, we remove the circuit.
|
// If the checks fail, we remove the circuit.
|
||||||
agent.teleportFlags = teleportFlags;
|
acd.teleportFlags = teleportFlags;
|
||||||
m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent);
|
m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd);
|
||||||
|
|
||||||
|
land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y);
|
||||||
|
|
||||||
// On login test land permisions
|
// On login test land permisions
|
||||||
if (vialogin)
|
if (vialogin)
|
||||||
{
|
{
|
||||||
IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
|
IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
|
||||||
if (cache != null)
|
if (cache != null)
|
||||||
cache.Remove(agent.firstname + " " + agent.lastname);
|
cache.Remove(acd.firstname + " " + acd.lastname);
|
||||||
if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
|
if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y))
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
|
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
|
||||||
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3891,9 +3947,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!VerifyUserPresence(agent, out reason))
|
if (!VerifyUserPresence(acd, out reason))
|
||||||
{
|
{
|
||||||
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
|
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3902,16 +3958,16 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_log.ErrorFormat(
|
m_log.ErrorFormat(
|
||||||
"[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
|
"[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
|
||||||
|
|
||||||
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
|
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!AuthorizeUser(agent, SeeIntoRegion, out reason))
|
if (!AuthorizeUser(acd, SeeIntoRegion, out reason))
|
||||||
{
|
{
|
||||||
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
|
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3920,15 +3976,20 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_log.ErrorFormat(
|
m_log.ErrorFormat(
|
||||||
"[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
|
"[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
|
||||||
|
|
||||||
m_authenticateHandler.RemoveCircuit(agent.circuitcode);
|
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.InfoFormat(
|
m_log.InfoFormat(
|
||||||
"[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
|
"[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
|
||||||
RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
|
Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
|
||||||
agent.AgentID, agent.circuitcode);
|
acd.AgentID, acd.circuitcode);
|
||||||
|
|
||||||
|
if (CapsModule != null)
|
||||||
|
{
|
||||||
|
CapsModule.SetAgentCapsSeeds(acd);
|
||||||
|
CapsModule.CreateCaps(acd.AgentID, acd.circuitcode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3940,14 +4001,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
m_log.DebugFormat(
|
||||||
"[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
|
"[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
|
||||||
agent.AgentID, RegionInfo.RegionName);
|
acd.AgentID, RegionInfo.RegionName);
|
||||||
|
|
||||||
sp.AdjustKnownSeeds();
|
sp.AdjustKnownSeeds();
|
||||||
|
|
||||||
if (CapsModule != null)
|
if (CapsModule != null)
|
||||||
{
|
{
|
||||||
CapsModule.SetAgentCapsSeeds(agent);
|
CapsModule.SetAgentCapsSeeds(acd);
|
||||||
CapsModule.CreateCaps(agent.AgentID, agent.circuitcode);
|
CapsModule.CreateCaps(acd.AgentID, acd.circuitcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3955,28 +4016,28 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// Try caching an incoming user name much earlier on to see if this helps with an issue
|
// Try caching an incoming user name much earlier on to see if this helps with an issue
|
||||||
// where HG users are occasionally seen by others as "Unknown User" because their UUIDName
|
// where HG users are occasionally seen by others as "Unknown User" because their UUIDName
|
||||||
// request for the HG avatar appears to trigger before the user name is cached.
|
// request for the HG avatar appears to trigger before the user name is cached.
|
||||||
CacheUserName(null, agent);
|
CacheUserName(null, acd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CapsModule != null)
|
if (CapsModule != null)
|
||||||
{
|
{
|
||||||
CapsModule.ActivateCaps(agent.circuitcode);
|
CapsModule.ActivateCaps(acd.circuitcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vialogin)
|
if (vialogin)
|
||||||
{
|
{
|
||||||
// CleanDroppedAttachments();
|
// CleanDroppedAttachments();
|
||||||
|
|
||||||
if (TestBorderCross(agent.startpos, Cardinals.E))
|
if (TestBorderCross(acd.startpos, Cardinals.E))
|
||||||
{
|
{
|
||||||
Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E);
|
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E);
|
||||||
agent.startpos.X = crossedBorder.BorderLine.Z - 1;
|
acd.startpos.X = crossedBorder.BorderLine.Z - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TestBorderCross(agent.startpos, Cardinals.N))
|
if (TestBorderCross(acd.startpos, Cardinals.N))
|
||||||
{
|
{
|
||||||
Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N);
|
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
|
||||||
agent.startpos.Y = crossedBorder.BorderLine.Z - 1;
|
acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Mitigate http://opensimulator.org/mantis/view.php?id=3522
|
//Mitigate http://opensimulator.org/mantis/view.php?id=3522
|
||||||
|
@ -3986,39 +4047,39 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
lock (EastBorders)
|
lock (EastBorders)
|
||||||
{
|
{
|
||||||
if (agent.startpos.X > EastBorders[0].BorderLine.Z)
|
if (acd.startpos.X > EastBorders[0].BorderLine.Z)
|
||||||
{
|
{
|
||||||
m_log.Warn("FIX AGENT POSITION");
|
m_log.Warn("FIX AGENT POSITION");
|
||||||
agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
|
acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
|
||||||
if (agent.startpos.Z > 720)
|
if (acd.startpos.Z > 720)
|
||||||
agent.startpos.Z = 720;
|
acd.startpos.Z = 720;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock (NorthBorders)
|
lock (NorthBorders)
|
||||||
{
|
{
|
||||||
if (agent.startpos.Y > NorthBorders[0].BorderLine.Z)
|
if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
|
||||||
{
|
{
|
||||||
m_log.Warn("FIX Agent POSITION");
|
m_log.Warn("FIX Agent POSITION");
|
||||||
agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
|
acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
|
||||||
if (agent.startpos.Z > 720)
|
if (acd.startpos.Z > 720)
|
||||||
agent.startpos.Z = 720;
|
acd.startpos.Z = 720;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
if (agent.startpos.X > EastBorders[0].BorderLine.Z)
|
if (acd.startpos.X > EastBorders[0].BorderLine.Z)
|
||||||
{
|
{
|
||||||
m_log.Warn("FIX AGENT POSITION");
|
m_log.Warn("FIX AGENT POSITION");
|
||||||
agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
|
acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
|
||||||
if (agent.startpos.Z > 720)
|
if (acd.startpos.Z > 720)
|
||||||
agent.startpos.Z = 720;
|
acd.startpos.Z = 720;
|
||||||
}
|
}
|
||||||
if (agent.startpos.Y > NorthBorders[0].BorderLine.Z)
|
if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
|
||||||
{
|
{
|
||||||
m_log.Warn("FIX Agent POSITION");
|
m_log.Warn("FIX Agent POSITION");
|
||||||
agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
|
acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
|
||||||
if (agent.startpos.Z > 720)
|
if (acd.startpos.Z > 720)
|
||||||
agent.startpos.Z = 720;
|
acd.startpos.Z = 720;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4034,12 +4095,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
// We have multiple SpawnPoints, Route the agent to a random or sequential one
|
// We have multiple SpawnPoints, Route the agent to a random or sequential one
|
||||||
if (SpawnPointRouting == "random")
|
if (SpawnPointRouting == "random")
|
||||||
agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
|
acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
|
||||||
telehub.AbsolutePosition,
|
telehub.AbsolutePosition,
|
||||||
telehub.GroupRotation
|
telehub.GroupRotation
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
agent.startpos = spawnpoints[SpawnPoint()].GetLocation(
|
acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
|
||||||
telehub.AbsolutePosition,
|
telehub.AbsolutePosition,
|
||||||
telehub.GroupRotation
|
telehub.GroupRotation
|
||||||
);
|
);
|
||||||
|
@ -4047,7 +4108,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We have a single SpawnPoint and will route the agent to it
|
// We have a single SpawnPoint and will route the agent to it
|
||||||
agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
|
acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -4060,7 +4121,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
|
if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
|
||||||
{
|
{
|
||||||
agent.startpos = land.LandData.UserLocation;
|
acd.startpos = land.LandData.UserLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/// This is now handled properly in ScenePresence.MakeRootAgent
|
*/// This is now handled properly in ScenePresence.MakeRootAgent
|
||||||
|
@ -4444,24 +4505,25 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
|
ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
|
||||||
if (childAgentUpdate != null)
|
if (childAgentUpdate != null)
|
||||||
{
|
{
|
||||||
if (childAgentUpdate.ControllingClient.SessionId == cAgentData.SessionID)
|
if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
|
||||||
|
// Only warn for now
|
||||||
|
m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
|
||||||
|
childAgentUpdate.UUID, cAgentData.SessionID);
|
||||||
|
|
||||||
|
// I can't imagine *yet* why we would get an update if the agent is a root agent..
|
||||||
|
// however to avoid a race condition crossing borders..
|
||||||
|
if (childAgentUpdate.IsChildAgent)
|
||||||
{
|
{
|
||||||
// I can't imagine *yet* why we would get an update if the agent is a root agent..
|
uint rRegionX = (uint)(cAgentData.RegionHandle >> 40);
|
||||||
// however to avoid a race condition crossing borders..
|
uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8);
|
||||||
if (childAgentUpdate.IsChildAgent)
|
uint tRegionX = RegionInfo.RegionLocX;
|
||||||
{
|
uint tRegionY = RegionInfo.RegionLocY;
|
||||||
uint rRegionX = (uint)(cAgentData.RegionHandle >> 40);
|
//Send Data to ScenePresence
|
||||||
uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8);
|
childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
|
||||||
uint tRegionX = RegionInfo.RegionLocX;
|
// Not Implemented:
|
||||||
uint tRegionY = RegionInfo.RegionLocY;
|
//TODO: Do we need to pass the message on to one of our neighbors?
|
||||||
//Send Data to ScenePresence
|
|
||||||
childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
|
|
||||||
// Not Implemented:
|
|
||||||
//TODO: Do we need to pass the message on to one of our neighbors?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}", childAgentUpdate.UUID, cAgentData.SessionID);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4540,11 +4602,51 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// </param>
|
/// </param>
|
||||||
public bool IncomingCloseAgent(UUID agentID, bool force)
|
public bool IncomingCloseAgent(UUID agentID, bool force)
|
||||||
{
|
{
|
||||||
//m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
|
ScenePresence sp;
|
||||||
ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
|
|
||||||
if (presence != null)
|
lock (m_removeClientLock)
|
||||||
{
|
{
|
||||||
presence.ControllingClient.Close(force, force);
|
sp = GetScenePresence(agentID);
|
||||||
|
|
||||||
|
if (sp == null)
|
||||||
|
{
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}",
|
||||||
|
agentID, Name);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sp.LifecycleState != ScenePresenceState.Running)
|
||||||
|
{
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}",
|
||||||
|
sp.Name, Name, sp.LifecycleState);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
|
||||||
|
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
|
||||||
|
// want to obey this close since C may have renewed the child agent lease on B.
|
||||||
|
if (sp.DoNotCloseAfterTeleport)
|
||||||
|
{
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection",
|
||||||
|
sp.IsChildAgent ? "child" : "root", sp.Name, Name);
|
||||||
|
|
||||||
|
// Need to reset the flag so that a subsequent close after another teleport can succeed.
|
||||||
|
sp.DoNotCloseAfterTeleport = false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.LifecycleState = ScenePresenceState.Removing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sp != null)
|
||||||
|
{
|
||||||
|
sp.ControllingClient.Close(force, force);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public class ScenePresence : EntityBase, IScenePresence
|
public class ScenePresence : EntityBase, IScenePresence
|
||||||
{
|
{
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
// ~ScenePresence()
|
// ~ScenePresence()
|
||||||
// {
|
// {
|
||||||
// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
|
// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
|
||||||
|
@ -86,10 +88,27 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_scene.EventManager.TriggerScenePresenceUpdated(this);
|
m_scene.EventManager.TriggerScenePresenceUpdated(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
|
||||||
|
|
||||||
public PresenceType PresenceType { get; private set; }
|
public PresenceType PresenceType { get; private set; }
|
||||||
|
|
||||||
|
private ScenePresenceStateMachine m_stateMachine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine
|
||||||
|
/// for more details.
|
||||||
|
/// </summary>
|
||||||
|
public ScenePresenceState LifecycleState
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_stateMachine.GetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_stateMachine.SetState(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
|
// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
|
||||||
private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
|
private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
|
||||||
private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
|
private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
|
||||||
|
@ -299,9 +318,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address.
|
/// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string m_callbackURI;
|
private string m_callbackURI;
|
||||||
|
|
||||||
UUID m_originRegionID;
|
public UUID m_originRegionID;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
|
/// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
|
||||||
|
@ -813,7 +832,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public ScenePresence(
|
public ScenePresence(
|
||||||
IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
|
IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
|
||||||
{
|
{
|
||||||
AttachmentsSyncLock = new Object();
|
AttachmentsSyncLock = new Object();
|
||||||
AllowMovement = true;
|
AllowMovement = true;
|
||||||
IsChildAgent = true;
|
IsChildAgent = true;
|
||||||
|
@ -859,6 +878,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
SetDirectionVectors();
|
SetDirectionVectors();
|
||||||
|
|
||||||
Appearance = appearance;
|
Appearance = appearance;
|
||||||
|
|
||||||
|
m_stateMachine = new ScenePresenceStateMachine(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegionHeartbeatEnd(Scene scene)
|
private void RegionHeartbeatEnd(Scene scene)
|
||||||
|
@ -956,7 +977,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void MakeRootAgent(Vector3 pos, bool isFlying)
|
public void MakeRootAgent(Vector3 pos, bool isFlying)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat(
|
m_log.InfoFormat(
|
||||||
"[SCENE]: Upgrading child to root agent for {0} in {1}",
|
"[SCENE]: Upgrading child to root agent for {0} in {1}",
|
||||||
Name, m_scene.RegionInfo.RegionName);
|
Name, m_scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
@ -996,6 +1017,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
IsChildAgent = false;
|
IsChildAgent = false;
|
||||||
|
|
||||||
|
// Must reset this here so that a teleport to a region next to an existing region does not keep the flag
|
||||||
|
// set and prevent the close of the connection on a subsequent re-teleport.
|
||||||
|
// Should not be needed if we are not trying to tell this region to close
|
||||||
|
// DoNotCloseAfterTeleport = false;
|
||||||
|
|
||||||
IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
|
IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
|
||||||
if (gm != null)
|
if (gm != null)
|
||||||
Grouptitle = gm.GetGroupTitle(m_uuid);
|
Grouptitle = gm.GetGroupTitle(m_uuid);
|
||||||
|
@ -1520,7 +1546,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
private bool WaitForUpdateAgent(IClientAPI client)
|
private bool WaitForUpdateAgent(IClientAPI client)
|
||||||
{
|
{
|
||||||
// Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero
|
// Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero
|
||||||
int count = 20;
|
int count = 50;
|
||||||
while (m_originRegionID.Equals(UUID.Zero) && count-- > 0)
|
while (m_originRegionID.Equals(UUID.Zero) && count-- > 0)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name);
|
m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name);
|
||||||
|
@ -3994,6 +4020,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// Animator.Close();
|
// Animator.Close();
|
||||||
Animator = null;
|
Animator = null;
|
||||||
|
|
||||||
|
LifecycleState = ScenePresenceState.Removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddAttachment(SceneObjectGroup gobj)
|
public void AddAttachment(SceneObjectGroup gobj)
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Framework.Scenes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The possible states that a scene presence can be in. This is currently orthagonal to whether a scene presence
|
||||||
|
/// is root or child.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is a state machine.
|
||||||
|
///
|
||||||
|
/// [Entry] => Running
|
||||||
|
/// Running => Removing
|
||||||
|
/// Removing => Removed
|
||||||
|
///
|
||||||
|
/// All other methods should only see the scene presence in running state - this is the normal operational state
|
||||||
|
/// Removed state occurs when the presence has been removed. This is the end state with no exit.
|
||||||
|
/// </remarks>
|
||||||
|
public enum ScenePresenceState
|
||||||
|
{
|
||||||
|
Running, // Normal operation state. The scene presence is available.
|
||||||
|
Removing, // The presence is in the process of being removed from the scene via Scene.RemoveClient.
|
||||||
|
Removed, // The presence has been removed from the scene and is effectively dead.
|
||||||
|
// There is no exit from this state.
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ScenePresenceStateMachine
|
||||||
|
{
|
||||||
|
private ScenePresence m_sp;
|
||||||
|
private ScenePresenceState m_state;
|
||||||
|
|
||||||
|
internal ScenePresenceStateMachine(ScenePresence sp)
|
||||||
|
{
|
||||||
|
m_sp = sp;
|
||||||
|
m_state = ScenePresenceState.Running;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ScenePresenceState GetState()
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the state of an agent that is already in transit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='id'></param>
|
||||||
|
/// <param name='newState'></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
|
||||||
|
internal void SetState(ScenePresenceState newState)
|
||||||
|
{
|
||||||
|
bool transitionOkay = false;
|
||||||
|
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (newState == ScenePresenceState.Removing && m_state == ScenePresenceState.Running)
|
||||||
|
transitionOkay = true;
|
||||||
|
else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing)
|
||||||
|
transitionOkay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transitionOkay)
|
||||||
|
{
|
||||||
|
throw new Exception(
|
||||||
|
string.Format(
|
||||||
|
"Scene presence {0} is not allowed to move from state {1} to new state {2} in {3}",
|
||||||
|
m_sp.Name, m_state, newState, m_sp.Scene.Name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_state = newState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -96,8 +96,8 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
|
m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
|
||||||
PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
|
PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
|
||||||
|
|
||||||
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6}",
|
||||||
LocalID, _size, Scale, Density, _avatarVolume, RawMass);
|
LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos);
|
||||||
|
|
||||||
// do actual creation in taint time
|
// do actual creation in taint time
|
||||||
PhysScene.TaintedObject("BSCharacter.create", delegate()
|
PhysScene.TaintedObject("BSCharacter.create", delegate()
|
||||||
|
@ -190,6 +190,10 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
|
// This is how much the avatar size is changing. Positive means getting bigger.
|
||||||
|
// The avatar altitude must be adjusted for this change.
|
||||||
|
float heightChange = value.Z - _size.Z;
|
||||||
|
|
||||||
_size = value;
|
_size = value;
|
||||||
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
|
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
|
||||||
// replace with the default values.
|
// replace with the default values.
|
||||||
|
@ -207,6 +211,10 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
{
|
{
|
||||||
PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
|
PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
|
||||||
UpdatePhysicalMassProperties(RawMass, true);
|
UpdatePhysicalMassProperties(RawMass, true);
|
||||||
|
|
||||||
|
// Adjust the avatar's position to account for the increase/decrease in size
|
||||||
|
ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
|
||||||
|
|
||||||
// Make sure this change appears as a property update event
|
// Make sure this change appears as a property update event
|
||||||
PhysScene.PE.PushUpdate(PhysBody);
|
PhysScene.PE.PushUpdate(PhysBody);
|
||||||
}
|
}
|
||||||
|
|
|
@ -570,9 +570,9 @@ public static class BSParam
|
||||||
new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
|
new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
|
||||||
-0.2f ),
|
-0.2f ),
|
||||||
new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
|
new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
|
||||||
0.1f ),
|
0.2f ),
|
||||||
new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
|
new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
|
||||||
0.1f ),
|
0.2f ),
|
||||||
new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
|
new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
|
||||||
0.1f ),
|
0.1f ),
|
||||||
new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
|
new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
|
||||||
|
|
|
@ -264,8 +264,15 @@
|
||||||
|
|
||||||
; Simulator Stats URI
|
; Simulator Stats URI
|
||||||
; Enable JSON simulator data by setting a URI name (case sensitive)
|
; Enable JSON simulator data by setting a URI name (case sensitive)
|
||||||
|
; Returns regular sim stats (SimFPS, ...)
|
||||||
; Stats_URI = "jsonSimStats"
|
; Stats_URI = "jsonSimStats"
|
||||||
|
|
||||||
|
; Simulator StatsManager URI
|
||||||
|
; Enable fetch of StatsManager registered stats. Fetch is query which can optionally
|
||||||
|
; specify category, container and stat to fetch. If not selected, returns all of that type.
|
||||||
|
; http://simulatorHTTPport/ManagedStats/?cat=Category&cont=Container&stat=Statistic
|
||||||
|
; ManagedStatsRemoteFetchURI = "ManagedStats"
|
||||||
|
|
||||||
; Make OpenSim start all regions woth logins disabled. They will need
|
; Make OpenSim start all regions woth logins disabled. They will need
|
||||||
; to be enabled from the console if this is set
|
; to be enabled from the console if this is set
|
||||||
; StartDisabled = false
|
; StartDisabled = false
|
||||||
|
|
Loading…
Reference in New Issue