diff options
Diffstat (limited to 'OpenSim')
24 files changed, 862 insertions, 362 deletions
diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs index 04442c3..318cf1c 100755 --- a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs | |||
@@ -34,142 +34,6 @@ using OpenMetaverse.StructuredData; | |||
34 | 34 | ||
35 | namespace OpenSim.Framework.Monitoring | 35 | namespace OpenSim.Framework.Monitoring |
36 | { | 36 | { |
37 | // Create a time histogram of events. The histogram is built in a wrap-around | ||
38 | // array of equally distributed buckets. | ||
39 | // For instance, a minute long histogram of second sized buckets would be: | ||
40 | // new EventHistogram(60, 1000) | ||
41 | public class EventHistogram | ||
42 | { | ||
43 | private int m_timeBase; | ||
44 | private int m_numBuckets; | ||
45 | private int m_bucketMilliseconds; | ||
46 | private int m_lastBucket; | ||
47 | private int m_totalHistogramMilliseconds; | ||
48 | private long[] m_histogram; | ||
49 | private object histoLock = new object(); | ||
50 | |||
51 | public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) | ||
52 | { | ||
53 | m_numBuckets = numberOfBuckets; | ||
54 | m_bucketMilliseconds = millisecondsPerBucket; | ||
55 | m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; | ||
56 | |||
57 | m_histogram = new long[m_numBuckets]; | ||
58 | Zero(); | ||
59 | m_lastBucket = 0; | ||
60 | m_timeBase = Util.EnvironmentTickCount(); | ||
61 | } | ||
62 | |||
63 | public void Event() | ||
64 | { | ||
65 | this.Event(1); | ||
66 | } | ||
67 | |||
68 | // Record an event at time 'now' in the histogram. | ||
69 | public void Event(int cnt) | ||
70 | { | ||
71 | lock (histoLock) | ||
72 | { | ||
73 | // The time as displaced from the base of the histogram | ||
74 | int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); | ||
75 | |||
76 | // If more than the total time of the histogram, we just start over | ||
77 | if (bucketTime > m_totalHistogramMilliseconds) | ||
78 | { | ||
79 | Zero(); | ||
80 | m_lastBucket = 0; | ||
81 | m_timeBase = Util.EnvironmentTickCount(); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | // To which bucket should we add this event? | ||
86 | int bucket = bucketTime / m_bucketMilliseconds; | ||
87 | |||
88 | // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. | ||
89 | while (bucket != m_lastBucket) | ||
90 | { | ||
91 | // Zero from just after the last bucket to the new bucket or the end | ||
92 | for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) | ||
93 | { | ||
94 | m_histogram[jj] = 0; | ||
95 | } | ||
96 | m_lastBucket = bucket; | ||
97 | // If the new bucket is off the end, wrap around to the beginning | ||
98 | if (bucket > m_numBuckets) | ||
99 | { | ||
100 | bucket -= m_numBuckets; | ||
101 | m_lastBucket = 0; | ||
102 | m_histogram[m_lastBucket] = 0; | ||
103 | m_timeBase += m_totalHistogramMilliseconds; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | m_histogram[m_lastBucket] += cnt; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | // Get a copy of the current histogram | ||
112 | public long[] GetHistogram() | ||
113 | { | ||
114 | long[] ret = new long[m_numBuckets]; | ||
115 | lock (histoLock) | ||
116 | { | ||
117 | int indx = m_lastBucket + 1; | ||
118 | for (int ii = 0; ii < m_numBuckets; ii++, indx++) | ||
119 | { | ||
120 | if (indx >= m_numBuckets) | ||
121 | indx = 0; | ||
122 | ret[ii] = m_histogram[indx]; | ||
123 | } | ||
124 | } | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | public OSDMap GetHistogramAsOSDMap() | ||
129 | { | ||
130 | OSDMap ret = new OSDMap(); | ||
131 | |||
132 | ret.Add("Buckets", OSD.FromInteger(m_numBuckets)); | ||
133 | ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds)); | ||
134 | ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds)); | ||
135 | |||
136 | // Compute a number for the first bucket in the histogram. | ||
137 | // This will allow readers to know how this histogram relates to any previously read histogram. | ||
138 | int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1; | ||
139 | ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum)); | ||
140 | |||
141 | ret.Add("Values", GetHistogramAsOSDArray()); | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | // Get a copy of the current histogram | ||
146 | public OSDArray GetHistogramAsOSDArray() | ||
147 | { | ||
148 | OSDArray ret = new OSDArray(m_numBuckets); | ||
149 | lock (histoLock) | ||
150 | { | ||
151 | int indx = m_lastBucket + 1; | ||
152 | for (int ii = 0; ii < m_numBuckets; ii++, indx++) | ||
153 | { | ||
154 | if (indx >= m_numBuckets) | ||
155 | indx = 0; | ||
156 | ret[ii] = OSD.FromLong(m_histogram[indx]); | ||
157 | } | ||
158 | } | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | // Zero out the histogram | ||
163 | public void Zero() | ||
164 | { | ||
165 | lock (histoLock) | ||
166 | { | ||
167 | for (int ii = 0; ii < m_numBuckets; ii++) | ||
168 | m_histogram[ii] = 0; | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | // A statistic that wraps a counter. | 37 | // A statistic that wraps a counter. |
174 | // Built this way mostly so histograms and history can be created. | 38 | // Built this way mostly so histograms and history can be created. |
175 | public class CounterStat : Stat | 39 | public class CounterStat : Stat |
@@ -236,12 +100,18 @@ public class CounterStat : Stat | |||
236 | // If there are any histograms, add a new field that is an array of histograms as OSDMaps | 100 | // If there are any histograms, add a new field that is an array of histograms as OSDMaps |
237 | if (m_histograms.Count > 0) | 101 | if (m_histograms.Count > 0) |
238 | { | 102 | { |
239 | OSDArray histos = new OSDArray(); | 103 | lock (counterLock) |
240 | foreach (EventHistogram histo in m_histograms.Values) | ||
241 | { | 104 | { |
242 | histos.Add(histo.GetHistogramAsOSDMap()); | 105 | if (m_histograms.Count > 0) |
106 | { | ||
107 | OSDArray histos = new OSDArray(); | ||
108 | foreach (EventHistogram histo in m_histograms.Values) | ||
109 | { | ||
110 | histos.Add(histo.GetHistogramAsOSDMap()); | ||
111 | } | ||
112 | map.Add("Histograms", histos); | ||
113 | } | ||
243 | } | 114 | } |
244 | map.Add("Histograms", histos); | ||
245 | } | 115 | } |
246 | return map; | 116 | return map; |
247 | } | 117 | } |
diff --git a/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs new file mode 100755 index 0000000..f51f322 --- /dev/null +++ b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenMetaverse.StructuredData; | ||
34 | |||
35 | namespace OpenSim.Framework.Monitoring | ||
36 | { | ||
37 | // Create a time histogram of events. The histogram is built in a wrap-around | ||
38 | // array of equally distributed buckets. | ||
39 | // For instance, a minute long histogram of second sized buckets would be: | ||
40 | // new EventHistogram(60, 1000) | ||
41 | public class EventHistogram | ||
42 | { | ||
43 | private int m_timeBase; | ||
44 | private int m_numBuckets; | ||
45 | private int m_bucketMilliseconds; | ||
46 | private int m_lastBucket; | ||
47 | private int m_totalHistogramMilliseconds; | ||
48 | private long[] m_histogram; | ||
49 | private object histoLock = new object(); | ||
50 | |||
51 | public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) | ||
52 | { | ||
53 | m_numBuckets = numberOfBuckets; | ||
54 | m_bucketMilliseconds = millisecondsPerBucket; | ||
55 | m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; | ||
56 | |||
57 | m_histogram = new long[m_numBuckets]; | ||
58 | Zero(); | ||
59 | m_lastBucket = 0; | ||
60 | m_timeBase = Util.EnvironmentTickCount(); | ||
61 | } | ||
62 | |||
63 | public void Event() | ||
64 | { | ||
65 | this.Event(1); | ||
66 | } | ||
67 | |||
68 | // Record an event at time 'now' in the histogram. | ||
69 | public void Event(int cnt) | ||
70 | { | ||
71 | lock (histoLock) | ||
72 | { | ||
73 | // The time as displaced from the base of the histogram | ||
74 | int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); | ||
75 | |||
76 | // If more than the total time of the histogram, we just start over | ||
77 | if (bucketTime > m_totalHistogramMilliseconds) | ||
78 | { | ||
79 | Zero(); | ||
80 | m_lastBucket = 0; | ||
81 | m_timeBase = Util.EnvironmentTickCount(); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | // To which bucket should we add this event? | ||
86 | int bucket = bucketTime / m_bucketMilliseconds; | ||
87 | |||
88 | // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. | ||
89 | while (bucket != m_lastBucket) | ||
90 | { | ||
91 | // Zero from just after the last bucket to the new bucket or the end | ||
92 | for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) | ||
93 | { | ||
94 | m_histogram[jj] = 0; | ||
95 | } | ||
96 | m_lastBucket = bucket; | ||
97 | // If the new bucket is off the end, wrap around to the beginning | ||
98 | if (bucket > m_numBuckets) | ||
99 | { | ||
100 | bucket -= m_numBuckets; | ||
101 | m_lastBucket = 0; | ||
102 | m_histogram[m_lastBucket] = 0; | ||
103 | m_timeBase += m_totalHistogramMilliseconds; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | m_histogram[m_lastBucket] += cnt; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | // Get a copy of the current histogram | ||
112 | public long[] GetHistogram() | ||
113 | { | ||
114 | long[] ret = new long[m_numBuckets]; | ||
115 | lock (histoLock) | ||
116 | { | ||
117 | int indx = m_lastBucket + 1; | ||
118 | for (int ii = 0; ii < m_numBuckets; ii++, indx++) | ||
119 | { | ||
120 | if (indx >= m_numBuckets) | ||
121 | indx = 0; | ||
122 | ret[ii] = m_histogram[indx]; | ||
123 | } | ||
124 | } | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | public OSDMap GetHistogramAsOSDMap() | ||
129 | { | ||
130 | OSDMap ret = new OSDMap(); | ||
131 | |||
132 | ret.Add("Buckets", OSD.FromInteger(m_numBuckets)); | ||
133 | ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds)); | ||
134 | ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds)); | ||
135 | |||
136 | // Compute a number for the first bucket in the histogram. | ||
137 | // This will allow readers to know how this histogram relates to any previously read histogram. | ||
138 | int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1; | ||
139 | ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum)); | ||
140 | |||
141 | ret.Add("Values", GetHistogramAsOSDArray()); | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | // Get a copy of the current histogram | ||
146 | public OSDArray GetHistogramAsOSDArray() | ||
147 | { | ||
148 | OSDArray ret = new OSDArray(m_numBuckets); | ||
149 | lock (histoLock) | ||
150 | { | ||
151 | int indx = m_lastBucket + 1; | ||
152 | for (int ii = 0; ii < m_numBuckets; ii++, indx++) | ||
153 | { | ||
154 | if (indx >= m_numBuckets) | ||
155 | indx = 0; | ||
156 | ret[ii] = OSD.FromLong(m_histogram[indx]); | ||
157 | } | ||
158 | } | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | // Zero out the histogram | ||
163 | public void Zero() | ||
164 | { | ||
165 | lock (histoLock) | ||
166 | { | ||
167 | for (int ii = 0; ii < m_numBuckets; ii++) | ||
168 | m_histogram[ii] = 0; | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | } | ||
diff --git a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs index 60bed55..55ddf06 100644 --- a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs | |||
@@ -29,6 +29,8 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | 31 | ||
32 | using OpenMetaverse.StructuredData; | ||
33 | |||
32 | namespace OpenSim.Framework.Monitoring | 34 | namespace OpenSim.Framework.Monitoring |
33 | { | 35 | { |
34 | public class PercentageStat : Stat | 36 | public class PercentageStat : Stat |
@@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring | |||
84 | 86 | ||
85 | return sb.ToString(); | 87 | return sb.ToString(); |
86 | } | 88 | } |
89 | |||
90 | // PercentageStat is a basic stat plus percent calc | ||
91 | public override OSDMap ToOSDMap() | ||
92 | { | ||
93 | // Get the foundational instance | ||
94 | OSDMap map = base.ToOSDMap(); | ||
95 | |||
96 | map["StatType"] = "PercentageStat"; | ||
97 | |||
98 | map.Add("Antecedent", OSD.FromLong(Antecedent)); | ||
99 | map.Add("Consequent", OSD.FromLong(Consequent)); | ||
100 | |||
101 | return map; | ||
102 | } | ||
87 | } | 103 | } |
88 | } \ No newline at end of file | 104 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index ffd5132..2b34493 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs | |||
@@ -241,6 +241,8 @@ namespace OpenSim.Framework.Monitoring | |||
241 | public virtual OSDMap ToOSDMap() | 241 | public virtual OSDMap ToOSDMap() |
242 | { | 242 | { |
243 | OSDMap ret = new OSDMap(); | 243 | OSDMap ret = new OSDMap(); |
244 | ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat | ||
245 | |||
244 | ret.Add("Category", OSD.FromString(Category)); | 246 | ret.Add("Category", OSD.FromString(Category)); |
245 | ret.Add("Container", OSD.FromString(Container)); | 247 | ret.Add("Container", OSD.FromString(Container)); |
246 | ret.Add("ShortName", OSD.FromString(ShortName)); | 248 | ret.Add("ShortName", OSD.FromString(ShortName)); |
@@ -248,26 +250,36 @@ namespace OpenSim.Framework.Monitoring | |||
248 | ret.Add("Description", OSD.FromString(Description)); | 250 | ret.Add("Description", OSD.FromString(Description)); |
249 | ret.Add("UnitName", OSD.FromString(UnitName)); | 251 | ret.Add("UnitName", OSD.FromString(UnitName)); |
250 | ret.Add("Value", OSD.FromReal(Value)); | 252 | ret.Add("Value", OSD.FromReal(Value)); |
251 | ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat | 253 | |
254 | double lastChangeOverTime, averageChangeOverTime; | ||
255 | if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) | ||
256 | { | ||
257 | ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime)); | ||
258 | ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime)); | ||
259 | } | ||
252 | 260 | ||
253 | return ret; | 261 | return ret; |
254 | } | 262 | } |
255 | 263 | ||
256 | protected void AppendMeasuresOfInterest(StringBuilder sb) | 264 | // Compute the averages over time and return same. |
265 | // Return 'true' if averages were actually computed. 'false' if no average info. | ||
266 | public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime) | ||
257 | { | 267 | { |
258 | if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) | 268 | bool ret = false; |
259 | == MeasuresOfInterest.AverageChangeOverTime) | 269 | lastChangeOverTime = 0; |
270 | averageChangeOverTime = 0; | ||
271 | |||
272 | if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime) | ||
260 | { | 273 | { |
261 | double totalChange = 0; | 274 | double totalChange = 0; |
262 | double lastChangeOverTime = 0; | ||
263 | double? penultimateSample = null; | 275 | double? penultimateSample = null; |
264 | double? lastSample = null; | 276 | double? lastSample = null; |
265 | 277 | ||
266 | lock (m_samples) | 278 | lock (m_samples) |
267 | { | 279 | { |
268 | // m_log.DebugFormat( | 280 | // m_log.DebugFormat( |
269 | // "[STAT]: Samples for {0} are {1}", | 281 | // "[STAT]: Samples for {0} are {1}", |
270 | // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); | 282 | // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); |
271 | 283 | ||
272 | foreach (double s in m_samples) | 284 | foreach (double s in m_samples) |
273 | { | 285 | { |
@@ -280,13 +292,27 @@ namespace OpenSim.Framework.Monitoring | |||
280 | } | 292 | } |
281 | 293 | ||
282 | if (lastSample != null && penultimateSample != null) | 294 | if (lastSample != null && penultimateSample != null) |
283 | lastChangeOverTime | 295 | { |
296 | lastChangeOverTime | ||
284 | = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); | 297 | = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); |
298 | } | ||
285 | 299 | ||
286 | int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; | 300 | int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; |
287 | 301 | ||
288 | double averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); | 302 | averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); |
303 | ret = true; | ||
304 | } | ||
305 | |||
306 | return ret; | ||
307 | } | ||
289 | 308 | ||
309 | protected void AppendMeasuresOfInterest(StringBuilder sb) | ||
310 | { | ||
311 | double lastChangeOverTime = 0; | ||
312 | double averageChangeOverTime = 0; | ||
313 | |||
314 | if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) | ||
315 | { | ||
290 | sb.AppendFormat( | 316 | sb.AppendFormat( |
291 | ", {0:0.##}{1}/s, {2:0.##}{3}/s", | 317 | ", {0:0.##}{1}/s, {2:0.##}{3}/s", |
292 | lastChangeOverTime, | 318 | lastChangeOverTime, |
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index c8e838c..7cf1fa7 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs | |||
@@ -26,10 +26,12 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | ||
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
30 | using System.Linq; | 31 | using System.Linq; |
31 | using System.Text; | 32 | using System.Text; |
32 | 33 | ||
34 | using OpenSim.Framework; | ||
33 | using OpenMetaverse.StructuredData; | 35 | using OpenMetaverse.StructuredData; |
34 | 36 | ||
35 | namespace OpenSim.Framework.Monitoring | 37 | namespace OpenSim.Framework.Monitoring |
@@ -262,6 +264,41 @@ namespace OpenSim.Framework.Monitoring | |||
262 | return map; | 264 | return map; |
263 | } | 265 | } |
264 | 266 | ||
267 | public static Hashtable HandleStatsRequest(Hashtable request) | ||
268 | { | ||
269 | Hashtable responsedata = new Hashtable(); | ||
270 | string regpath = request["uri"].ToString(); | ||
271 | int response_code = 200; | ||
272 | string contenttype = "text/json"; | ||
273 | |||
274 | string pCategoryName = StatsManager.AllSubCommand; | ||
275 | string pContainerName = StatsManager.AllSubCommand; | ||
276 | string pStatName = StatsManager.AllSubCommand; | ||
277 | |||
278 | if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString(); | ||
279 | if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString(); | ||
280 | if (request.ContainsKey("stat")) pStatName = request["cat"].ToString(); | ||
281 | |||
282 | string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString(); | ||
283 | |||
284 | // If requestor wants it as a callback function, build response as a function rather than just the JSON string. | ||
285 | if (request.ContainsKey("callback")) | ||
286 | { | ||
287 | strOut = request["callback"].ToString() + "(" + strOut + ");"; | ||
288 | } | ||
289 | |||
290 | // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}", | ||
291 | // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut); | ||
292 | |||
293 | responsedata["int_response_code"] = response_code; | ||
294 | responsedata["content_type"] = contenttype; | ||
295 | responsedata["keepalive"] = false; | ||
296 | responsedata["str_response_string"] = strOut; | ||
297 | responsedata["access_control_allow_origin"] = "*"; | ||
298 | |||
299 | return responsedata; | ||
300 | } | ||
301 | |||
265 | // /// <summary> | 302 | // /// <summary> |
266 | // /// Start collecting statistics related to assets. | 303 | // /// Start collecting statistics related to assets. |
267 | // /// Should only be called once. | 304 | // /// Should only be called once. |
diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs index af5f164..3d5d1d2 100644 --- a/OpenSim/Framework/Tests/LocationTest.cs +++ b/OpenSim/Framework/Tests/LocationTest.cs | |||
@@ -55,11 +55,18 @@ namespace OpenSim.Framework.Tests | |||
55 | Location TestLocation2 = new Location(1095216660736000); | 55 | Location TestLocation2 = new Location(1095216660736000); |
56 | Assert.That(TestLocation1 == TestLocation2); | 56 | Assert.That(TestLocation1 == TestLocation2); |
57 | 57 | ||
58 | Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor"); | ||
58 | Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); | 59 | Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); |
59 | 60 | ||
60 | Assert.That(TestLocation2.RegionHandle == 1095216660736000, | 61 | Assert.That(TestLocation2.RegionHandle == 1095216660736000, |
61 | "Location RegionHandle Property didn't match regionhandle provided in constructor"); | 62 | "Location RegionHandle Property didn't match regionhandle provided in constructor"); |
62 | 63 | ||
64 | ulong RegionHandle = TestLocation1.RegionHandle; | ||
65 | Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor"); | ||
66 | |||
67 | TestLocation2 = new Location(RegionHandle); | ||
68 | Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor"); | ||
69 | |||
63 | 70 | ||
64 | TestLocation1 = new Location(255001, 256001); | 71 | TestLocation1 = new Location(255001, 256001); |
65 | TestLocation2 = new Location(1095216660736000); | 72 | TestLocation2 = new Location(1095216660736000); |
diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs index 11ca068..3b7f252 100644 --- a/OpenSim/Framework/Tests/UtilTest.cs +++ b/OpenSim/Framework/Tests/UtilTest.cs | |||
@@ -282,5 +282,87 @@ namespace OpenSim.Framework.Tests | |||
282 | String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i])); | 282 | String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i])); |
283 | } | 283 | } |
284 | } | 284 | } |
285 | |||
286 | [Test] | ||
287 | public void FakeParcelIDTests() | ||
288 | { | ||
289 | byte[] hexBytes8 = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; | ||
290 | byte[] hexBytes16 = { | ||
291 | 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, | ||
292 | 0x77, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f }; | ||
293 | UInt64 var64Bit = (UInt64)0xfedcba9876543210; | ||
294 | |||
295 | //Region handle is for location 255000,256000. | ||
296 | ulong regionHandle1 = 1095216660736000; | ||
297 | uint x1 = 100; | ||
298 | uint y1 = 200; | ||
299 | uint z1 = 22; | ||
300 | ulong regionHandle2; | ||
301 | uint x2, y2, z2; | ||
302 | UUID fakeParcelID1, fakeParcelID2, uuid; | ||
303 | |||
304 | ulong bigInt64 = Util.BytesToUInt64Big(hexBytes8); | ||
305 | Assert.AreEqual(var64Bit, bigInt64, | ||
306 | "BytesToUint64Bit conversion of 8 bytes to UInt64 failed."); | ||
307 | |||
308 | //Test building and decoding using some typical input values | ||
309 | fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1); | ||
310 | Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2); | ||
311 | Assert.AreEqual(regionHandle1, regionHandle2, | ||
312 | "region handle decoded from FakeParcelID wth X/Y failed."); | ||
313 | Assert.AreEqual(x1, x2, | ||
314 | "X coordinate decoded from FakeParcelID wth X/Y failed."); | ||
315 | Assert.AreEqual(y1, y2, | ||
316 | "Y coordinate decoded from FakeParcelID wth X/Y failed."); | ||
317 | |||
318 | fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1, z1); | ||
319 | Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2); | ||
320 | Assert.AreEqual(regionHandle1, regionHandle2, | ||
321 | "region handle decoded from FakeParcelID with X/Y/Z failed."); | ||
322 | Assert.AreEqual(x1, x2, | ||
323 | "X coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
324 | Assert.AreEqual(y1, y2, | ||
325 | "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
326 | Assert.AreEqual(z1, z2, | ||
327 | "Z coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
328 | |||
329 | //Do some more extreme tests to check the encoding and decoding | ||
330 | x1 = 0x55aa; | ||
331 | y1 = 0x9966; | ||
332 | z1 = 0x5a96; | ||
333 | |||
334 | fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1); | ||
335 | Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2); | ||
336 | Assert.AreEqual(var64Bit, regionHandle2, | ||
337 | "region handle decoded from FakeParcelID with X/Y/Z failed."); | ||
338 | Assert.AreEqual(x1, x2, | ||
339 | "X coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
340 | Assert.AreEqual(y1, y2, | ||
341 | "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
342 | |||
343 | fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1, z1); | ||
344 | Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2); | ||
345 | Assert.AreEqual(var64Bit, regionHandle2, | ||
346 | "region handle decoded from FakeParcelID with X/Y/Z failed."); | ||
347 | Assert.AreEqual(x1, x2, | ||
348 | "X coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
349 | Assert.AreEqual(y1, y2, | ||
350 | "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
351 | Assert.AreEqual(z1, z2, | ||
352 | "Z coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
353 | |||
354 | |||
355 | x1 = 64; | ||
356 | y1 = 192; | ||
357 | fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1); | ||
358 | Util.FakeParcelIDToGlobalPosition(fakeParcelID1, out x2, out y2); | ||
359 | Assert.AreEqual(255000+x1, x2, | ||
360 | "Global X coordinate decoded from regionHandle failed."); | ||
361 | Assert.AreEqual(256000+y1, y2, | ||
362 | "Global Y coordinate decoded from regionHandle failed."); | ||
363 | |||
364 | uuid = new UUID("00dd0700-00d1-0700-3800-000032000000"); | ||
365 | Util.FakeParcelIDToGlobalPosition(uuid, out x2, out y2); | ||
366 | } | ||
285 | } | 367 | } |
286 | } | 368 | } |
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 19d40db..7398b37 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -1259,7 +1259,7 @@ namespace OpenSim.Framework | |||
1259 | byte[] bytes = | 1259 | byte[] bytes = |
1260 | { | 1260 | { |
1261 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), | 1261 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), |
1262 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), | 1262 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), |
1263 | (byte)x, (byte)(x >> 8), 0, 0, | 1263 | (byte)x, (byte)(x >> 8), 0, 0, |
1264 | (byte)y, (byte)(y >> 8), 0, 0 }; | 1264 | (byte)y, (byte)(y >> 8), 0, 0 }; |
1265 | return new UUID(bytes, 0); | 1265 | return new UUID(bytes, 0); |
@@ -1270,7 +1270,7 @@ namespace OpenSim.Framework | |||
1270 | byte[] bytes = | 1270 | byte[] bytes = |
1271 | { | 1271 | { |
1272 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), | 1272 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), |
1273 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), | 1273 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), |
1274 | (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), | 1274 | (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), |
1275 | (byte)y, (byte)(y >> 8), 0, 0 }; | 1275 | (byte)y, (byte)(y >> 8), 0, 0 }; |
1276 | return new UUID(bytes, 0); | 1276 | return new UUID(bytes, 0); |
diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index 2e155ec..3a4e5df 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs | |||
@@ -142,19 +142,19 @@ namespace OpenSim | |||
142 | if (iocpThreads < iocpThreadsMin) | 142 | if (iocpThreads < iocpThreadsMin) |
143 | { | 143 | { |
144 | iocpThreads = iocpThreadsMin; | 144 | iocpThreads = iocpThreadsMin; |
145 | m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IO completion threads to {0}",iocpThreads); | 145 | m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IOCP threads to {0}",iocpThreads); |
146 | } | 146 | } |
147 | // Make sure we don't overallocate IOCP threads and thrash system resources | 147 | // Make sure we don't overallocate IOCP threads and thrash system resources |
148 | if ( iocpThreads > iocpThreadsMax ) | 148 | if ( iocpThreads > iocpThreadsMax ) |
149 | { | 149 | { |
150 | iocpThreads = iocpThreadsMax; | 150 | iocpThreads = iocpThreadsMax; |
151 | m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IO completion threads to {0}",iocpThreads); | 151 | m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IOCP completion threads to {0}",iocpThreads); |
152 | } | 152 | } |
153 | // set the resulting worker and IO completion thread counts back to ThreadPool | 153 | // set the resulting worker and IO completion thread counts back to ThreadPool |
154 | if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) ) | 154 | if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) ) |
155 | { | 155 | { |
156 | m_log.InfoFormat( | 156 | m_log.InfoFormat( |
157 | "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IO completion threads", | 157 | "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IOCP threads", |
158 | workerThreads, iocpThreads); | 158 | workerThreads, iocpThreads); |
159 | } | 159 | } |
160 | else | 160 | else |
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 6dd1f5b..a18a6fe 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs | |||
@@ -172,6 +172,13 @@ namespace OpenSim | |||
172 | if (userStatsURI != String.Empty) | 172 | if (userStatsURI != String.Empty) |
173 | MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this)); | 173 | MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this)); |
174 | 174 | ||
175 | if (managedStatsURI != String.Empty) | ||
176 | { | ||
177 | string urlBase = String.Format("/{0}/", managedStatsURI); | ||
178 | MainServer.Instance.AddHTTPHandler(urlBase, StatsManager.HandleStatsRequest); | ||
179 | m_log.InfoFormat("[OPENSIM] Enabling remote managed stats fetch. URL = {0}", urlBase); | ||
180 | } | ||
181 | |||
175 | if (m_console is RemoteConsole) | 182 | if (m_console is RemoteConsole) |
176 | { | 183 | { |
177 | if (m_consolePort == 0) | 184 | if (m_consolePort == 0) |
@@ -348,18 +355,6 @@ namespace OpenSim | |||
348 | m_console.Commands.AddCommand("Regions", false, "delete-region", | 355 | m_console.Commands.AddCommand("Regions", false, "delete-region", |
349 | "delete-region <name>", | 356 | "delete-region <name>", |
350 | "Delete a region from disk", RunCommand); | 357 | "Delete a region from disk", RunCommand); |
351 | |||
352 | m_console.Commands.AddCommand("General", false, "modules list", | ||
353 | "modules list", | ||
354 | "List modules", HandleModules); | ||
355 | |||
356 | m_console.Commands.AddCommand("General", false, "modules load", | ||
357 | "modules load <name>", | ||
358 | "Load a module", HandleModules); | ||
359 | |||
360 | m_console.Commands.AddCommand("General", false, "modules unload", | ||
361 | "modules unload <name>", | ||
362 | "Unload a module", HandleModules); | ||
363 | } | 358 | } |
364 | 359 | ||
365 | protected override void ShutdownSpecific() | 360 | protected override void ShutdownSpecific() |
@@ -557,34 +552,6 @@ namespace OpenSim | |||
557 | } | 552 | } |
558 | 553 | ||
559 | /// <summary> | 554 | /// <summary> |
560 | /// Load, Unload, and list Region modules in use | ||
561 | /// </summary> | ||
562 | /// <param name="module"></param> | ||
563 | /// <param name="cmd"></param> | ||
564 | private void HandleModules(string module, string[] cmd) | ||
565 | { | ||
566 | List<string> args = new List<string>(cmd); | ||
567 | args.RemoveAt(0); | ||
568 | string[] cmdparams = args.ToArray(); | ||
569 | |||
570 | if (cmdparams.Length > 0) | ||
571 | { | ||
572 | switch (cmdparams[0].ToLower()) | ||
573 | { | ||
574 | case "list": | ||
575 | //TODO: Convert to new region modules | ||
576 | break; | ||
577 | case "unload": | ||
578 | //TODO: Convert to new region modules | ||
579 | break; | ||
580 | case "load": | ||
581 | //TODO: Convert to new region modules | ||
582 | break; | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | /// <summary> | ||
588 | /// Runs commands issued by the server console from the operator | 555 | /// Runs commands issued by the server console from the operator |
589 | /// </summary> | 556 | /// </summary> |
590 | /// <param name="command">The first argument of the parameter (the command)</param> | 557 | /// <param name="command">The first argument of the parameter (the command)</param> |
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index db76529..0f3bac4 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs | |||
@@ -75,6 +75,7 @@ namespace OpenSim | |||
75 | protected int proxyOffset = 0; | 75 | protected int proxyOffset = 0; |
76 | 76 | ||
77 | public string userStatsURI = String.Empty; | 77 | public string userStatsURI = String.Empty; |
78 | public string managedStatsURI = String.Empty; | ||
78 | 79 | ||
79 | protected bool m_autoCreateClientStack = true; | 80 | protected bool m_autoCreateClientStack = true; |
80 | 81 | ||
@@ -197,6 +198,8 @@ namespace OpenSim | |||
197 | 198 | ||
198 | string permissionModules = startupConfig.GetString("permissionmodules", "DefaultPermissionsModule"); | 199 | string permissionModules = startupConfig.GetString("permissionmodules", "DefaultPermissionsModule"); |
199 | m_permsModules = new List<string>(permissionModules.Split(',')); | 200 | m_permsModules = new List<string>(permissionModules.Split(',')); |
201 | |||
202 | managedStatsURI = startupConfig.GetString("ManagedStatsRemoteFetchURI", String.Empty); | ||
200 | } | 203 | } |
201 | 204 | ||
202 | // Load the simulation data service | 205 | // Load the simulation data service |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index 141af8a..626932f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs | |||
@@ -91,7 +91,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests | |||
91 | public void RemoveForClient() | 91 | public void RemoveForClient() |
92 | { | 92 | { |
93 | TestHelpers.InMethod(); | 93 | TestHelpers.InMethod(); |
94 | // log4net.Config.XmlConfigurator.Configure(); | 94 | // TestHelpers.EnableLogging(); |
95 | 95 | ||
96 | UUID spId = TestHelpers.ParseTail(0x1); | 96 | UUID spId = TestHelpers.ParseTail(0x1); |
97 | 97 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 0e20e38..8cbbfd9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -337,6 +337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
337 | private bool m_VelocityInterpolate = false; | 337 | private bool m_VelocityInterpolate = false; |
338 | private const uint MaxTransferBytesPerPacket = 600; | 338 | private const uint MaxTransferBytesPerPacket = 600; |
339 | 339 | ||
340 | private volatile bool m_justEditedTerrain = false; | ||
340 | 341 | ||
341 | /// <value> | 342 | /// <value> |
342 | /// List used in construction of data blocks for an object update packet. This is to stop us having to | 343 | /// 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 | |||
536 | // We still perform a force close inside the sync lock since this is intended to attempt close where | 537 | // We still perform a force close inside the sync lock since this is intended to attempt close where |
537 | // there is some unidentified connection problem, not where we have issues due to deadlock | 538 | // there is some unidentified connection problem, not where we have issues due to deadlock |
538 | if (!IsActive && !force) | 539 | if (!IsActive && !force) |
540 | { | ||
541 | m_log.DebugFormat( | ||
542 | "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set", | ||
543 | Name, m_scene.Name); | ||
544 | |||
539 | return; | 545 | return; |
546 | } | ||
540 | 547 | ||
541 | IsActive = false; | 548 | IsActive = false; |
542 | CloseWithoutChecks(sendStop); | 549 | CloseWithoutChecks(sendStop); |
@@ -1231,9 +1238,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1231 | LLHeightFieldMoronize(map); | 1238 | LLHeightFieldMoronize(map); |
1232 | 1239 | ||
1233 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); | 1240 | LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); |
1234 | layerpack.Header.Reliable = true; | 1241 | |
1242 | // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. | ||
1243 | // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. | ||
1244 | // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area | ||
1245 | // invalidating previous packets for that area. | ||
1246 | |||
1247 | // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a | ||
1248 | // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower. | ||
1249 | |||
1250 | // 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 | ||
1251 | // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain | ||
1252 | // patches. | ||
1235 | 1253 | ||
1236 | OutPacket(layerpack, ThrottleOutPacketType.Task); | 1254 | // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss. |
1255 | if (m_justEditedTerrain) | ||
1256 | { | ||
1257 | layerpack.Header.Reliable = false; | ||
1258 | OutPacket(layerpack, | ||
1259 | ThrottleOutPacketType.Unknown ); | ||
1260 | } | ||
1261 | else | ||
1262 | { | ||
1263 | layerpack.Header.Reliable = true; | ||
1264 | OutPacket(layerpack, | ||
1265 | ThrottleOutPacketType.Task); | ||
1266 | } | ||
1237 | } | 1267 | } |
1238 | catch (Exception e) | 1268 | catch (Exception e) |
1239 | { | 1269 | { |
@@ -6367,6 +6397,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6367 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); | 6397 | //m_log.Info("[LAND]: LAND:" + modify.ToString()); |
6368 | if (modify.ParcelData.Length > 0) | 6398 | if (modify.ParcelData.Length > 0) |
6369 | { | 6399 | { |
6400 | // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, | ||
6401 | // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit. | ||
6402 | m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable | ||
6370 | if (OnModifyTerrain != null) | 6403 | if (OnModifyTerrain != null) |
6371 | { | 6404 | { |
6372 | for (int i = 0; i < modify.ParcelData.Length; i++) | 6405 | for (int i = 0; i < modify.ParcelData.Length; i++) |
@@ -6382,6 +6415,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
6382 | } | 6415 | } |
6383 | } | 6416 | } |
6384 | } | 6417 | } |
6418 | m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again | ||
6385 | } | 6419 | } |
6386 | 6420 | ||
6387 | return true; | 6421 | return true; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 71b464b..0431b53 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -1871,9 +1871,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1871 | 1871 | ||
1872 | if (!client.SceneAgent.IsChildAgent) | 1872 | if (!client.SceneAgent.IsChildAgent) |
1873 | client.Kick("Simulator logged you out due to connection timeout."); | 1873 | client.Kick("Simulator logged you out due to connection timeout."); |
1874 | |||
1875 | client.CloseWithoutChecks(true); | ||
1876 | } | 1874 | } |
1875 | |||
1876 | m_scene.IncomingCloseAgent(client.AgentId, true); | ||
1877 | } | 1877 | } |
1878 | 1878 | ||
1879 | private void IncomingPacketHandler() | 1879 | private void IncomingPacketHandler() |
@@ -2216,7 +2216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2216 | if (!client.IsLoggingOut) | 2216 | if (!client.IsLoggingOut) |
2217 | { | 2217 | { |
2218 | client.IsLoggingOut = true; | 2218 | client.IsLoggingOut = true; |
2219 | client.Close(false, false); | 2219 | m_scene.IncomingCloseAgent(client.AgentId, false); |
2220 | } | 2220 | } |
2221 | } | 2221 | } |
2222 | } | 2222 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index b47ff54..9700224 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs | |||
@@ -200,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
200 | public void TestLogoutClientDueToAck() | 200 | public void TestLogoutClientDueToAck() |
201 | { | 201 | { |
202 | TestHelpers.InMethod(); | 202 | TestHelpers.InMethod(); |
203 | // TestHelpers.EnableLogging(); | 203 | TestHelpers.EnableLogging(); |
204 | 204 | ||
205 | IniConfigSource ics = new IniConfigSource(); | 205 | IniConfigSource ics = new IniConfigSource(); |
206 | IConfig config = ics.AddConfig("ClientStack.LindenUDP"); | 206 | IConfig config = ics.AddConfig("ClientStack.LindenUDP"); |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 4286eef..711167f 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -1069,8 +1069,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1069 | // Now let's make it officially a child agent | 1069 | // Now let's make it officially a child agent |
1070 | sp.MakeChildAgent(); | 1070 | sp.MakeChildAgent(); |
1071 | 1071 | ||
1072 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone | 1072 | // May still need to signal neighbours whether child agents may need closing irrespective of whether this |
1073 | // one needed closing. Neighbour regions also contain logic to prevent a close if a subsequent move or | ||
1074 | // teleport re-established the child connection. | ||
1075 | // | ||
1076 | // It may be possible to also close child agents after a pause but one needs to be very careful about | ||
1077 | // race conditions between different regions on rapid teleporting (e.g. from A1 to a non-neighbour B, back | ||
1078 | // to a neighbour A2 then off to a non-neighbour C. Also, closing child agents early may be more compatible | ||
1079 | // with complicated scenarios where there a mixture of V1 and V2 teleports, though this is conjecture. It's | ||
1080 | // easier to close immediately and greatly reduce the scope of race conditions if possible. | ||
1081 | sp.CloseChildAgents(newRegionX, newRegionY); | ||
1073 | 1082 | ||
1083 | // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone | ||
1074 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) | 1084 | if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) |
1075 | { | 1085 | { |
1076 | sp.DoNotCloseAfterTeleport = false; | 1086 | sp.DoNotCloseAfterTeleport = false; |
@@ -1086,14 +1096,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1086 | if (!sp.DoNotCloseAfterTeleport) | 1096 | if (!sp.DoNotCloseAfterTeleport) |
1087 | { | 1097 | { |
1088 | // OK, it got this agent. Let's close everything | 1098 | // OK, it got this agent. Let's close everything |
1089 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.Name); | 1099 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing agent {0} in {1}", sp.Name, Scene.Name); |
1090 | sp.CloseChildAgents(newRegionX, newRegionY); | ||
1091 | sp.Scene.IncomingCloseAgent(sp.UUID, false); | 1100 | sp.Scene.IncomingCloseAgent(sp.UUID, false); |
1092 | |||
1093 | } | 1101 | } |
1094 | else | 1102 | else |
1095 | { | 1103 | { |
1096 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.Name); | 1104 | m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {1}", sp.Name, Scene.Name); |
1097 | sp.DoNotCloseAfterTeleport = false; | 1105 | sp.DoNotCloseAfterTeleport = false; |
1098 | } | 1106 | } |
1099 | } | 1107 | } |
@@ -1836,10 +1844,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1836 | List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); | 1844 | List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); |
1837 | List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); | 1845 | List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); |
1838 | 1846 | ||
1839 | //Dump("Current Neighbors", neighbourHandles); | 1847 | // Dump("Current Neighbors", neighbourHandles); |
1840 | //Dump("Previous Neighbours", previousRegionNeighbourHandles); | 1848 | // Dump("Previous Neighbours", previousRegionNeighbourHandles); |
1841 | //Dump("New Neighbours", newRegions); | 1849 | // Dump("New Neighbours", newRegions); |
1842 | //Dump("Old Neighbours", oldRegions); | 1850 | // Dump("Old Neighbours", oldRegions); |
1843 | 1851 | ||
1844 | /// Update the scene presence's known regions here on this region | 1852 | /// Update the scene presence's known regions here on this region |
1845 | sp.DropOldNeighbours(oldRegions); | 1853 | sp.DropOldNeighbours(oldRegions); |
@@ -1847,8 +1855,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1847 | /// Collect as many seeds as possible | 1855 | /// Collect as many seeds as possible |
1848 | Dictionary<ulong, string> seeds; | 1856 | Dictionary<ulong, string> seeds; |
1849 | if (sp.Scene.CapsModule != null) | 1857 | if (sp.Scene.CapsModule != null) |
1850 | seeds | 1858 | seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); |
1851 | = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); | ||
1852 | else | 1859 | else |
1853 | seeds = new Dictionary<ulong, string>(); | 1860 | seeds = new Dictionary<ulong, string>(); |
1854 | 1861 | ||
@@ -1918,6 +1925,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1918 | newAgent = true; | 1925 | newAgent = true; |
1919 | else | 1926 | else |
1920 | newAgent = false; | 1927 | newAgent = false; |
1928 | // continue; | ||
1921 | 1929 | ||
1922 | if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) | 1930 | if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) |
1923 | { | 1931 | { |
diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs index bb304df..ad33f23 100644 --- a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs | |||
@@ -45,6 +45,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms | |||
45 | { | 45 | { |
46 | private static readonly ILog m_log = | 46 | private static readonly ILog m_log = |
47 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | private static string LogHeader = "[MODULE COMMS]"; | ||
48 | 49 | ||
49 | private Dictionary<string,object> m_constants = new Dictionary<string,object>(); | 50 | private Dictionary<string,object> m_constants = new Dictionary<string,object>(); |
50 | 51 | ||
@@ -148,7 +149,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms | |||
148 | MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true); | 149 | MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true); |
149 | if (mi == null) | 150 | if (mi == null) |
150 | { | 151 | { |
151 | m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", meth); | 152 | m_log.WarnFormat("{0} Failed to register method {1}", LogHeader, meth); |
152 | return; | 153 | return; |
153 | } | 154 | } |
154 | 155 | ||
@@ -165,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms | |||
165 | { | 166 | { |
166 | // m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name); | 167 | // m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name); |
167 | 168 | ||
168 | Type delegateType; | 169 | Type delegateType = typeof(void); |
169 | List<Type> typeArgs = mi.GetParameters() | 170 | List<Type> typeArgs = mi.GetParameters() |
170 | .Select(p => p.ParameterType) | 171 | .Select(p => p.ParameterType) |
171 | .ToList(); | 172 | .ToList(); |
@@ -176,8 +177,16 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms | |||
176 | } | 177 | } |
177 | else | 178 | else |
178 | { | 179 | { |
179 | typeArgs.Add(mi.ReturnType); | 180 | try |
180 | delegateType = Expression.GetFuncType(typeArgs.ToArray()); | 181 | { |
182 | typeArgs.Add(mi.ReturnType); | ||
183 | delegateType = Expression.GetFuncType(typeArgs.ToArray()); | ||
184 | } | ||
185 | catch (Exception e) | ||
186 | { | ||
187 | m_log.ErrorFormat("{0} Failed to create function signature. Most likely more than 5 parameters. Method={1}. Error={2}", | ||
188 | LogHeader, mi.Name, e); | ||
189 | } | ||
181 | } | 190 | } |
182 | 191 | ||
183 | Delegate fcall; | 192 | Delegate fcall; |
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs index 4d49794..173b603 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs | |||
@@ -76,6 +76,13 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
76 | " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.", | 76 | " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.", |
77 | consoleSetTerrainHeights); | 77 | consoleSetTerrainHeights); |
78 | 78 | ||
79 | m_module.Scene.AddCommand("Regions", m_module, "set water height", | ||
80 | "set water height <height> [<x>] [<y>]", | ||
81 | "Sets the water height in meters. If <x> and <y> are specified, it will only set it on regions with a matching coordinate. " + | ||
82 | "Specify -1 in <x> or <y> to wildcard that coordinate.", | ||
83 | consoleSetWaterHeight); | ||
84 | |||
85 | |||
79 | m_module.Scene.AddCommand( | 86 | m_module.Scene.AddCommand( |
80 | "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand); | 87 | "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand); |
81 | } | 88 | } |
@@ -121,7 +128,29 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
121 | } | 128 | } |
122 | } | 129 | } |
123 | } | 130 | } |
124 | 131 | protected void consoleSetWaterHeight(string module, string[] args) | |
132 | { | ||
133 | string heightstring = args[3]; | ||
134 | |||
135 | int x = (args.Length > 4 ? int.Parse(args[4]) : -1); | ||
136 | int y = (args.Length > 5 ? int.Parse(args[5]) : -1); | ||
137 | |||
138 | if (x == -1 || m_module.Scene.RegionInfo.RegionLocX == x) | ||
139 | { | ||
140 | if (y == -1 || m_module.Scene.RegionInfo.RegionLocY == y) | ||
141 | { | ||
142 | double selectedheight = double.Parse(heightstring); | ||
143 | |||
144 | m_log.Debug("[ESTATEMODULE]: Setting water height in " + m_module.Scene.RegionInfo.RegionName + " to " + | ||
145 | string.Format(" {0}", selectedheight)); | ||
146 | m_module.Scene.RegionInfo.RegionSettings.WaterHeight = selectedheight; | ||
147 | |||
148 | m_module.Scene.RegionInfo.RegionSettings.Save(); | ||
149 | m_module.TriggerRegionInfoChange(); | ||
150 | m_module.sendRegionHandshakeToAll(); | ||
151 | } | ||
152 | } | ||
153 | } | ||
125 | protected void consoleSetTerrainHeights(string module, string[] args) | 154 | protected void consoleSetTerrainHeights(string module, string[] args) |
126 | { | 155 | { |
127 | string num = args[3]; | 156 | string num = args[3]; |
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index a5f5749..1808fdd 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs | |||
@@ -572,7 +572,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
572 | if (!Scene.TeleportClientHome(user, s.ControllingClient)) | 572 | if (!Scene.TeleportClientHome(user, s.ControllingClient)) |
573 | { | 573 | { |
574 | s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); | 574 | s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); |
575 | s.ControllingClient.Close(); | 575 | Scene.IncomingCloseAgent(s.UUID, false); |
576 | } | 576 | } |
577 | } | 577 | } |
578 | } | 578 | } |
@@ -807,7 +807,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
807 | if (!Scene.TeleportClientHome(prey, s.ControllingClient)) | 807 | if (!Scene.TeleportClientHome(prey, s.ControllingClient)) |
808 | { | 808 | { |
809 | s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); | 809 | s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); |
810 | s.ControllingClient.Close(); | 810 | Scene.IncomingCloseAgent(s.UUID, false); |
811 | } | 811 | } |
812 | } | 812 | } |
813 | } | 813 | } |
@@ -830,7 +830,7 @@ namespace OpenSim.Region.CoreModules.World.Estate | |||
830 | if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient)) | 830 | if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient)) |
831 | { | 831 | { |
832 | p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); | 832 | p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); |
833 | p.ControllingClient.Close(); | 833 | Scene.IncomingCloseAgent(p.UUID, false); |
834 | } | 834 | } |
835 | } | 835 | } |
836 | } | 836 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index aa09092..6323a88 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -151,7 +151,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
151 | public SynchronizeSceneHandler SynchronizeScene; | 151 | public SynchronizeSceneHandler SynchronizeScene; |
152 | 152 | ||
153 | /// <summary> | 153 | /// <summary> |
154 | /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other. | 154 | /// Used to prevent simultaneous calls to code that adds and removes agents. |
155 | /// </summary> | 155 | /// </summary> |
156 | private object m_removeClientLock = new object(); | 156 | private object m_removeClientLock = new object(); |
157 | 157 | ||
@@ -1338,7 +1338,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1338 | Thread.Sleep(500); | 1338 | Thread.Sleep(500); |
1339 | 1339 | ||
1340 | // Stop all client threads. | 1340 | // Stop all client threads. |
1341 | ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); }); | 1341 | ForEachScenePresence(delegate(ScenePresence avatar) { IncomingCloseAgent(avatar.UUID, false); }); |
1342 | 1342 | ||
1343 | m_log.Debug("[SCENE]: TriggerSceneShuttingDown"); | 1343 | m_log.Debug("[SCENE]: TriggerSceneShuttingDown"); |
1344 | EventManager.TriggerSceneShuttingDown(this); | 1344 | EventManager.TriggerSceneShuttingDown(this); |
@@ -3127,7 +3127,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3127 | if (sp != null) | 3127 | if (sp != null) |
3128 | { | 3128 | { |
3129 | PresenceService.LogoutAgent(sp.ControllingClient.SessionId); | 3129 | PresenceService.LogoutAgent(sp.ControllingClient.SessionId); |
3130 | sp.ControllingClient.Close(); | 3130 | |
3131 | IncomingCloseAgent(sp.UUID, false); | ||
3131 | } | 3132 | } |
3132 | 3133 | ||
3133 | // BANG! SLASH! | 3134 | // BANG! SLASH! |
@@ -3541,47 +3542,48 @@ namespace OpenSim.Region.Framework.Scenes | |||
3541 | 3542 | ||
3542 | public override void RemoveClient(UUID agentID, bool closeChildAgents) | 3543 | public override void RemoveClient(UUID agentID, bool closeChildAgents) |
3543 | { | 3544 | { |
3544 | // CheckHeartbeat(); | 3545 | AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID); |
3545 | bool isChildAgent = false; | ||
3546 | AgentCircuitData acd; | ||
3547 | 3546 | ||
3548 | lock (m_removeClientLock) | 3547 | // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which |
3548 | // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not | ||
3549 | // However, will keep for now just in case. | ||
3550 | if (acd == null) | ||
3549 | { | 3551 | { |
3550 | acd = m_authenticateHandler.GetAgentCircuitData(agentID); | 3552 | m_log.ErrorFormat( |
3553 | "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name); | ||
3551 | 3554 | ||
3552 | if (acd == null) | 3555 | return; |
3553 | { | 3556 | } |
3554 | m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID); | 3557 | else |
3555 | return; | 3558 | { |
3556 | } | 3559 | m_authenticateHandler.RemoveCircuit(agentID); |
3557 | else | ||
3558 | { | ||
3559 | // We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred | ||
3560 | // simultaneously. | ||
3561 | // We also need to remove by agent ID since NPCs will have no circuit code. | ||
3562 | m_authenticateHandler.RemoveCircuit(agentID); | ||
3563 | } | ||
3564 | } | 3560 | } |
3565 | 3561 | ||
3562 | // TODO: Can we now remove this lock? | ||
3566 | lock (acd) | 3563 | lock (acd) |
3567 | { | 3564 | { |
3565 | bool isChildAgent = false; | ||
3566 | |||
3568 | ScenePresence avatar = GetScenePresence(agentID); | 3567 | ScenePresence avatar = GetScenePresence(agentID); |
3569 | 3568 | ||
3569 | // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which | ||
3570 | // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not | ||
3571 | // However, will keep for now just in case. | ||
3570 | if (avatar == null) | 3572 | if (avatar == null) |
3571 | { | 3573 | { |
3572 | m_log.WarnFormat( | 3574 | m_log.ErrorFormat( |
3573 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); | 3575 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); |
3574 | 3576 | ||
3575 | return; | 3577 | return; |
3576 | } | 3578 | } |
3577 | 3579 | ||
3578 | try | 3580 | try |
3579 | { | 3581 | { |
3580 | isChildAgent = avatar.IsChildAgent; | 3582 | isChildAgent = avatar.IsChildAgent; |
3581 | 3583 | ||
3582 | m_log.DebugFormat( | 3584 | m_log.DebugFormat( |
3583 | "[SCENE]: Removing {0} agent {1} {2} from {3}", | 3585 | "[SCENE]: Removing {0} agent {1} {2} from {3}", |
3584 | (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); | 3586 | isChildAgent ? "child" : "root", avatar.Name, agentID, Name); |
3585 | 3587 | ||
3586 | // Don't do this to root agents, it's not nice for the viewer | 3588 | // Don't do this to root agents, it's not nice for the viewer |
3587 | if (closeChildAgents && isChildAgent) | 3589 | if (closeChildAgents && isChildAgent) |
@@ -3745,13 +3747,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3745 | /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of | 3747 | /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of |
3746 | /// the LLUDP stack). | 3748 | /// the LLUDP stack). |
3747 | /// </remarks> | 3749 | /// </remarks> |
3748 | /// <param name="agent">CircuitData of the agent who is connecting</param> | 3750 | /// <param name="acd">CircuitData of the agent who is connecting</param> |
3749 | /// <param name="reason">Outputs the reason for the false response on this string</param> | 3751 | /// <param name="reason">Outputs the reason for the false response on this string</param> |
3750 | /// <param name="requirePresenceLookup">True for normal presence. False for NPC | 3752 | /// <param name="requirePresenceLookup">True for normal presence. False for NPC |
3751 | /// or other applications where a full grid/Hypergrid presence may not be required.</param> | 3753 | /// or other applications where a full grid/Hypergrid presence may not be required.</param> |
3752 | /// <returns>True if the region accepts this agent. False if it does not. False will | 3754 | /// <returns>True if the region accepts this agent. False if it does not. False will |
3753 | /// also return a reason.</returns> | 3755 | /// also return a reason.</returns> |
3754 | public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup) | 3756 | public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, out string reason, bool requirePresenceLookup) |
3755 | { | 3757 | { |
3756 | bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || | 3758 | bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || |
3757 | (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); | 3759 | (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); |
@@ -3771,15 +3773,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
3771 | m_log.DebugFormat( | 3773 | m_log.DebugFormat( |
3772 | "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", | 3774 | "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", |
3773 | RegionInfo.RegionName, | 3775 | RegionInfo.RegionName, |
3774 | (agent.child ? "child" : "root"), | 3776 | (acd.child ? "child" : "root"), |
3775 | agent.firstname, | 3777 | acd.firstname, |
3776 | agent.lastname, | 3778 | acd.lastname, |
3777 | agent.AgentID, | 3779 | acd.AgentID, |
3778 | agent.circuitcode, | 3780 | acd.circuitcode, |
3779 | agent.IPAddress, | 3781 | acd.IPAddress, |
3780 | agent.Viewer, | 3782 | acd.Viewer, |
3781 | ((TPFlags)teleportFlags).ToString(), | 3783 | ((TPFlags)teleportFlags).ToString(), |
3782 | agent.startpos | 3784 | acd.startpos |
3783 | ); | 3785 | ); |
3784 | 3786 | ||
3785 | if (!LoginsEnabled) | 3787 | if (!LoginsEnabled) |
@@ -3797,7 +3799,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3797 | { | 3799 | { |
3798 | foreach (string viewer in m_AllowedViewers) | 3800 | foreach (string viewer in m_AllowedViewers) |
3799 | { | 3801 | { |
3800 | if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) | 3802 | if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower()) |
3801 | { | 3803 | { |
3802 | ViewerDenied = false; | 3804 | ViewerDenied = false; |
3803 | break; | 3805 | break; |
@@ -3814,7 +3816,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3814 | { | 3816 | { |
3815 | foreach (string viewer in m_BannedViewers) | 3817 | foreach (string viewer in m_BannedViewers) |
3816 | { | 3818 | { |
3817 | if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) | 3819 | if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower()) |
3818 | { | 3820 | { |
3819 | ViewerDenied = true; | 3821 | ViewerDenied = true; |
3820 | break; | 3822 | break; |
@@ -3826,61 +3828,115 @@ namespace OpenSim.Region.Framework.Scenes | |||
3826 | { | 3828 | { |
3827 | m_log.DebugFormat( | 3829 | m_log.DebugFormat( |
3828 | "[SCENE]: Access denied for {0} {1} using {2}", | 3830 | "[SCENE]: Access denied for {0} {1} using {2}", |
3829 | agent.firstname, agent.lastname, agent.Viewer); | 3831 | acd.firstname, acd.lastname, acd.Viewer); |
3830 | reason = "Access denied, your viewer is banned by the region owner"; | 3832 | reason = "Access denied, your viewer is banned by the region owner"; |
3831 | return false; | 3833 | return false; |
3832 | } | 3834 | } |
3835 | |||
3836 | ILandObject land; | ||
3837 | ScenePresence sp; | ||
3833 | 3838 | ||
3834 | lock (agent) | 3839 | lock (m_removeClientLock) |
3835 | { | 3840 | { |
3836 | ScenePresence sp = GetScenePresence(agent.AgentID); | 3841 | sp = GetScenePresence(acd.AgentID); |
3837 | 3842 | ||
3838 | if (sp != null) | 3843 | // We need to ensure that we are not already removing the scene presence before we ask it not to be |
3844 | // closed. | ||
3845 | if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running) | ||
3839 | { | 3846 | { |
3840 | if (!sp.IsChildAgent) | 3847 | m_log.DebugFormat( |
3841 | { | 3848 | "[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name); |
3842 | // We have a root agent. Is it in transit? | ||
3843 | if (!EntityTransferModule.IsInTransit(sp.UUID)) | ||
3844 | { | ||
3845 | // We have a zombie from a crashed session. | ||
3846 | // Or the same user is trying to be root twice here, won't work. | ||
3847 | // Kill it. | ||
3848 | m_log.WarnFormat( | ||
3849 | "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", | ||
3850 | sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3851 | 3849 | ||
3852 | if (sp.ControllingClient != null) | 3850 | // In the case where, for example, an A B C D region layout, an avatar may |
3853 | sp.ControllingClient.Close(true, true); | 3851 | // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C |
3852 | // renews the lease on the child agent at B, we must make sure that the close from A does not succeed. | ||
3853 | if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle)) | ||
3854 | { | ||
3855 | m_log.DebugFormat( | ||
3856 | "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.", | ||
3857 | sp.Name, Name); | ||
3854 | 3858 | ||
3855 | sp = null; | 3859 | sp.DoNotCloseAfterTeleport = true; |
3856 | } | ||
3857 | //else | ||
3858 | // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3859 | } | 3860 | } |
3860 | else | 3861 | else if (EntityTransferModule.IsInTransit(sp.UUID)) |
3861 | { | 3862 | { |
3862 | // We have a child agent here | 3863 | m_log.DebugFormat( |
3864 | "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt previous end-of-teleport close.", | ||
3865 | sp.Name, Name); | ||
3866 | |||
3863 | sp.DoNotCloseAfterTeleport = true; | 3867 | sp.DoNotCloseAfterTeleport = true; |
3864 | //m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3865 | } | 3868 | } |
3866 | } | 3869 | } |
3870 | } | ||
3871 | |||
3872 | // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will | ||
3873 | // allow unpredictable things to happen. | ||
3874 | if (sp != null) | ||
3875 | { | ||
3876 | const int polls = 10; | ||
3877 | const int pollInterval = 1000; | ||
3878 | int pollsLeft = polls; | ||
3879 | |||
3880 | while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0) | ||
3881 | Thread.Sleep(pollInterval); | ||
3882 | |||
3883 | if (sp.LifecycleState == ScenePresenceState.Removing) | ||
3884 | { | ||
3885 | m_log.WarnFormat( | ||
3886 | "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.", | ||
3887 | sp.Name, Name, polls * pollInterval / 1000); | ||
3888 | |||
3889 | return false; | ||
3890 | } | ||
3891 | else if (polls != pollsLeft) | ||
3892 | { | ||
3893 | m_log.DebugFormat( | ||
3894 | "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.", | ||
3895 | sp.Name, Name, polls * pollInterval / 1000); | ||
3896 | } | ||
3897 | } | ||
3898 | |||
3899 | // TODO: can we remove this lock? | ||
3900 | lock (acd) | ||
3901 | { | ||
3902 | if (sp != null && !sp.IsChildAgent) | ||
3903 | { | ||
3904 | // We have a root agent. Is it in transit? | ||
3905 | if (!EntityTransferModule.IsInTransit(sp.UUID)) | ||
3906 | { | ||
3907 | // We have a zombie from a crashed session. | ||
3908 | // Or the same user is trying to be root twice here, won't work. | ||
3909 | // Kill it. | ||
3910 | m_log.WarnFormat( | ||
3911 | "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", | ||
3912 | sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3913 | |||
3914 | if (sp.ControllingClient != null) | ||
3915 | IncomingCloseAgent(sp.UUID, true); | ||
3916 | |||
3917 | sp = null; | ||
3918 | } | ||
3919 | //else | ||
3920 | // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3921 | } | ||
3867 | 3922 | ||
3868 | // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. | 3923 | // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. |
3869 | // We need the circuit data here for some of the subsequent checks. (groups, for example) | 3924 | // We need the circuit data here for some of the subsequent checks. (groups, for example) |
3870 | // If the checks fail, we remove the circuit. | 3925 | // If the checks fail, we remove the circuit. |
3871 | agent.teleportFlags = teleportFlags; | 3926 | acd.teleportFlags = teleportFlags; |
3872 | m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); | 3927 | m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd); |
3873 | 3928 | ||
3929 | land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y); | ||
3930 | |||
3874 | // On login test land permisions | 3931 | // On login test land permisions |
3875 | if (vialogin) | 3932 | if (vialogin) |
3876 | { | 3933 | { |
3877 | IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>(); | 3934 | IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>(); |
3878 | if (cache != null) | 3935 | if (cache != null) |
3879 | cache.Remove(agent.firstname + " " + agent.lastname); | 3936 | cache.Remove(acd.firstname + " " + acd.lastname); |
3880 | if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) | 3937 | if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y)) |
3881 | { | 3938 | { |
3882 | m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString()); | 3939 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3883 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | ||
3884 | return false; | 3940 | return false; |
3885 | } | 3941 | } |
3886 | } | 3942 | } |
@@ -3891,9 +3947,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3891 | { | 3947 | { |
3892 | try | 3948 | try |
3893 | { | 3949 | { |
3894 | if (!VerifyUserPresence(agent, out reason)) | 3950 | if (!VerifyUserPresence(acd, out reason)) |
3895 | { | 3951 | { |
3896 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3952 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3897 | return false; | 3953 | return false; |
3898 | } | 3954 | } |
3899 | } | 3955 | } |
@@ -3902,16 +3958,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
3902 | m_log.ErrorFormat( | 3958 | m_log.ErrorFormat( |
3903 | "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); | 3959 | "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); |
3904 | 3960 | ||
3905 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3961 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3906 | return false; | 3962 | return false; |
3907 | } | 3963 | } |
3908 | } | 3964 | } |
3909 | 3965 | ||
3910 | try | 3966 | try |
3911 | { | 3967 | { |
3912 | if (!AuthorizeUser(agent, SeeIntoRegion, out reason)) | 3968 | if (!AuthorizeUser(acd, SeeIntoRegion, out reason)) |
3913 | { | 3969 | { |
3914 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3970 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3915 | return false; | 3971 | return false; |
3916 | } | 3972 | } |
3917 | } | 3973 | } |
@@ -3920,15 +3976,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
3920 | m_log.ErrorFormat( | 3976 | m_log.ErrorFormat( |
3921 | "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); | 3977 | "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); |
3922 | 3978 | ||
3923 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3979 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3924 | return false; | 3980 | return false; |
3925 | } | 3981 | } |
3926 | 3982 | ||
3927 | m_log.InfoFormat( | 3983 | m_log.InfoFormat( |
3928 | "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", | 3984 | "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", |
3929 | RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, | 3985 | Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname, |
3930 | agent.AgentID, agent.circuitcode); | 3986 | acd.AgentID, acd.circuitcode); |
3931 | 3987 | ||
3988 | if (CapsModule != null) | ||
3989 | { | ||
3990 | CapsModule.SetAgentCapsSeeds(acd); | ||
3991 | CapsModule.CreateCaps(acd.AgentID, acd.circuitcode); | ||
3992 | } | ||
3932 | } | 3993 | } |
3933 | else | 3994 | else |
3934 | { | 3995 | { |
@@ -3940,14 +4001,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3940 | { | 4001 | { |
3941 | m_log.DebugFormat( | 4002 | m_log.DebugFormat( |
3942 | "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", | 4003 | "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", |
3943 | agent.AgentID, RegionInfo.RegionName); | 4004 | acd.AgentID, RegionInfo.RegionName); |
3944 | 4005 | ||
3945 | sp.AdjustKnownSeeds(); | 4006 | sp.AdjustKnownSeeds(); |
3946 | 4007 | ||
3947 | if (CapsModule != null) | 4008 | if (CapsModule != null) |
3948 | { | 4009 | { |
3949 | CapsModule.SetAgentCapsSeeds(agent); | 4010 | CapsModule.SetAgentCapsSeeds(acd); |
3950 | CapsModule.CreateCaps(agent.AgentID, agent.circuitcode); | 4011 | CapsModule.CreateCaps(acd.AgentID, acd.circuitcode); |
3951 | } | 4012 | } |
3952 | } | 4013 | } |
3953 | } | 4014 | } |
@@ -3955,28 +4016,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
3955 | // Try caching an incoming user name much earlier on to see if this helps with an issue | 4016 | // Try caching an incoming user name much earlier on to see if this helps with an issue |
3956 | // where HG users are occasionally seen by others as "Unknown User" because their UUIDName | 4017 | // where HG users are occasionally seen by others as "Unknown User" because their UUIDName |
3957 | // request for the HG avatar appears to trigger before the user name is cached. | 4018 | // request for the HG avatar appears to trigger before the user name is cached. |
3958 | CacheUserName(null, agent); | 4019 | CacheUserName(null, acd); |
3959 | } | 4020 | } |
3960 | 4021 | ||
3961 | if (CapsModule != null) | 4022 | if (CapsModule != null) |
3962 | { | 4023 | { |
3963 | CapsModule.ActivateCaps(agent.circuitcode); | 4024 | CapsModule.ActivateCaps(acd.circuitcode); |
3964 | } | 4025 | } |
3965 | 4026 | ||
3966 | if (vialogin) | 4027 | if (vialogin) |
3967 | { | 4028 | { |
3968 | // CleanDroppedAttachments(); | 4029 | // CleanDroppedAttachments(); |
3969 | 4030 | ||
3970 | if (TestBorderCross(agent.startpos, Cardinals.E)) | 4031 | if (TestBorderCross(acd.startpos, Cardinals.E)) |
3971 | { | 4032 | { |
3972 | Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E); | 4033 | Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E); |
3973 | agent.startpos.X = crossedBorder.BorderLine.Z - 1; | 4034 | acd.startpos.X = crossedBorder.BorderLine.Z - 1; |
3974 | } | 4035 | } |
3975 | 4036 | ||
3976 | if (TestBorderCross(agent.startpos, Cardinals.N)) | 4037 | if (TestBorderCross(acd.startpos, Cardinals.N)) |
3977 | { | 4038 | { |
3978 | Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N); | 4039 | Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N); |
3979 | agent.startpos.Y = crossedBorder.BorderLine.Z - 1; | 4040 | acd.startpos.Y = crossedBorder.BorderLine.Z - 1; |
3980 | } | 4041 | } |
3981 | 4042 | ||
3982 | //Mitigate http://opensimulator.org/mantis/view.php?id=3522 | 4043 | //Mitigate http://opensimulator.org/mantis/view.php?id=3522 |
@@ -3986,39 +4047,39 @@ namespace OpenSim.Region.Framework.Scenes | |||
3986 | { | 4047 | { |
3987 | lock (EastBorders) | 4048 | lock (EastBorders) |
3988 | { | 4049 | { |
3989 | if (agent.startpos.X > EastBorders[0].BorderLine.Z) | 4050 | if (acd.startpos.X > EastBorders[0].BorderLine.Z) |
3990 | { | 4051 | { |
3991 | m_log.Warn("FIX AGENT POSITION"); | 4052 | m_log.Warn("FIX AGENT POSITION"); |
3992 | agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; | 4053 | acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; |
3993 | if (agent.startpos.Z > 720) | 4054 | if (acd.startpos.Z > 720) |
3994 | agent.startpos.Z = 720; | 4055 | acd.startpos.Z = 720; |
3995 | } | 4056 | } |
3996 | } | 4057 | } |
3997 | lock (NorthBorders) | 4058 | lock (NorthBorders) |
3998 | { | 4059 | { |
3999 | if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) | 4060 | if (acd.startpos.Y > NorthBorders[0].BorderLine.Z) |
4000 | { | 4061 | { |
4001 | m_log.Warn("FIX Agent POSITION"); | 4062 | m_log.Warn("FIX Agent POSITION"); |
4002 | agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; | 4063 | acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; |
4003 | if (agent.startpos.Z > 720) | 4064 | if (acd.startpos.Z > 720) |
4004 | agent.startpos.Z = 720; | 4065 | acd.startpos.Z = 720; |
4005 | } | 4066 | } |
4006 | } | 4067 | } |
4007 | } else | 4068 | } else |
4008 | { | 4069 | { |
4009 | if (agent.startpos.X > EastBorders[0].BorderLine.Z) | 4070 | if (acd.startpos.X > EastBorders[0].BorderLine.Z) |
4010 | { | 4071 | { |
4011 | m_log.Warn("FIX AGENT POSITION"); | 4072 | m_log.Warn("FIX AGENT POSITION"); |
4012 | agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; | 4073 | acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; |
4013 | if (agent.startpos.Z > 720) | 4074 | if (acd.startpos.Z > 720) |
4014 | agent.startpos.Z = 720; | 4075 | acd.startpos.Z = 720; |
4015 | } | 4076 | } |
4016 | if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) | 4077 | if (acd.startpos.Y > NorthBorders[0].BorderLine.Z) |
4017 | { | 4078 | { |
4018 | m_log.Warn("FIX Agent POSITION"); | 4079 | m_log.Warn("FIX Agent POSITION"); |
4019 | agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; | 4080 | acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; |
4020 | if (agent.startpos.Z > 720) | 4081 | if (acd.startpos.Z > 720) |
4021 | agent.startpos.Z = 720; | 4082 | acd.startpos.Z = 720; |
4022 | } | 4083 | } |
4023 | } | 4084 | } |
4024 | 4085 | ||
@@ -4034,12 +4095,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
4034 | { | 4095 | { |
4035 | // We have multiple SpawnPoints, Route the agent to a random or sequential one | 4096 | // We have multiple SpawnPoints, Route the agent to a random or sequential one |
4036 | if (SpawnPointRouting == "random") | 4097 | if (SpawnPointRouting == "random") |
4037 | agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( | 4098 | acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( |
4038 | telehub.AbsolutePosition, | 4099 | telehub.AbsolutePosition, |
4039 | telehub.GroupRotation | 4100 | telehub.GroupRotation |
4040 | ); | 4101 | ); |
4041 | else | 4102 | else |
4042 | agent.startpos = spawnpoints[SpawnPoint()].GetLocation( | 4103 | acd.startpos = spawnpoints[SpawnPoint()].GetLocation( |
4043 | telehub.AbsolutePosition, | 4104 | telehub.AbsolutePosition, |
4044 | telehub.GroupRotation | 4105 | telehub.GroupRotation |
4045 | ); | 4106 | ); |
@@ -4047,7 +4108,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4047 | else | 4108 | else |
4048 | { | 4109 | { |
4049 | // We have a single SpawnPoint and will route the agent to it | 4110 | // We have a single SpawnPoint and will route the agent to it |
4050 | agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); | 4111 | acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); |
4051 | } | 4112 | } |
4052 | 4113 | ||
4053 | return true; | 4114 | return true; |
@@ -4060,7 +4121,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4060 | { | 4121 | { |
4061 | if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) | 4122 | if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) |
4062 | { | 4123 | { |
4063 | agent.startpos = land.LandData.UserLocation; | 4124 | acd.startpos = land.LandData.UserLocation; |
4064 | } | 4125 | } |
4065 | } | 4126 | } |
4066 | */// This is now handled properly in ScenePresence.MakeRootAgent | 4127 | */// This is now handled properly in ScenePresence.MakeRootAgent |
@@ -4444,24 +4505,25 @@ namespace OpenSim.Region.Framework.Scenes | |||
4444 | ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); | 4505 | ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); |
4445 | if (childAgentUpdate != null) | 4506 | if (childAgentUpdate != null) |
4446 | { | 4507 | { |
4447 | if (childAgentUpdate.ControllingClient.SessionId == cAgentData.SessionID) | 4508 | if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID) |
4509 | // Only warn for now | ||
4510 | m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?", | ||
4511 | childAgentUpdate.UUID, cAgentData.SessionID); | ||
4512 | |||
4513 | // I can't imagine *yet* why we would get an update if the agent is a root agent.. | ||
4514 | // however to avoid a race condition crossing borders.. | ||
4515 | if (childAgentUpdate.IsChildAgent) | ||
4448 | { | 4516 | { |
4449 | // I can't imagine *yet* why we would get an update if the agent is a root agent.. | 4517 | uint rRegionX = (uint)(cAgentData.RegionHandle >> 40); |
4450 | // however to avoid a race condition crossing borders.. | 4518 | uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8); |
4451 | if (childAgentUpdate.IsChildAgent) | 4519 | uint tRegionX = RegionInfo.RegionLocX; |
4452 | { | 4520 | uint tRegionY = RegionInfo.RegionLocY; |
4453 | uint rRegionX = (uint)(cAgentData.RegionHandle >> 40); | 4521 | //Send Data to ScenePresence |
4454 | uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8); | 4522 | childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); |
4455 | uint tRegionX = RegionInfo.RegionLocX; | 4523 | // Not Implemented: |
4456 | uint tRegionY = RegionInfo.RegionLocY; | 4524 | //TODO: Do we need to pass the message on to one of our neighbors? |
4457 | //Send Data to ScenePresence | ||
4458 | childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); | ||
4459 | // Not Implemented: | ||
4460 | //TODO: Do we need to pass the message on to one of our neighbors? | ||
4461 | } | ||
4462 | } | 4525 | } |
4463 | else | 4526 | |
4464 | m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}", childAgentUpdate.UUID, cAgentData.SessionID); | ||
4465 | return true; | 4527 | return true; |
4466 | } | 4528 | } |
4467 | 4529 | ||
@@ -4540,11 +4602,51 @@ namespace OpenSim.Region.Framework.Scenes | |||
4540 | /// </param> | 4602 | /// </param> |
4541 | public bool IncomingCloseAgent(UUID agentID, bool force) | 4603 | public bool IncomingCloseAgent(UUID agentID, bool force) |
4542 | { | 4604 | { |
4543 | //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); | 4605 | ScenePresence sp; |
4544 | ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); | 4606 | |
4545 | if (presence != null) | 4607 | lock (m_removeClientLock) |
4608 | { | ||
4609 | sp = GetScenePresence(agentID); | ||
4610 | |||
4611 | if (sp == null) | ||
4612 | { | ||
4613 | m_log.DebugFormat( | ||
4614 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}", | ||
4615 | agentID, Name); | ||
4616 | |||
4617 | return false; | ||
4618 | } | ||
4619 | |||
4620 | if (sp.LifecycleState != ScenePresenceState.Running) | ||
4621 | { | ||
4622 | m_log.DebugFormat( | ||
4623 | "[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}", | ||
4624 | sp.Name, Name, sp.LifecycleState); | ||
4625 | |||
4626 | return false; | ||
4627 | } | ||
4628 | |||
4629 | // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may | ||
4630 | // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not | ||
4631 | // want to obey this close since C may have renewed the child agent lease on B. | ||
4632 | if (sp.DoNotCloseAfterTeleport) | ||
4633 | { | ||
4634 | m_log.DebugFormat( | ||
4635 | "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection", | ||
4636 | sp.IsChildAgent ? "child" : "root", sp.Name, Name); | ||
4637 | |||
4638 | // Need to reset the flag so that a subsequent close after another teleport can succeed. | ||
4639 | sp.DoNotCloseAfterTeleport = false; | ||
4640 | |||
4641 | return false; | ||
4642 | } | ||
4643 | |||
4644 | sp.LifecycleState = ScenePresenceState.Removing; | ||
4645 | } | ||
4646 | |||
4647 | if (sp != null) | ||
4546 | { | 4648 | { |
4547 | presence.ControllingClient.Close(force, force); | 4649 | sp.ControllingClient.Close(force, force); |
4548 | return true; | 4650 | return true; |
4549 | } | 4651 | } |
4550 | 4652 | ||
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 48bf6f3..5301a82 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -75,6 +75,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
75 | 75 | ||
76 | public class ScenePresence : EntityBase, IScenePresence | 76 | public class ScenePresence : EntityBase, IScenePresence |
77 | { | 77 | { |
78 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
79 | |||
78 | // ~ScenePresence() | 80 | // ~ScenePresence() |
79 | // { | 81 | // { |
80 | // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); | 82 | // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); |
@@ -86,10 +88,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
86 | m_scene.EventManager.TriggerScenePresenceUpdated(this); | 88 | m_scene.EventManager.TriggerScenePresenceUpdated(this); |
87 | } | 89 | } |
88 | 90 | ||
89 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
90 | |||
91 | public PresenceType PresenceType { get; private set; } | 91 | public PresenceType PresenceType { get; private set; } |
92 | 92 | ||
93 | private ScenePresenceStateMachine m_stateMachine; | ||
94 | |||
95 | /// <summary> | ||
96 | /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine | ||
97 | /// for more details. | ||
98 | /// </summary> | ||
99 | public ScenePresenceState LifecycleState | ||
100 | { | ||
101 | get | ||
102 | { | ||
103 | return m_stateMachine.GetState(); | ||
104 | } | ||
105 | |||
106 | set | ||
107 | { | ||
108 | m_stateMachine.SetState(value); | ||
109 | } | ||
110 | } | ||
111 | |||
93 | // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); | 112 | // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); |
94 | private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); | 113 | private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); |
95 | private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); | 114 | private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); |
@@ -299,9 +318,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
299 | /// <summary> | 318 | /// <summary> |
300 | /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address. | 319 | /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address. |
301 | /// </summary> | 320 | /// </summary> |
302 | string m_callbackURI; | 321 | private string m_callbackURI; |
303 | 322 | ||
304 | UUID m_originRegionID; | 323 | public UUID m_originRegionID; |
305 | 324 | ||
306 | /// <summary> | 325 | /// <summary> |
307 | /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent | 326 | /// 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 | |||
813 | 832 | ||
814 | public ScenePresence( | 833 | public ScenePresence( |
815 | IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) | 834 | IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) |
816 | { | 835 | { |
817 | AttachmentsSyncLock = new Object(); | 836 | AttachmentsSyncLock = new Object(); |
818 | AllowMovement = true; | 837 | AllowMovement = true; |
819 | IsChildAgent = true; | 838 | IsChildAgent = true; |
@@ -859,6 +878,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
859 | SetDirectionVectors(); | 878 | SetDirectionVectors(); |
860 | 879 | ||
861 | Appearance = appearance; | 880 | Appearance = appearance; |
881 | |||
882 | m_stateMachine = new ScenePresenceStateMachine(this); | ||
862 | } | 883 | } |
863 | 884 | ||
864 | private void RegionHeartbeatEnd(Scene scene) | 885 | private void RegionHeartbeatEnd(Scene scene) |
@@ -956,7 +977,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
956 | /// </summary> | 977 | /// </summary> |
957 | public void MakeRootAgent(Vector3 pos, bool isFlying) | 978 | public void MakeRootAgent(Vector3 pos, bool isFlying) |
958 | { | 979 | { |
959 | m_log.DebugFormat( | 980 | m_log.InfoFormat( |
960 | "[SCENE]: Upgrading child to root agent for {0} in {1}", | 981 | "[SCENE]: Upgrading child to root agent for {0} in {1}", |
961 | Name, m_scene.RegionInfo.RegionName); | 982 | Name, m_scene.RegionInfo.RegionName); |
962 | 983 | ||
@@ -996,6 +1017,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
996 | 1017 | ||
997 | IsChildAgent = false; | 1018 | IsChildAgent = false; |
998 | 1019 | ||
1020 | // Must reset this here so that a teleport to a region next to an existing region does not keep the flag | ||
1021 | // set and prevent the close of the connection on a subsequent re-teleport. | ||
1022 | // Should not be needed if we are not trying to tell this region to close | ||
1023 | // DoNotCloseAfterTeleport = false; | ||
1024 | |||
999 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); | 1025 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); |
1000 | if (gm != null) | 1026 | if (gm != null) |
1001 | Grouptitle = gm.GetGroupTitle(m_uuid); | 1027 | Grouptitle = gm.GetGroupTitle(m_uuid); |
@@ -1520,7 +1546,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1520 | private bool WaitForUpdateAgent(IClientAPI client) | 1546 | private bool WaitForUpdateAgent(IClientAPI client) |
1521 | { | 1547 | { |
1522 | // Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero | 1548 | // Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero |
1523 | int count = 20; | 1549 | int count = 50; |
1524 | while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) | 1550 | while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) |
1525 | { | 1551 | { |
1526 | m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name); | 1552 | 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 | |||
3994 | // Animator.Close(); | 4020 | // Animator.Close(); |
3995 | Animator = null; | 4021 | Animator = null; |
3996 | 4022 | ||
4023 | LifecycleState = ScenePresenceState.Removed; | ||
3997 | } | 4024 | } |
3998 | 4025 | ||
3999 | public void AddAttachment(SceneObjectGroup gobj) | 4026 | public void AddAttachment(SceneObjectGroup gobj) |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs new file mode 100644 index 0000000..dc3a212 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Region.Framework.Scenes | ||
31 | { | ||
32 | /// <summary> | ||
33 | /// The possible states that a scene presence can be in. This is currently orthagonal to whether a scene presence | ||
34 | /// is root or child. | ||
35 | /// </summary> | ||
36 | /// <remarks> | ||
37 | /// This is a state machine. | ||
38 | /// | ||
39 | /// [Entry] => Running | ||
40 | /// Running => Removing | ||
41 | /// Removing => Removed | ||
42 | /// | ||
43 | /// All other methods should only see the scene presence in running state - this is the normal operational state | ||
44 | /// Removed state occurs when the presence has been removed. This is the end state with no exit. | ||
45 | /// </remarks> | ||
46 | public enum ScenePresenceState | ||
47 | { | ||
48 | Running, // Normal operation state. The scene presence is available. | ||
49 | Removing, // The presence is in the process of being removed from the scene via Scene.RemoveClient. | ||
50 | Removed, // The presence has been removed from the scene and is effectively dead. | ||
51 | // There is no exit from this state. | ||
52 | } | ||
53 | |||
54 | internal class ScenePresenceStateMachine | ||
55 | { | ||
56 | private ScenePresence m_sp; | ||
57 | private ScenePresenceState m_state; | ||
58 | |||
59 | internal ScenePresenceStateMachine(ScenePresence sp) | ||
60 | { | ||
61 | m_sp = sp; | ||
62 | m_state = ScenePresenceState.Running; | ||
63 | } | ||
64 | |||
65 | internal ScenePresenceState GetState() | ||
66 | { | ||
67 | return m_state; | ||
68 | } | ||
69 | |||
70 | /// <summary> | ||
71 | /// Updates the state of an agent that is already in transit. | ||
72 | /// </summary> | ||
73 | /// <param name='id'></param> | ||
74 | /// <param name='newState'></param> | ||
75 | /// <returns></returns> | ||
76 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> | ||
77 | internal void SetState(ScenePresenceState newState) | ||
78 | { | ||
79 | bool transitionOkay = false; | ||
80 | |||
81 | lock (this) | ||
82 | { | ||
83 | if (newState == ScenePresenceState.Removing && m_state == ScenePresenceState.Running) | ||
84 | transitionOkay = true; | ||
85 | else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing) | ||
86 | transitionOkay = true; | ||
87 | } | ||
88 | |||
89 | if (!transitionOkay) | ||
90 | { | ||
91 | throw new Exception( | ||
92 | string.Format( | ||
93 | "Scene presence {0} is not allowed to move from state {1} to new state {2} in {3}", | ||
94 | m_sp.Name, m_state, newState, m_sp.Scene.Name)); | ||
95 | } | ||
96 | else | ||
97 | { | ||
98 | m_state = newState; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 58a417e..9af3dce 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -96,8 +96,8 @@ public sealed class BSCharacter : BSPhysObject | |||
96 | m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); | 96 | m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); |
97 | PhysicalActors.Add(AvatarMoveActorName, m_moveActor); | 97 | PhysicalActors.Add(AvatarMoveActorName, m_moveActor); |
98 | 98 | ||
99 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 99 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6}", |
100 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | 100 | LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos); |
101 | 101 | ||
102 | // do actual creation in taint time | 102 | // do actual creation in taint time |
103 | PhysScene.TaintedObject("BSCharacter.create", delegate() | 103 | PhysScene.TaintedObject("BSCharacter.create", delegate() |
@@ -190,6 +190,10 @@ public sealed class BSCharacter : BSPhysObject | |||
190 | } | 190 | } |
191 | 191 | ||
192 | set { | 192 | set { |
193 | // This is how much the avatar size is changing. Positive means getting bigger. | ||
194 | // The avatar altitude must be adjusted for this change. | ||
195 | float heightChange = value.Z - _size.Z; | ||
196 | |||
193 | _size = value; | 197 | _size = value; |
194 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | 198 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |
195 | // replace with the default values. | 199 | // replace with the default values. |
@@ -207,6 +211,10 @@ public sealed class BSCharacter : BSPhysObject | |||
207 | { | 211 | { |
208 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); | 212 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
209 | UpdatePhysicalMassProperties(RawMass, true); | 213 | UpdatePhysicalMassProperties(RawMass, true); |
214 | |||
215 | // Adjust the avatar's position to account for the increase/decrease in size | ||
216 | ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); | ||
217 | |||
210 | // Make sure this change appears as a property update event | 218 | // Make sure this change appears as a property update event |
211 | PhysScene.PE.PushUpdate(PhysBody); | 219 | PhysScene.PE.PushUpdate(PhysBody); |
212 | } | 220 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 4520171..fcb892a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | |||
@@ -570,9 +570,9 @@ public static class BSParam | |||
570 | new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", | 570 | new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", |
571 | -0.2f ), | 571 | -0.2f ), |
572 | new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", | 572 | new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", |
573 | 0.1f ), | 573 | 0.2f ), |
574 | new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", | 574 | new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", |
575 | 0.1f ), | 575 | 0.2f ), |
576 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | 576 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", |
577 | 0.1f ), | 577 | 0.1f ), |
578 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", | 578 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", |