aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Data/IRegionData.cs15
-rw-r--r--OpenSim/Data/MSSQL/MSSQLRegionData.cs1
-rw-r--r--OpenSim/Data/MySQL/MySQLRegionData.cs4
-rw-r--r--OpenSim/Data/Null/NullRegionData.cs1
-rw-r--r--OpenSim/Framework/Console/ConsoleUtil.cs4
-rw-r--r--OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs16
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs204
-rw-r--r--OpenSim/Framework/Monitoring/Watchdog.cs20
-rw-r--r--OpenSim/Framework/RegionFlags.cs53
-rw-r--r--OpenSim/Framework/Servers/BaseOpenSimServer.cs32
-rw-r--r--OpenSim/Region/Application/OpenSim.cs13
-rw-r--r--OpenSim/Region/Application/OpenSimBase.cs72
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs13
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs21
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs36
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs51
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs1
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs111
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs20
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs507
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs15
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs13
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs16
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs185
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs7
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs62
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs90
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs81
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs23
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs31
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs4
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs15
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs4
-rw-r--r--OpenSim/Server/ServerMain.cs22
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs4
-rw-r--r--OpenSim/Services/GridService/GridService.cs48
-rw-r--r--OpenSim/Services/GridService/HypergridLinker.cs6
-rw-r--r--OpenSim/Services/Interfaces/IGridService.cs13
42 files changed, 1218 insertions, 633 deletions
diff --git a/OpenSim/Data/IRegionData.cs b/OpenSim/Data/IRegionData.cs
index 546b5e8..70e1065 100644
--- a/OpenSim/Data/IRegionData.cs
+++ b/OpenSim/Data/IRegionData.cs
@@ -85,21 +85,6 @@ namespace OpenSim.Data
85 List<RegionData> GetHyperlinks(UUID scopeID); 85 List<RegionData> GetHyperlinks(UUID scopeID);
86 } 86 }
87 87
88 [Flags]
89 public enum RegionFlags : int
90 {
91 DefaultRegion = 1, // Used for new Rez. Random if multiple defined
92 FallbackRegion = 2, // Regions we redirect to when the destination is down
93 RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
94 NoDirectLogin = 8, // Region unavailable for direct logins (by name)
95 Persistent = 16, // Don't remove on unregister
96 LockedOut = 32, // Don't allow registration
97 NoMove = 64, // Don't allow moving this region
98 Reservation = 128, // This is an inactive reservation
99 Authenticate = 256, // Require authentication
100 Hyperlink = 512 // Record represents a HG link
101 }
102
103 public class RegionDataDistanceCompare : IComparer<RegionData> 88 public class RegionDataDistanceCompare : IComparer<RegionData>
104 { 89 {
105 private Vector2 m_origin; 90 private Vector2 m_origin;
diff --git a/OpenSim/Data/MSSQL/MSSQLRegionData.cs b/OpenSim/Data/MSSQL/MSSQLRegionData.cs
index 3ae87c3..0d89706 100644
--- a/OpenSim/Data/MSSQL/MSSQLRegionData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLRegionData.cs
@@ -37,6 +37,7 @@ using OpenMetaverse;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using RegionFlags = OpenSim.Framework.RegionFlags;
40 41
41namespace OpenSim.Data.MSSQL 42namespace OpenSim.Data.MSSQL
42{ 43{
diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs
index 0614879..a2d4ae4 100644
--- a/OpenSim/Data/MySQL/MySQLRegionData.cs
+++ b/OpenSim/Data/MySQL/MySQLRegionData.cs
@@ -30,11 +30,11 @@ using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Data; 31using System.Data;
32using System.Reflection; 32using System.Reflection;
33 33using MySql.Data.MySqlClient;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Data; 36using OpenSim.Data;
37using MySql.Data.MySqlClient; 37using RegionFlags = OpenSim.Framework.RegionFlags;
38 38
39namespace OpenSim.Data.MySQL 39namespace OpenSim.Data.MySQL
40{ 40{
diff --git a/OpenSim/Data/Null/NullRegionData.cs b/OpenSim/Data/Null/NullRegionData.cs
index deb50cb..b4d701a 100644
--- a/OpenSim/Data/Null/NullRegionData.cs
+++ b/OpenSim/Data/Null/NullRegionData.cs
@@ -33,6 +33,7 @@ using OpenSim.Framework;
33using OpenSim.Data; 33using OpenSim.Data;
34using System.Reflection; 34using System.Reflection;
35using log4net; 35using log4net;
36using RegionFlags = OpenSim.Framework.RegionFlags;
36 37
37namespace OpenSim.Data.Null 38namespace OpenSim.Data.Null
38{ 39{
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs
index 2612a50..a7cf0c0 100644
--- a/OpenSim/Framework/Console/ConsoleUtil.cs
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -34,7 +34,7 @@ using OpenMetaverse;
34 34
35public class ConsoleUtil 35public class ConsoleUtil
36{ 36{
37 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 37// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
38 38
39 public const string MinRawConsoleVectorValue = "-~"; 39 public const string MinRawConsoleVectorValue = "-~";
40 public const string MaxRawConsoleVectorValue = "~"; 40 public const string MaxRawConsoleVectorValue = "~";
@@ -107,7 +107,7 @@ public class ConsoleUtil
107 107
108 string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray()); 108 string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
109 109
110 m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector); 110// m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
111 111
112 return Vector3.TryParse(semiDigestedConsoleVector, out vector); 112 return Vector3.TryParse(semiDigestedConsoleVector, out vector);
113 } 113 }
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
index 8ac9090..aa86202 100644
--- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -359,13 +359,19 @@ Asset service request failures: {3}" + Environment.NewLine,
359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, 359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); 360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
361 361
362 foreach (KeyValuePair<string, Stat> kvp in StatsManager.RegisteredStats) 362 Dictionary<string, Dictionary<string, Stat>> sceneStats;
363 {
364 Stat stat = kvp.Value;
365 363
366 if (stat.Category == "scene" && stat.Verbosity == StatVerbosity.Info) 364 if (StatsManager.TryGetStats("scene", out sceneStats))
365 {
366 foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
367 { 367 {
368 sb.AppendFormat("Slow frames ({0}): {1}\n", stat.Container, stat.Value); 368 foreach (Stat stat in kvp.Value.Values)
369 {
370 if (stat.Verbosity == StatVerbosity.Info)
371 {
372 sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
373 }
374 }
369 } 375 }
370 } 376 }
371 377
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index b5dc24f..31989e5 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -35,13 +35,23 @@ namespace OpenSim.Framework.Monitoring
35 /// </summary> 35 /// </summary>
36 public class StatsManager 36 public class StatsManager
37 { 37 {
38 // Subcommand used to list other stats.
39 public const string AllSubCommand = "all";
40
41 // Subcommand used to list other stats.
42 public const string ListSubCommand = "list";
43
44 // All subcommands
45 public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
46
38 /// <summary> 47 /// <summary>
39 /// Registered stats. 48 /// Registered stats categorized by category/container/shortname
40 /// </summary> 49 /// </summary>
41 /// <remarks> 50 /// <remarks>
42 /// Do not add or remove from this dictionary. 51 /// Do not add or remove directly from this dictionary.
43 /// </remarks> 52 /// </remarks>
44 public static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>(); 53 public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
54 = new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
45 55
46 private static AssetStatsCollector assetStats; 56 private static AssetStatsCollector assetStats;
47 private static UserStatsCollector userStats; 57 private static UserStatsCollector userStats;
@@ -51,6 +61,75 @@ namespace OpenSim.Framework.Monitoring
51 public static UserStatsCollector UserStats { get { return userStats; } } 61 public static UserStatsCollector UserStats { get { return userStats; } }
52 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } 62 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
53 63
64 public static void RegisterConsoleCommands(ICommandConsole console)
65 {
66 console.Commands.AddCommand(
67 "General",
68 false,
69 "show stats",
70 "show stats [list|all|<category>]",
71 "Show statistical information for this server",
72 "If no final argument is specified then legacy statistics information is currently shown.\n"
73 + "If list is specified then statistic categories are shown.\n"
74 + "If all is specified then all registered statistics are shown.\n"
75 + "If a category name is specified then only statistics from that category are shown.\n"
76 + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
77 HandleShowStatsCommand);
78 }
79
80 public static void HandleShowStatsCommand(string module, string[] cmd)
81 {
82 ICommandConsole con = MainConsole.Instance;
83
84 if (cmd.Length > 2)
85 {
86 var categoryName = cmd[2];
87
88 if (categoryName == AllSubCommand)
89 {
90 foreach (var category in RegisteredStats.Values)
91 {
92 OutputCategoryStatsToConsole(con, category);
93 }
94 }
95 else if (categoryName == ListSubCommand)
96 {
97 con.Output("Statistic categories available are:");
98 foreach (string category in RegisteredStats.Keys)
99 con.OutputFormat(" {0}", category);
100 }
101 else
102 {
103 Dictionary<string, Dictionary<string, Stat>> category;
104 if (!RegisteredStats.TryGetValue(categoryName, out category))
105 {
106 con.OutputFormat("No such category as {0}", categoryName);
107 }
108 else
109 {
110 OutputCategoryStatsToConsole(con, category);
111 }
112 }
113 }
114 else
115 {
116 // Legacy
117 con.Output(SimExtraStats.Report());
118 }
119 }
120
121 private static void OutputCategoryStatsToConsole(
122 ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
123 {
124 foreach (var container in category.Values)
125 {
126 foreach (Stat stat in container.Values)
127 {
128 con.Output(stat.ToConsoleString());
129 }
130 }
131 }
132
54 /// <summary> 133 /// <summary>
55 /// Start collecting statistics related to assets. 134 /// Start collecting statistics related to assets.
56 /// Should only be called once. 135 /// Should only be called once.
@@ -73,43 +152,100 @@ namespace OpenSim.Framework.Monitoring
73 return userStats; 152 return userStats;
74 } 153 }
75 154
155 /// <summary>
156 /// Registers a statistic.
157 /// </summary>
158 /// <param name='stat'></param>
159 /// <returns></returns>
76 public static bool RegisterStat(Stat stat) 160 public static bool RegisterStat(Stat stat)
77 { 161 {
162 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
163 Dictionary<string, Stat> container = null, newContainer;
164
78 lock (RegisteredStats) 165 lock (RegisteredStats)
79 { 166 {
80 if (RegisteredStats.ContainsKey(stat.UniqueName)) 167 // Stat name is not unique across category/container/shortname key.
81 { 168 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
82 // XXX: For now just return false. This is to avoid problems in regression tests where all tests 169 // in a class are run in the same instance of the VM.
83 // in a class are run in the same instance of the VM. 170 if (TryGetStat(stat, out category, out container))
84 return false; 171 return false;
85 172
86// throw new Exception( 173 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
87// "StatsManager already contains stat with ShortName {0} in Category {1}", stat.ShortName, stat.Category); 174 // This means that we don't need to lock or copy them on iteration, which will be a much more
88 } 175 // common operation after startup.
176 if (container != null)
177 newContainer = new Dictionary<string, Stat>(container);
178 else
179 newContainer = new Dictionary<string, Stat>();
89 180
90 // We take a replace-on-write approach here so that we don't need to generate a new Dictionary 181 if (category != null)
91 Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats); 182 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
92 newRegisteredStats[stat.UniqueName] = stat; 183 else
93 RegisteredStats = newRegisteredStats; 184 newCategory = new Dictionary<string, Dictionary<string, Stat>>();
185
186 newContainer[stat.ShortName] = stat;
187 newCategory[stat.Container] = newContainer;
188 RegisteredStats[stat.Category] = newCategory;
94 } 189 }
95 190
96 return true; 191 return true;
97 } 192 }
98 193
194 /// <summary>
195 /// Deregister a statistic
196 /// </summary>>
197 /// <param name='stat'></param>
198 /// <returns></returns
99 public static bool DeregisterStat(Stat stat) 199 public static bool DeregisterStat(Stat stat)
100 { 200 {
201 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
202 Dictionary<string, Stat> container = null, newContainer;
203
101 lock (RegisteredStats) 204 lock (RegisteredStats)
102 { 205 {
103 if (!RegisteredStats.ContainsKey(stat.UniqueName)) 206 if (!TryGetStat(stat, out category, out container))
104 return false; 207 return false;
105 208
106 Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats); 209 newContainer = new Dictionary<string, Stat>(container);
107 newRegisteredStats.Remove(stat.UniqueName); 210 newContainer.Remove(stat.UniqueName);
108 RegisteredStats = newRegisteredStats; 211
212 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
213 newCategory.Remove(stat.Container);
214
215 newCategory[stat.Container] = newContainer;
216 RegisteredStats[stat.Category] = newCategory;
109 217
110 return true; 218 return true;
111 } 219 }
112 } 220 }
221
222 public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
223 {
224 return RegisteredStats.TryGetValue(category, out stats);
225 }
226
227 public static bool TryGetStat(
228 Stat stat,
229 out Dictionary<string, Dictionary<string, Stat>> category,
230 out Dictionary<string, Stat> container)
231 {
232 category = null;
233 container = null;
234
235 lock (RegisteredStats)
236 {
237 if (RegisteredStats.TryGetValue(stat.Category, out category))
238 {
239 if (category.TryGetValue(stat.Container, out container))
240 {
241 if (container.ContainsKey(stat.ShortName))
242 return true;
243 }
244 }
245 }
246
247 return false;
248 }
113 } 249 }
114 250
115 /// <summary> 251 /// <summary>
@@ -157,9 +293,26 @@ namespace OpenSim.Framework.Monitoring
157 293
158 public virtual double Value { get; set; } 294 public virtual double Value { get; set; }
159 295
296 /// <summary>
297 /// Constructor
298 /// </summary>
299 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
300 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
301 /// <param name='unitName'>
302 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
303 /// e.g. " frames"
304 /// </param>
305 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
306 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
307 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
308 /// <param name='description'>Description of stat</param>
160 public Stat( 309 public Stat(
161 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description) 310 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
162 { 311 {
312 if (StatsManager.SubCommands.Contains(category))
313 throw new Exception(
314 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
315
163 ShortName = shortName; 316 ShortName = shortName;
164 Name = name; 317 Name = name;
165 UnitName = unitName; 318 UnitName = unitName;
@@ -175,6 +328,12 @@ namespace OpenSim.Framework.Monitoring
175 { 328 {
176 return string.Format("{0}+{1}+{2}", container, category, shortName); 329 return string.Format("{0}+{1}+{2}", container, category, shortName);
177 } 330 }
331
332 public virtual string ToConsoleString()
333 {
334 return string.Format(
335 "{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
336 }
178 } 337 }
179 338
180 public class PercentageStat : Stat 339 public class PercentageStat : Stat
@@ -192,7 +351,7 @@ namespace OpenSim.Framework.Monitoring
192 if (c == 0) 351 if (c == 0)
193 return 0; 352 return 0;
194 353
195 return (double)Antecedent / c; 354 return (double)Antecedent / c * 100;
196 } 355 }
197 356
198 set 357 set
@@ -203,8 +362,13 @@ namespace OpenSim.Framework.Monitoring
203 362
204 public PercentageStat( 363 public PercentageStat(
205 string shortName, string name, string category, string container, StatVerbosity verbosity, string description) 364 string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
206 : base(shortName, name, " %", category, container, verbosity, description) 365 : base(shortName, name, "%", category, container, verbosity, description) {}
366
367 public override string ToConsoleString()
207 { 368 {
369 return string.Format(
370 "{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
371 Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
208 } 372 }
209 } 373 }
210} \ No newline at end of file 374} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs
index eaddb8c..28d6d5c 100644
--- a/OpenSim/Framework/Monitoring/Watchdog.cs
+++ b/OpenSim/Framework/Monitoring/Watchdog.cs
@@ -231,7 +231,25 @@ namespace OpenSim.Framework.Monitoring
231 private static bool RemoveThread(int threadID) 231 private static bool RemoveThread(int threadID)
232 { 232 {
233 lock (m_threads) 233 lock (m_threads)
234 return m_threads.Remove(threadID); 234 {
235 ThreadWatchdogInfo twi;
236 if (m_threads.TryGetValue(threadID, out twi))
237 {
238 m_log.DebugFormat(
239 "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
240
241 m_threads.Remove(threadID);
242
243 return true;
244 }
245 else
246 {
247 m_log.WarnFormat(
248 "[WATCHDOG]: Requested to remove thread with ID {0} but this is not being monitored", threadID);
249
250 return false;
251 }
252 }
235 } 253 }
236 254
237 public static bool AbortThread(int threadID) 255 public static bool AbortThread(int threadID)
diff --git a/OpenSim/Framework/RegionFlags.cs b/OpenSim/Framework/RegionFlags.cs
new file mode 100644
index 0000000..a3089b0
--- /dev/null
+++ b/OpenSim/Framework/RegionFlags.cs
@@ -0,0 +1,53 @@
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
28using System;
29
30namespace OpenSim.Framework
31{
32 /// <summary>
33 /// Region flags used internally by OpenSimulator to store installation specific information about regions.
34 /// </summary>
35 /// <remarks>
36 /// Don't confuse with OpenMetaverse.RegionFlags which are client facing flags (i.e. they go over the wire).
37 /// Returned by IGridService.GetRegionFlags()
38 /// </remarks>
39 [Flags]
40 public enum RegionFlags : int
41 {
42 DefaultRegion = 1, // Used for new Rez. Random if multiple defined
43 FallbackRegion = 2, // Regions we redirect to when the destination is down
44 RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
45 NoDirectLogin = 8, // Region unavailable for direct logins (by name)
46 Persistent = 16, // Don't remove on unregister
47 LockedOut = 32, // Don't allow registration
48 NoMove = 64, // Don't allow moving this region
49 Reservation = 128, // This is an inactive reservation
50 Authenticate = 256, // Require authentication
51 Hyperlink = 512 // Record represents a HG link
52 }
53} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index cf19002..a8f3a9e 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -96,11 +96,6 @@ namespace OpenSim.Framework.Servers
96 get { return m_httpServer; } 96 get { return m_httpServer; }
97 } 97 }
98 98
99 /// <summary>
100 /// Holds the non-viewer statistics collection object for this service/server
101 /// </summary>
102 protected IStatsCollector m_stats;
103
104 public BaseOpenSimServer() 99 public BaseOpenSimServer()
105 { 100 {
106 m_startuptime = DateTime.Now; 101 m_startuptime = DateTime.Now;
@@ -177,10 +172,6 @@ namespace OpenSim.Framework.Servers
177 "show info", 172 "show info",
178 "Show general information about the server", HandleShow); 173 "Show general information about the server", HandleShow);
179 174
180 m_console.Commands.AddCommand("General", false, "show stats",
181 "show stats",
182 "Show statistics", HandleShow);
183
184 m_console.Commands.AddCommand("General", false, "show threads", 175 m_console.Commands.AddCommand("General", false, "show threads",
185 "show threads", 176 "show threads",
186 "Show thread status", HandleShow); 177 "Show thread status", HandleShow);
@@ -226,12 +217,7 @@ namespace OpenSim.Framework.Servers
226 { 217 {
227 StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n"); 218 StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
228 sb.Append(GetUptimeReport()); 219 sb.Append(GetUptimeReport());
229 220 sb.Append(StatsManager.SimExtraStats.Report());
230 if (m_stats != null)
231 {
232 sb.Append(m_stats.Report());
233 }
234
235 sb.Append(Environment.NewLine); 221 sb.Append(Environment.NewLine);
236 sb.Append(GetThreadsReport()); 222 sb.Append(GetThreadsReport());
237 223
@@ -382,10 +368,6 @@ namespace OpenSim.Framework.Servers
382 { 368 {
383 Notice("set log level [level] - change the console logging level only. For example, off or debug."); 369 Notice("set log level [level] - change the console logging level only. For example, off or debug.");
384 Notice("show info - show server information (e.g. startup path)."); 370 Notice("show info - show server information (e.g. startup path).");
385
386 if (m_stats != null)
387 Notice("show stats - show statistical information for this server");
388
389 Notice("show threads - list tracked threads"); 371 Notice("show threads - list tracked threads");
390 Notice("show uptime - show server startup time and uptime."); 372 Notice("show uptime - show server startup time and uptime.");
391 Notice("show version - show server version."); 373 Notice("show version - show server version.");
@@ -409,11 +391,6 @@ namespace OpenSim.Framework.Servers
409 ShowInfo(); 391 ShowInfo();
410 break; 392 break;
411 393
412 case "stats":
413 if (m_stats != null)
414 Notice(m_stats.Report());
415 break;
416
417 case "threads": 394 case "threads":
418 Notice(GetThreadsReport()); 395 Notice(GetThreadsReport());
419 break; 396 break;
@@ -604,8 +581,7 @@ namespace OpenSim.Framework.Servers
604 581
605 public string osSecret { 582 public string osSecret {
606 // Secret uuid for the simulator 583 // Secret uuid for the simulator
607 get { return m_osSecret; } 584 get { return m_osSecret; }
608
609 } 585 }
610 586
611 public string StatReport(IOSHttpRequest httpRequest) 587 public string StatReport(IOSHttpRequest httpRequest)
@@ -613,11 +589,11 @@ namespace OpenSim.Framework.Servers
613 // If we catch a request for "callback", wrap the response in the value for jsonp 589 // If we catch a request for "callback", wrap the response in the value for jsonp
614 if (httpRequest.Query.ContainsKey("callback")) 590 if (httpRequest.Query.ContainsKey("callback"))
615 { 591 {
616 return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");"; 592 return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
617 } 593 }
618 else 594 else
619 { 595 {
620 return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version); 596 return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
621 } 597 }
622 } 598 }
623 599
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index a9b2745..3d4dce1 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -254,8 +254,14 @@ namespace OpenSim
254 m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug); 254 m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
255 255
256 m_console.Commands.AddCommand("Debug", false, "debug scene", 256 m_console.Commands.AddCommand("Debug", false, "debug scene",
257 "debug scene <scripting> <collisions> <physics>", 257 "debug scene active|collisions|physics|scripting|teleport true|false",
258 "Turn on scene debugging", Debug); 258 "Turn on scene debugging.",
259 "If active is false then main scene update and maintenance loops are suspended.\n"
260 + "If collisions is false then collisions with other objects are turned off.\n"
261 + "If physics is false then all physics objects are non-physical.\n"
262 + "If scripting is false then no scripting operations happen.\n"
263 + "If teleport is true then some extra teleport debug information is logged.",
264 Debug);
259 265
260 m_console.Commands.AddCommand("General", false, "change region", 266 m_console.Commands.AddCommand("General", false, "change region",
261 "change region <region name>", 267 "change region <region name>",
@@ -930,7 +936,8 @@ namespace OpenSim
930 } 936 }
931 else 937 else
932 { 938 {
933 MainConsole.Instance.Output("Usage: debug scene scripting|collisions|physics|teleport true|false"); 939 MainConsole.Instance.Output(
940 "Usage: debug scene active|scripting|collisions|physics|teleport true|false");
934 } 941 }
935 942
936 break; 943 break;
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index d107b7a..b410a0e 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -232,8 +232,6 @@ namespace OpenSim
232 232
233 base.StartupSpecific(); 233 base.StartupSpecific();
234 234
235 m_stats = StatsManager.SimExtraStats;
236
237 // Create a ModuleLoader instance 235 // Create a ModuleLoader instance
238 m_moduleLoader = new ModuleLoader(m_config.Source); 236 m_moduleLoader = new ModuleLoader(m_config.Source);
239 237
@@ -249,51 +247,51 @@ namespace OpenSim
249 plugin.PostInitialise(); 247 plugin.PostInitialise();
250 } 248 }
251 249
252 AddPluginCommands(); 250 if (m_console != null)
251 {
252 StatsManager.RegisterConsoleCommands(m_console);
253 AddPluginCommands(m_console);
254 }
253 } 255 }
254 256
255 protected virtual void AddPluginCommands() 257 protected virtual void AddPluginCommands(CommandConsole console)
256 { 258 {
257 // If console exists add plugin commands. 259 List<string> topics = GetHelpTopics();
258 if (m_console != null)
259 {
260 List<string> topics = GetHelpTopics();
261 260
262 foreach (string topic in topics) 261 foreach (string topic in topics)
263 { 262 {
264 string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1); 263 string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
265 264
266 // This is a hack to allow the user to enter the help command in upper or lowercase. This will go 265 // This is a hack to allow the user to enter the help command in upper or lowercase. This will go
267 // away at some point. 266 // away at some point.
268 m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic, 267 console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
269 "help " + capitalizedTopic, 268 "help " + capitalizedTopic,
270 "Get help on plugin command '" + topic + "'", 269 "Get help on plugin command '" + topic + "'",
271 HandleCommanderHelp); 270 HandleCommanderHelp);
272 m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic, 271 console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
273 "help " + capitalizedTopic, 272 "help " + capitalizedTopic,
274 "Get help on plugin command '" + topic + "'", 273 "Get help on plugin command '" + topic + "'",
275 HandleCommanderHelp); 274 HandleCommanderHelp);
276 275
277 ICommander commander = null; 276 ICommander commander = null;
278 277
279 Scene s = SceneManager.CurrentOrFirstScene; 278 Scene s = SceneManager.CurrentOrFirstScene;
280 279
281 if (s != null && s.GetCommanders() != null) 280 if (s != null && s.GetCommanders() != null)
282 { 281 {
283 if (s.GetCommanders().ContainsKey(topic)) 282 if (s.GetCommanders().ContainsKey(topic))
284 commander = s.GetCommanders()[topic]; 283 commander = s.GetCommanders()[topic];
285 } 284 }
286 285
287 if (commander == null) 286 if (commander == null)
288 continue; 287 continue;
289 288
290 foreach (string command in commander.Commands.Keys) 289 foreach (string command in commander.Commands.Keys)
291 { 290 {
292 m_console.Commands.AddCommand(capitalizedTopic, false, 291 console.Commands.AddCommand(capitalizedTopic, false,
293 topic + " " + command, 292 topic + " " + command,
294 topic + " " + commander.Commands[command].ShortHelp(), 293 topic + " " + commander.Commands[command].ShortHelp(),
295 String.Empty, HandleCommanderCommand); 294 String.Empty, HandleCommanderCommand);
296 }
297 } 295 }
298 } 296 }
299 } 297 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index e113c60..132546b 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
94 94
95 //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); 95 //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
96 96
97 scene.EventManager.OnNewClient += OnNewClient; 97// scene.EventManager.OnNewClient += OnNewClient;
98 98
99 // TODO: Leaving these open, or closing them when we 99 // TODO: Leaving these open, or closing them when we
100 // become a child is incorrect. It messes up TP in a big 100 // become a child is incorrect. It messes up TP in a big
@@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 // circuit is there. 102 // circuit is there.
103 103
104 scene.EventManager.OnClientClosed += ClientClosed; 104 scene.EventManager.OnClientClosed += ClientClosed;
105
105 scene.EventManager.OnMakeChildAgent += MakeChildAgent; 106 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
106 scene.EventManager.OnRegisterCaps += OnRegisterCaps; 107 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
107 108
@@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden
226 227
227 #endregion 228 #endregion
228 229
229 private void OnNewClient(IClientAPI client)
230 {
231 //client.OnLogout += ClientClosed;
232 }
233
234// private void ClientClosed(IClientAPI client)
235// {
236// ClientClosed(client.AgentId);
237// }
238
239 private void ClientClosed(UUID agentID, Scene scene) 230 private void ClientClosed(UUID agentID, Scene scene)
240 { 231 {
241// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); 232// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 6ccabf1..d04bd96 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -47,6 +47,7 @@ using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces; 47using OpenSim.Services.Interfaces;
48using Timer = System.Timers.Timer; 48using Timer = System.Timers.Timer;
49using AssetLandmark = OpenSim.Framework.AssetLandmark; 49using AssetLandmark = OpenSim.Framework.AssetLandmark;
50using RegionFlags = OpenMetaverse.RegionFlags;
50using Nini.Config; 51using Nini.Config;
51 52
52using System.IO; 53using System.IO;
@@ -3983,7 +3984,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3983 { 3984 {
3984 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3985 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3985 3986
3986 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3987 ImprovedTerseObjectUpdatePacket packet
3988 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3987 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3989 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3988 packet.RegionData.TimeDilation = timeDilation; 3990 packet.RegionData.TimeDilation = timeDilation;
3989 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3991 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4028,7 +4030,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4028 { 4030 {
4029 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 4031 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4030 4032
4031 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 4033 ImprovedTerseObjectUpdatePacket packet
4034 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4035 PacketType.ImprovedTerseObjectUpdate);
4032 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4036 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4033 packet.RegionData.TimeDilation = timeDilation; 4037 packet.RegionData.TimeDilation = timeDilation;
4034 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4038 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4036,7 +4040,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4036 for (int i = 0; i < blocks.Count; i++) 4040 for (int i = 0; i < blocks.Count; i++)
4037 packet.ObjectData[i] = blocks[i]; 4041 packet.ObjectData[i] = blocks[i];
4038 4042
4039 OutPacket(packet, ThrottleOutPacketType.Task, true); 4043 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4040 } 4044 }
4041 4045
4042 #endregion Packet Sending 4046 #endregion Packet Sending
@@ -5037,7 +5041,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5037 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; 5041 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
5038 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; 5042 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
5039 5043
5040 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); 5044 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
5045 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
5046
5041 block.Data = data; 5047 block.Data = data;
5042 5048
5043 if (textureEntry != null && textureEntry.Length > 0) 5049 if (textureEntry != null && textureEntry.Length > 0)
@@ -11949,7 +11955,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11949 logPacket = false; 11955 logPacket = false;
11950 11956
11951 if (DebugPacketLevel <= 50 11957 if (DebugPacketLevel <= 50
11952 & (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) 11958 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
11953 logPacket = false; 11959 logPacket = false;
11954 11960
11955 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily) 11961 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@@ -12481,7 +12487,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12481 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12487 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12482 12488
12483 12489
12484 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 12490 ImprovedTerseObjectUpdatePacket packet
12491 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12492 PacketType.ImprovedTerseObjectUpdate);
12493
12485 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 12494 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
12486 packet.RegionData.TimeDilation = timeDilation; 12495 packet.RegionData.TimeDilation = timeDilation;
12487 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; 12496 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index b3db064..97b79ce 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -100,9 +100,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
100 100
101 /// <summary>The measured resolution of Environment.TickCount</summary> 101 /// <summary>The measured resolution of Environment.TickCount</summary>
102 public readonly float TickCountResolution; 102 public readonly float TickCountResolution;
103
103 /// <summary>Number of prim updates to put on the queue each time the 104 /// <summary>Number of prim updates to put on the queue each time the
104 /// OnQueueEmpty event is triggered for updates</summary> 105 /// OnQueueEmpty event is triggered for updates</summary>
105 public readonly int PrimUpdatesPerCallback; 106 public readonly int PrimUpdatesPerCallback;
107
106 /// <summary>Number of texture packets to put on the queue each time the 108 /// <summary>Number of texture packets to put on the queue each time the
107 /// OnQueueEmpty event is triggered for textures</summary> 109 /// OnQueueEmpty event is triggered for textures</summary>
108 public readonly int TextureSendLimit; 110 public readonly int TextureSendLimit;
@@ -124,28 +126,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
124 126
125 /// <summary>Manages authentication for agent circuits</summary> 127 /// <summary>Manages authentication for agent circuits</summary>
126 private AgentCircuitManager m_circuitManager; 128 private AgentCircuitManager m_circuitManager;
129
127 /// <summary>Reference to the scene this UDP server is attached to</summary> 130 /// <summary>Reference to the scene this UDP server is attached to</summary>
128 protected Scene m_scene; 131 protected Scene m_scene;
132
129 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 133 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
130 private Location m_location; 134 private Location m_location;
135
131 /// <summary>The size of the receive buffer for the UDP socket. This value 136 /// <summary>The size of the receive buffer for the UDP socket. This value
132 /// is passed up to the operating system and used in the system networking 137 /// is passed up to the operating system and used in the system networking
133 /// stack. Use zero to leave this value as the default</summary> 138 /// stack. Use zero to leave this value as the default</summary>
134 private int m_recvBufferSize; 139 private int m_recvBufferSize;
140
135 /// <summary>Flag to process packets asynchronously or synchronously</summary> 141 /// <summary>Flag to process packets asynchronously or synchronously</summary>
136 private bool m_asyncPacketHandling; 142 private bool m_asyncPacketHandling;
143
137 /// <summary>Tracks whether or not a packet was sent each round so we know 144 /// <summary>Tracks whether or not a packet was sent each round so we know
138 /// whether or not to sleep</summary> 145 /// whether or not to sleep</summary>
139 private bool m_packetSent; 146 private bool m_packetSent;
140 147
141 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> 148 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
142 private int m_elapsedMSSinceLastStatReport = 0; 149 private int m_elapsedMSSinceLastStatReport = 0;
150
143 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> 151 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
144 private int m_tickLastOutgoingPacketHandler; 152 private int m_tickLastOutgoingPacketHandler;
153
145 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> 154 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
146 private int m_elapsedMSOutgoingPacketHandler; 155 private int m_elapsedMSOutgoingPacketHandler;
156
147 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> 157 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
148 private int m_elapsed100MSOutgoingPacketHandler; 158 private int m_elapsed100MSOutgoingPacketHandler;
159
149 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> 160 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
150 private int m_elapsed500MSOutgoingPacketHandler; 161 private int m_elapsed500MSOutgoingPacketHandler;
151 162
@@ -425,6 +436,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
425 byte[] data = packet.ToBytes(); 436 byte[] data = packet.ToBytes();
426 SendPacketData(udpClient, data, packet.Type, category, method); 437 SendPacketData(udpClient, data, packet.Type, category, method);
427 } 438 }
439
440 PacketPool.Instance.ReturnPacket(packet);
428 } 441 }
429 442
430 /// <summary> 443 /// <summary>
@@ -742,7 +755,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
742 755
743 try 756 try
744 { 757 {
745 packet = Packet.BuildPacket(buffer.Data, ref packetEnd, 758// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
759// // Only allocate a buffer for zerodecoding if the packet is zerocoded
760// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
761 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
746 // Only allocate a buffer for zerodecoding if the packet is zerocoded 762 // Only allocate a buffer for zerodecoding if the packet is zerocoded
747 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 763 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
748 } 764 }
@@ -757,11 +773,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
757 773
758 return; // Drop short packet 774 return; // Drop short packet
759 } 775 }
760 catch(Exception e) 776 catch (Exception e)
761 { 777 {
762 if (m_malformedCount < 100) 778 if (m_malformedCount < 100)
763 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 779 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
780
764 m_malformedCount++; 781 m_malformedCount++;
782
765 if ((m_malformedCount % 100000) == 0) 783 if ((m_malformedCount % 100000) == 0)
766 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); 784 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
767 } 785 }
@@ -1169,20 +1187,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1169 { 1187 {
1170 IClientAPI client = null; 1188 IClientAPI client = null;
1171 1189
1172 // In priciple there shouldn't be more than one thread here, ever. 1190 // We currently synchronize this code across the whole scene to avoid issues such as
1173 // But in case that happens, we need to synchronize this piece of code 1191 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1174 // because it's too important 1192 // consistently, this lock could probably be removed.
1175 lock (this) 1193 lock (this)
1176 { 1194 {
1177 if (!m_scene.TryGetClient(agentID, out client)) 1195 if (!m_scene.TryGetClient(agentID, out client))
1178 { 1196 {
1179 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1197 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1180 1198
1181 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1199 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1182 client.OnLogout += LogoutHandler; 1200 client.OnLogout += LogoutHandler;
1183 1201
1184 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1202 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1185 1203
1186 client.Start(); 1204 client.Start();
1187 } 1205 }
1188 } 1206 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index fc9406b..71f6fe1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -31,6 +31,7 @@ using System.Reflection;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenMetaverse.Packets; 32using OpenMetaverse.Packets;
33using log4net; 33using log4net;
34using OpenSim.Framework.Monitoring;
34 35
35namespace OpenSim.Region.ClientStack.LindenUDP 36namespace OpenSim.Region.ClientStack.LindenUDP
36{ 37{
@@ -43,17 +44,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
43 private bool packetPoolEnabled = true; 44 private bool packetPoolEnabled = true;
44 private bool dataBlockPoolEnabled = true; 45 private bool dataBlockPoolEnabled = true;
45 46
47 private PercentageStat m_packetsReusedStat = new PercentageStat(
48 "PacketsReused",
49 "Packets reused",
50 "clientstack",
51 "packetpool",
52 StatVerbosity.Debug,
53 "Number of packets reused out of all requests to the packet pool");
54
55 private PercentageStat m_blocksReusedStat = new PercentageStat(
56 "BlocksReused",
57 "Blocks reused",
58 "clientstack",
59 "packetpool",
60 StatVerbosity.Debug,
61 "Number of data blocks reused out of all requests to the packet pool");
62
46 /// <summary> 63 /// <summary>
47 /// Pool of packets available for reuse. 64 /// Pool of packets available for reuse.
48 /// </summary> 65 /// </summary>
49 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>(); 66 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
50 67
51 private static Dictionary<Type, Stack<Object>> DataBlocks = 68 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
52 new Dictionary<Type, Stack<Object>>();
53
54 static PacketPool()
55 {
56 }
57 69
58 public static PacketPool Instance 70 public static PacketPool Instance
59 { 71 {
@@ -72,8 +84,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
72 get { return dataBlockPoolEnabled; } 84 get { return dataBlockPoolEnabled; }
73 } 85 }
74 86
87 private PacketPool()
88 {
89 StatsManager.RegisterStat(m_packetsReusedStat);
90 StatsManager.RegisterStat(m_blocksReusedStat);
91 }
92
93 /// <summary>
94 /// Gets a packet of the given type.
95 /// </summary>
96 /// <param name='type'></param>
97 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
75 public Packet GetPacket(PacketType type) 98 public Packet GetPacket(PacketType type)
76 { 99 {
100 m_packetsReusedStat.Consequent++;
101
77 Packet packet; 102 Packet packet;
78 103
79 if (!packetPoolEnabled) 104 if (!packetPoolEnabled)
@@ -89,6 +114,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
89 else 114 else
90 { 115 {
91 // Recycle old packages 116 // Recycle old packages
117 m_packetsReusedStat.Antecedent++;
118
92 packet = (pool[type]).Pop(); 119 packet = (pool[type]).Pop();
93 } 120 }
94 } 121 }
@@ -138,7 +165,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
138 { 165 {
139 PacketType type = GetType(bytes); 166 PacketType type = GetType(bytes);
140 167
141 Array.Clear(zeroBuffer, 0, zeroBuffer.Length); 168// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
142 169
143 int i = 0; 170 int i = 0;
144 Packet packet = GetPacket(type); 171 Packet packet = GetPacket(type);
@@ -185,6 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
185 switch (packet.Type) 212 switch (packet.Type)
186 { 213 {
187 // List pooling packets here 214 // List pooling packets here
215 case PacketType.AgentUpdate:
188 case PacketType.PacketAck: 216 case PacketType.PacketAck:
189 case PacketType.ObjectUpdate: 217 case PacketType.ObjectUpdate:
190 case PacketType.ImprovedTerseObjectUpdate: 218 case PacketType.ImprovedTerseObjectUpdate:
@@ -211,16 +239,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
211 } 239 }
212 } 240 }
213 241
214 public static T GetDataBlock<T>() where T: new() 242 public T GetDataBlock<T>() where T: new()
215 { 243 {
216 lock (DataBlocks) 244 lock (DataBlocks)
217 { 245 {
246 m_blocksReusedStat.Consequent++;
247
218 Stack<Object> s; 248 Stack<Object> s;
219 249
220 if (DataBlocks.TryGetValue(typeof(T), out s)) 250 if (DataBlocks.TryGetValue(typeof(T), out s))
221 { 251 {
222 if (s.Count > 0) 252 if (s.Count > 0)
253 {
254 m_blocksReusedStat.Antecedent++;
223 return (T)s.Pop(); 255 return (T)s.Pop();
256 }
224 } 257 }
225 else 258 else
226 { 259 {
@@ -231,7 +264,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
231 } 264 }
232 } 265 }
233 266
234 public static void ReturnDataBlock<T>(T block) where T: new() 267 public void ReturnDataBlock<T>(T block) where T: new()
235 { 268 {
236 if (block == null) 269 if (block == null)
237 return; 270 return;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 109a8e1..fa9378c 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -43,7 +43,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
43 /// This will contain basic tests for the LindenUDP client stack 43 /// This will contain basic tests for the LindenUDP client stack
44 /// </summary> 44 /// </summary>
45 [TestFixture] 45 [TestFixture]
46 public class BasicCircuitTests 46 public class BasicCircuitTests : OpenSimTestCase
47 { 47 {
48 private Scene m_scene; 48 private Scene m_scene;
49 private TestLLUDPServer m_udpServer; 49 private TestLLUDPServer m_udpServer;
@@ -143,7 +143,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
143 public void TestAddClient() 143 public void TestAddClient()
144 { 144 {
145 TestHelpers.InMethod(); 145 TestHelpers.InMethod();
146// XmlConfigurator.Configure(); 146// TestHelpers.EnableLogging();
147 147
148 AddUdpServer(); 148 AddUdpServer();
149 149
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index a5c4584..0aee0d4 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -212,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
212 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); 212 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
213 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); 213 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
214 214
215 if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) 215 if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
216 { 216 {
217 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); 217 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID);
218 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); 218 GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
@@ -232,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
232 return true; 232 return true;
233 233
234 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); 234 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
235 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) 235 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
236 return true; 236 return true;
237 237
238 return false; 238 return false;
@@ -256,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
256 reason = string.Empty; 256 reason = string.Empty;
257 logout = false; 257 logout = false;
258 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); 258 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
259 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) 259 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
260 { 260 {
261 // this user is going to another grid 261 // this user is going to another grid
262 // check if HyperGrid teleport is allowed, based on user level 262 // check if HyperGrid teleport is allowed, based on user level
@@ -303,7 +303,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
303 // The rest is only needed for controlling appearance 303 // The rest is only needed for controlling appearance
304 304
305 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); 305 int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
306 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) 306 if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
307 { 307 {
308 // this user is going to another grid 308 // this user is going to another grid
309 if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID)) 309 if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID))
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index fdef9d8..5fd1bce 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -40,6 +40,7 @@ using OpenMetaverse;
40using OpenSim.Framework; 40using OpenSim.Framework;
41using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using RegionFlags = OpenMetaverse.RegionFlags;
43 44
44namespace OpenSim.Region.CoreModules.World.Estate 45namespace OpenSim.Region.CoreModules.World.Estate
45{ 46{
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index 4f06737..d5b2adb 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -33,6 +33,7 @@ using OpenMetaverse;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using RegionFlags = OpenMetaverse.RegionFlags;
36 37
37namespace OpenSim.Region.CoreModules.World.Land 38namespace OpenSim.Region.CoreModules.World.Land
38{ 39{
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index 6e39e9a..7a35182 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
30using System.Reflection; 31using System.Reflection;
31using System.Text; 32using System.Text;
32using System.Text.RegularExpressions; 33using System.Text.RegularExpressions;
@@ -83,29 +84,56 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
83 m_console.Commands.AddCommand( 84 m_console.Commands.AddCommand(
84 "Objects", false, "delete object owner", 85 "Objects", false, "delete object owner",
85 "delete object owner <UUID>", 86 "delete object owner <UUID>",
86 "Delete a scene object by owner", HandleDeleteObject); 87 "Delete scene objects by owner",
88 "Command will ask for confirmation before proceeding.",
89 HandleDeleteObject);
87 90
88 m_console.Commands.AddCommand( 91 m_console.Commands.AddCommand(
89 "Objects", false, "delete object creator", 92 "Objects", false, "delete object creator",
90 "delete object creator <UUID>", 93 "delete object creator <UUID>",
91 "Delete a scene object by creator", HandleDeleteObject); 94 "Delete scene objects by creator",
95 "Command will ask for confirmation before proceeding.",
96 HandleDeleteObject);
92 97
93 m_console.Commands.AddCommand( 98 m_console.Commands.AddCommand(
94 "Objects", false, "delete object uuid", 99 "Objects", false, "delete object uuid",
95 "delete object uuid <UUID>", 100 "delete object uuid <UUID>",
96 "Delete a scene object by uuid", HandleDeleteObject); 101 "Delete a scene object by uuid",
102 HandleDeleteObject);
97 103
98 m_console.Commands.AddCommand( 104 m_console.Commands.AddCommand(
99 "Objects", false, "delete object name", 105 "Objects", false, "delete object name",
100 "delete object name [--regex] <name>", 106 "delete object name [--regex] <name>",
101 "Delete a scene object by name.", 107 "Delete a scene object by name.",
102 "If --regex is specified then the name is treatead as a regular expression", 108 "Command will ask for confirmation before proceeding.\n"
109 + "If --regex is specified then the name is treatead as a regular expression",
103 HandleDeleteObject); 110 HandleDeleteObject);
104 111
105 m_console.Commands.AddCommand( 112 m_console.Commands.AddCommand(
106 "Objects", false, "delete object outside", 113 "Objects", false, "delete object outside",
107 "delete object outside", 114 "delete object outside",
108 "Delete all scene objects outside region boundaries", HandleDeleteObject); 115 "Delete all scene objects outside region boundaries",
116 "Command will ask for confirmation before proceeding.",
117 HandleDeleteObject);
118
119 m_console.Commands.AddCommand(
120 "Objects",
121 false,
122 "delete object pos",
123 "delete object pos <start-coord> to <end-coord>",
124 "Delete scene objects within the given area.",
125 "Each component of the coord is comma separated. There must be no spaces between the commas.\n"
126 + "If you don't care about the z component you can simply omit it.\n"
127 + "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
128 + "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
129 + "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
130 + "e.g.\n"
131 + "delete object pos 20,20,20 to 40,40,40\n"
132 + "delete object pos 20,20 to 40,40\n"
133 + "delete object pos ,20,20 to ,40,40\n"
134 + "delete object pos ,,30 to ,,~\n"
135 + "delete object pos ,,-~ to ,,30",
136 HandleDeleteObject);
109 137
110 m_console.Commands.AddCommand( 138 m_console.Commands.AddCommand(
111 "Objects", 139 "Objects",
@@ -301,23 +329,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
301 return; 329 return;
302 } 330 }
303 331
304 string rawConsoleStartVector = cmdparams[3]; 332 Vector3 startVector, endVector;
305 Vector3 startVector;
306 333
307 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) 334 if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
308 {
309 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
310 return; 335 return;
311 }
312
313 string rawConsoleEndVector = cmdparams[5];
314 Vector3 endVector;
315
316 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
317 {
318 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
319 return;
320 }
321 336
322 Predicate<SceneObjectGroup> searchPredicate 337 Predicate<SceneObjectGroup> searchPredicate
323 = so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector); 338 = so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector);
@@ -557,6 +572,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
557 572
558 break; 573 break;
559 574
575 case "pos":
576 deletes = GetDeleteCandidatesByPos(module, cmd);
577 break;
578
560 default: 579 default:
561 m_console.OutputFormat("Unrecognized mode {0}", mode); 580 m_console.OutputFormat("Unrecognized mode {0}", mode);
562 return; 581 return;
@@ -571,7 +590,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
571 string.Format( 590 string.Format(
572 "Are you sure that you want to delete {0} objects from {1}", 591 "Are you sure that you want to delete {0} objects from {1}",
573 deletes.Count, m_scene.RegionInfo.RegionName), 592 deletes.Count, m_scene.RegionInfo.RegionName),
574 "n"); 593 "y/N");
575 594
576 if (response.ToLower() != "y") 595 if (response.ToLower() != "y")
577 { 596 {
@@ -593,9 +612,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
593 612
594 private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams) 613 private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams)
595 { 614 {
596 if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
597 return null;
598
599 bool useRegex = false; 615 bool useRegex = false;
600 OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); 616 OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
601 617
@@ -629,5 +645,52 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
629 645
630 return sceneObjects; 646 return sceneObjects;
631 } 647 }
648
649 /// <summary>
650 /// Get scene object delete candidates by position
651 /// </summary>
652 /// <param name='module'></param>
653 /// <param name='cmdparams'></param>
654 /// <returns>null if parsing failed on one of the arguments, otherwise a list of objects to delete. If there
655 /// are no objects to delete then the list will be empty./returns>
656 private List<SceneObjectGroup> GetDeleteCandidatesByPos(string module, string[] cmdparams)
657 {
658 if (cmdparams.Length < 5)
659 {
660 m_console.OutputFormat("Usage: delete object pos <start-coord> to <end-coord>");
661 return null;
662 }
663
664 Vector3 startVector, endVector;
665
666 if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
667 return null;
668
669 return m_scene.GetSceneObjectGroups().FindAll(
670 so => !so.IsAttachment && Util.IsInsideBox(so.AbsolutePosition, startVector, endVector));
671 }
672
673 private bool TryParseVectorRange(IEnumerable<string> rawComponents, out Vector3 startVector, out Vector3 endVector)
674 {
675 string rawConsoleStartVector = rawComponents.Take(1).Single();
676
677 if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
678 {
679 m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
680 endVector = Vector3.Zero;
681
682 return false;
683 }
684
685 string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single();
686
687 if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
688 {
689 m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
690 return false;
691 }
692
693 return true;
694 }
632 } 695 }
633} \ No newline at end of file 696} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 7133817..e2414eb 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -125,13 +125,21 @@ namespace OpenSim.Region.Framework.Scenes
125 /// </summary> 125 /// </summary>
126 /// <remarks> 126 /// <remarks>
127 /// This is triggered for both child and root agent client connections. 127 /// This is triggered for both child and root agent client connections.
128 ///
128 /// Triggered before OnClientLogin. 129 /// Triggered before OnClientLogin.
130 ///
131 /// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
132 /// do this on a separate thread.
129 /// </remarks> 133 /// </remarks>
130 public event OnNewClientDelegate OnNewClient; 134 public event OnNewClientDelegate OnNewClient;
131 135
132 /// <summary> 136 /// <summary>
133 /// Fired if the client entering this sim is doing so as a new login 137 /// Fired if the client entering this sim is doing so as a new login
134 /// </summary> 138 /// </summary>
139 /// <remarks>
140 /// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
141 /// do this on a separate thread.
142 /// </remarks>
135 public event Action<IClientAPI> OnClientLogin; 143 public event Action<IClientAPI> OnClientLogin;
136 144
137 public delegate void OnNewPresenceDelegate(ScenePresence presence); 145 public delegate void OnNewPresenceDelegate(ScenePresence presence);
@@ -153,6 +161,9 @@ namespace OpenSim.Region.Framework.Scenes
153 /// <remarks> 161 /// <remarks>
154 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both 162 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both
155 /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see> 163 /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
164 ///
165 /// Triggered under per-agent lock. So if you want to perform any long-running operations, please
166 /// do this on a separate thread.
156 /// </remarks> 167 /// </remarks>
157 public event OnRemovePresenceDelegate OnRemovePresence; 168 public event OnRemovePresenceDelegate OnRemovePresence;
158 169
@@ -429,6 +440,9 @@ namespace OpenSim.Region.Framework.Scenes
429 /// </summary> 440 /// </summary>
430 /// <remarks> 441 /// <remarks>
431 /// At the point of firing, the scene still contains the client's scene presence. 442 /// At the point of firing, the scene still contains the client's scene presence.
443 ///
444 /// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
445 /// do this on a separate thread.
432 /// </remarks> 446 /// </remarks>
433 public event ClientClosed OnClientClosed; 447 public event ClientClosed OnClientClosed;
434 448
@@ -917,7 +931,7 @@ namespace OpenSim.Region.Framework.Scenes
917 public event SceneObjectPartCopyDelegate OnSceneObjectPartCopy; 931 public event SceneObjectPartCopyDelegate OnSceneObjectPartCopy;
918 public delegate void SceneObjectPartCopyDelegate(SceneObjectPart copy, SceneObjectPart original, bool userExposed); 932 public delegate void SceneObjectPartCopyDelegate(SceneObjectPart copy, SceneObjectPart original, bool userExposed);
919 933
920 public delegate void SceneObjectPartUpdated(SceneObjectPart sop); 934 public delegate void SceneObjectPartUpdated(SceneObjectPart sop, bool full);
921 public event SceneObjectPartUpdated OnSceneObjectPartUpdated; 935 public event SceneObjectPartUpdated OnSceneObjectPartUpdated;
922 936
923 public delegate void ScenePresenceUpdated(ScenePresence sp); 937 public delegate void ScenePresenceUpdated(ScenePresence sp);
@@ -2862,7 +2876,7 @@ namespace OpenSim.Region.Framework.Scenes
2862 } 2876 }
2863 } 2877 }
2864 2878
2865 public void TriggerSceneObjectPartUpdated(SceneObjectPart sop) 2879 public void TriggerSceneObjectPartUpdated(SceneObjectPart sop, bool full)
2866 { 2880 {
2867 SceneObjectPartUpdated handler = OnSceneObjectPartUpdated; 2881 SceneObjectPartUpdated handler = OnSceneObjectPartUpdated;
2868 if (handler != null) 2882 if (handler != null)
@@ -2871,7 +2885,7 @@ namespace OpenSim.Region.Framework.Scenes
2871 { 2885 {
2872 try 2886 try
2873 { 2887 {
2874 d(sop); 2888 d(sop, full);
2875 } 2889 }
2876 catch (Exception e) 2890 catch (Exception e)
2877 { 2891 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 8d112db..c8e7156 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -80,6 +80,11 @@ namespace OpenSim.Region.Framework.Scenes
80 public SynchronizeSceneHandler SynchronizeScene; 80 public SynchronizeSceneHandler SynchronizeScene;
81 81
82 /// <summary> 82 /// <summary>
83 /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other.
84 /// </summary>
85 private object m_removeClientLock = new object();
86
87 /// <summary>
83 /// Statistical information for this scene. 88 /// Statistical information for this scene.
84 /// </summary> 89 /// </summary>
85 public SimStatsReporter StatsReporter { get; private set; } 90 public SimStatsReporter StatsReporter { get; private set; }
@@ -308,6 +313,31 @@ namespace OpenSim.Region.Framework.Scenes
308 } 313 }
309 private volatile bool m_shuttingDown; 314 private volatile bool m_shuttingDown;
310 315
316 /// <summary>
317 /// Is the scene active?
318 /// </summary>
319 /// <remarks>
320 /// If false, maintenance and update loops are not being run. Updates can still be triggered manually if
321 /// the scene is not active.
322 /// </remarks>
323 public bool Active
324 {
325 get { return m_active; }
326 set
327 {
328 if (value)
329 {
330 if (!m_active)
331 Start();
332 }
333 else
334 {
335 m_active = false;
336 }
337 }
338 }
339 private volatile bool m_active;
340
311// private int m_lastUpdate; 341// private int m_lastUpdate;
312 private bool m_firstHeartbeat = true; 342 private bool m_firstHeartbeat = true;
313 343
@@ -1187,6 +1217,14 @@ namespace OpenSim.Region.Framework.Scenes
1187 1217
1188 public void SetSceneCoreDebug(Dictionary<string, string> options) 1218 public void SetSceneCoreDebug(Dictionary<string, string> options)
1189 { 1219 {
1220 if (options.ContainsKey("active"))
1221 {
1222 bool active;
1223
1224 if (bool.TryParse(options["active"], out active))
1225 Active = active;
1226 }
1227
1190 if (options.ContainsKey("scripting")) 1228 if (options.ContainsKey("scripting"))
1191 { 1229 {
1192 bool enableScripts = true; 1230 bool enableScripts = true;
@@ -1326,6 +1364,8 @@ namespace OpenSim.Region.Framework.Scenes
1326 /// </summary> 1364 /// </summary>
1327 public void Start() 1365 public void Start()
1328 { 1366 {
1367 m_active = true;
1368
1329// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName); 1369// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName);
1330 1370
1331 //m_heartbeatTimer.Enabled = true; 1371 //m_heartbeatTimer.Enabled = true;
@@ -1382,7 +1422,7 @@ namespace OpenSim.Region.Framework.Scenes
1382 #region Update Methods 1422 #region Update Methods
1383 1423
1384 /// <summary> 1424 /// <summary>
1385 /// Performs per-frame updates regularly 1425 /// Activate the various loops necessary to continually update the scene.
1386 /// </summary> 1426 /// </summary>
1387 private void Heartbeat() 1427 private void Heartbeat()
1388 { 1428 {
@@ -1439,7 +1479,7 @@ namespace OpenSim.Region.Framework.Scenes
1439 List<Vector3> coarseLocations; 1479 List<Vector3> coarseLocations;
1440 List<UUID> avatarUUIDs; 1480 List<UUID> avatarUUIDs;
1441 1481
1442 while (!m_shuttingDown && (endRun == null || MaintenanceRun < endRun)) 1482 while (!m_shuttingDown && ((endRun == null && Active) || MaintenanceRun < endRun))
1443 { 1483 {
1444 runtc = Util.EnvironmentTickCount(); 1484 runtc = Util.EnvironmentTickCount();
1445 ++MaintenanceRun; 1485 ++MaintenanceRun;
@@ -1501,7 +1541,7 @@ namespace OpenSim.Region.Framework.Scenes
1501 int sleepMS; 1541 int sleepMS;
1502 int framestart; 1542 int framestart;
1503 1543
1504 while (!m_shuttingDown && (endFrame == null || Frame < endFrame)) 1544 while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame))
1505 { 1545 {
1506 framestart = Util.EnvironmentTickCount(); 1546 framestart = Util.EnvironmentTickCount();
1507 ++Frame; 1547 ++Frame;
@@ -2218,10 +2258,14 @@ namespace OpenSim.Region.Framework.Scenes
2218 public bool AddRestoredSceneObject( 2258 public bool AddRestoredSceneObject(
2219 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 2259 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
2220 { 2260 {
2221 bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); 2261 if (m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates))
2222 if (result) 2262 {
2223 sceneObject.IsDeleted = false; 2263 sceneObject.IsDeleted = false;
2224 return result; 2264 EventManager.TriggerObjectAddedToScene(sceneObject);
2265 return true;
2266 }
2267
2268 return false;
2225 } 2269 }
2226 2270
2227 /// <summary> 2271 /// <summary>
@@ -2862,77 +2906,89 @@ namespace OpenSim.Region.Framework.Scenes
2862 2906
2863 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) 2907 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
2864 { 2908 {
2909 ScenePresence sp;
2910 bool vialogin;
2911
2865 // Validation occurs in LLUDPServer 2912 // Validation occurs in LLUDPServer
2913 //
2914 // XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with
2915 // each other. In practice, this does not currently occur in the code.
2866 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); 2916 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
2867 2917
2868 bool vialogin 2918 // We lock here on AgentCircuitData to prevent a race condition between the thread adding a new connection
2869 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 2919 // and a simultaneous one that removes it (as can happen if the client is closed at a particular point
2870 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; 2920 // whilst connecting).
2871 2921 //
2872 CheckHeartbeat(); 2922 // It would be easier to lock across all NewUserConnection(), AddNewClient() and
2873 2923 // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
2874 ScenePresence sp = GetScenePresence(client.AgentId); 2924 // response in some module listening to AddNewClient()) from holding up unrelated agent calls.
2875 2925 //
2876 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this 2926 // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
2877 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause 2927 // AddNewClient() operations (though not other ops).
2878 // other problems, and possible the code calling AddNewClient() should ensure that no client is already 2928 // In the future this can be relieved once locking per agent (not necessarily on AgentCircuitData) is improved.
2879 // connected. 2929 lock (aCircuit)
2880 if (sp == null) 2930 {
2881 { 2931 vialogin
2882 m_log.DebugFormat( 2932 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
2883 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}", 2933 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2884 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos); 2934
2885 2935 CheckHeartbeat();
2886 m_clientManager.Add(client); 2936
2887 SubscribeToClientEvents(client); 2937 sp = GetScenePresence(client.AgentId);
2888
2889 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2890 m_eventManager.TriggerOnNewPresence(sp);
2891
2892 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2893 2938
2894 // The first agent upon login is a root agent by design. 2939 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
2895 // For this agent we will have to rez the attachments. 2940 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
2896 // All other AddNewClient calls find aCircuit.child to be true. 2941 // other problems, and possible the code calling AddNewClient() should ensure that no client is already
2897 if (aCircuit.child == false) 2942 // connected.
2943 if (sp == null)
2898 { 2944 {
2899 // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to 2945 m_log.DebugFormat(
2900 // start the scripts again (since this is done in RezAttachments()). 2946 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
2901 // XXX: This is convoluted. 2947 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
2902 sp.IsChildAgent = false; 2948
2903 2949 m_clientManager.Add(client);
2904 if (AttachmentsModule != null) 2950 SubscribeToClientEvents(client);
2905 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); 2951
2952 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2953 m_eventManager.TriggerOnNewPresence(sp);
2954
2955 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2956
2957 // The first agent upon login is a root agent by design.
2958 // For this agent we will have to rez the attachments.
2959 // All other AddNewClient calls find aCircuit.child to be true.
2960 if (aCircuit.child == false)
2961 {
2962 // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
2963 // start the scripts again (since this is done in RezAttachments()).
2964 // XXX: This is convoluted.
2965 sp.IsChildAgent = false;
2966
2967 if (AttachmentsModule != null)
2968 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
2969 }
2906 } 2970 }
2907 } 2971 else
2908 else 2972 {
2909 { 2973 m_log.WarnFormat(
2910 m_log.WarnFormat( 2974 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
2911 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence", 2975 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
2912 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName); 2976 }
2913 } 2977
2978 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2979 // client is for a root or child agent.
2980 client.SceneAgent = sp;
2914 2981
2915 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the 2982 // Cache the user's name
2916 // client is for a root or child agent. 2983 CacheUserName(sp, aCircuit);
2917 client.SceneAgent = sp; 2984
2985 EventManager.TriggerOnNewClient(client);
2986 if (vialogin)
2987 EventManager.TriggerOnClientLogin(client);
2988 }
2918 2989
2919 m_LastLogin = Util.EnvironmentTickCount(); 2990 m_LastLogin = Util.EnvironmentTickCount();
2920 2991
2921 // Cache the user's name
2922 CacheUserName(sp, aCircuit);
2923
2924 EventManager.TriggerOnNewClient(client);
2925 if (vialogin)
2926 {
2927 EventManager.TriggerOnClientLogin(client);
2928 // Send initial parcel data
2929/* this is done on TriggerOnNewClient by landmanegement respective event handler
2930 Vector3 pos = sp.AbsolutePosition;
2931 ILandObject land = LandChannel.GetLandObject(pos.X, pos.Y);
2932 land.SendLandUpdateToClient(client);
2933*/
2934 }
2935
2936 return sp; 2992 return sp;
2937 } 2993 }
2938 2994
@@ -3472,110 +3528,130 @@ namespace OpenSim.Region.Framework.Scenes
3472 { 3528 {
3473// CheckHeartbeat(); 3529// CheckHeartbeat();
3474 bool isChildAgent = false; 3530 bool isChildAgent = false;
3475 ScenePresence avatar = GetScenePresence(agentID); 3531 AgentCircuitData acd;
3476
3477 if (avatar == null)
3478 {
3479 m_log.WarnFormat(
3480 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3481 3532
3482 return; 3533 lock (m_removeClientLock)
3483 }
3484
3485 try
3486 { 3534 {
3487 isChildAgent = avatar.IsChildAgent; 3535 acd = m_authenticateHandler.GetAgentCircuitData(agentID);
3488 3536
3489 m_log.DebugFormat( 3537 if (acd == null)
3490 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3491 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
3492
3493 // Don't do this to root agents, it's not nice for the viewer
3494 if (closeChildAgents && isChildAgent)
3495 { 3538 {
3496 // Tell a single agent to disconnect from the region. 3539 m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
3497 IEventQueue eq = RequestModuleInterface<IEventQueue>(); 3540 return;
3498 if (eq != null)
3499 {
3500 eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
3501 }
3502 else
3503 {
3504 avatar.ControllingClient.SendShutdownConnectionNotice();
3505 }
3506 } 3541 }
3507 3542 else
3508 // Only applies to root agents.
3509 if (avatar.ParentID != 0)
3510 { 3543 {
3511 avatar.StandUp(); 3544 // We remove the acd up here to avoid later raec conditions if two RemoveClient() calls occurred
3545 // simultaneously.
3546 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3512 } 3547 }
3548 }
3513 3549
3514 m_sceneGraph.removeUserCount(!isChildAgent); 3550 lock (acd)
3515 3551 {
3516 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop 3552 ScenePresence avatar = GetScenePresence(agentID);
3517 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI 3553
3518 if (closeChildAgents && CapsModule != null) 3554 if (avatar == null)
3519 CapsModule.RemoveCaps(agentID);
3520
3521 // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3522 // this method is doing is HORRIBLE!!!
3523 avatar.Scene.NeedSceneCacheClear(avatar.UUID);
3524
3525 if (closeChildAgents && !isChildAgent)
3526 { 3555 {
3527 List<ulong> regions = avatar.KnownRegionHandles; 3556 m_log.WarnFormat(
3528 regions.Remove(RegionInfo.RegionHandle); 3557 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3529 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3558
3559 return;
3530 } 3560 }
3531 3561
3532 m_eventManager.TriggerClientClosed(agentID, this); 3562 try
3533 m_eventManager.TriggerOnRemovePresence(agentID);
3534
3535 if (!isChildAgent)
3536 { 3563 {
3537 if (AttachmentsModule != null) 3564 isChildAgent = avatar.IsChildAgent;
3565
3566 m_log.DebugFormat(
3567 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3568 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
3569
3570 // Don't do this to root agents, it's not nice for the viewer
3571 if (closeChildAgents && isChildAgent)
3538 { 3572 {
3539 AttachmentsModule.DeRezAttachments(avatar); 3573 // Tell a single agent to disconnect from the region.
3574 IEventQueue eq = RequestModuleInterface<IEventQueue>();
3575 if (eq != null)
3576 {
3577 eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
3578 }
3579 else
3580 {
3581 avatar.ControllingClient.SendShutdownConnectionNotice();
3582 }
3540 } 3583 }
3541 3584
3542 ForEachClient( 3585 // Only applies to root agents.
3543 delegate(IClientAPI client) 3586 if (avatar.ParentID != 0)
3587 {
3588 avatar.StandUp();
3589 }
3590
3591 m_sceneGraph.removeUserCount(!isChildAgent);
3592
3593 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
3594 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
3595 if (closeChildAgents && CapsModule != null)
3596 CapsModule.RemoveCaps(agentID);
3597
3598 // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3599 // this method is doing is HORRIBLE!!!
3600 avatar.Scene.NeedSceneCacheClear(avatar.UUID);
3601
3602 if (closeChildAgents && !isChildAgent)
3603 {
3604 List<ulong> regions = avatar.KnownRegionHandles;
3605 regions.Remove(RegionInfo.RegionHandle);
3606 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3607 }
3608
3609 m_eventManager.TriggerClientClosed(agentID, this);
3610 m_eventManager.TriggerOnRemovePresence(agentID);
3611
3612 if (!isChildAgent)
3613 {
3614 if (AttachmentsModule != null)
3544 { 3615 {
3545 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway 3616 AttachmentsModule.DeRezAttachments(avatar);
3546 try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } 3617 }
3547 catch (NullReferenceException) { }
3548 });
3549 }
3550
3551 // It's possible for child agents to have transactions if changes are being made cross-border.
3552 if (AgentTransactionsModule != null)
3553 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3554 3618
3555 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3619 ForEachClient(
3556 m_log.Debug("[Scene] The avatar has left the building"); 3620 delegate(IClientAPI client)
3557 } 3621 {
3558 catch (Exception e) 3622 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3559 { 3623 try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); }
3560 m_log.Error( 3624 catch (NullReferenceException) { }
3561 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e); 3625 });
3562 } 3626 }
3563 finally
3564 {
3565 try
3566 {
3567 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3568 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3569 // the same cleanup exception continually.
3570 m_sceneGraph.RemoveScenePresence(agentID);
3571 m_clientManager.Remove(agentID);
3572 3627
3573 avatar.Close(); 3628 // It's possible for child agents to have transactions if changes are being made cross-border.
3629 if (AgentTransactionsModule != null)
3630 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3631 m_log.Debug("[Scene] The avatar has left the building");
3574 } 3632 }
3575 catch (Exception e) 3633 catch (Exception e)
3576 { 3634 {
3577 m_log.Error( 3635 m_log.Error(
3578 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e); 3636 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
3637 }
3638 finally
3639 {
3640 try
3641 {
3642 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3643 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3644 // the same cleanup exception continually.
3645 m_sceneGraph.RemoveScenePresence(agentID);
3646 m_clientManager.Remove(agentID);
3647
3648 avatar.Close();
3649 }
3650 catch (Exception e)
3651 {
3652 m_log.Error(
3653 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
3654 }
3579 } 3655 }
3580 } 3656 }
3581 3657
@@ -3634,11 +3710,9 @@ namespace OpenSim.Region.Framework.Scenes
3634 3710
3635 /// <summary> 3711 /// <summary>
3636 /// Do the work necessary to initiate a new user connection for a particular scene. 3712 /// Do the work necessary to initiate a new user connection for a particular scene.
3637 /// At the moment, this consists of setting up the caps infrastructure
3638 /// The return bool should allow for connections to be refused, but as not all calling paths
3639 /// take proper notice of it let, we allowed banned users in still.
3640 /// </summary> 3713 /// </summary>
3641 /// <param name="agent">CircuitData of the agent who is connecting</param> 3714 /// <param name="agent">CircuitData of the agent who is connecting</param>
3715 /// <param name="teleportFlags"></param>
3642 /// <param name="reason">Outputs the reason for the false response on this string</param> 3716 /// <param name="reason">Outputs the reason for the false response on this string</param>
3643 /// <returns>True if the region accepts this agent. False if it does not. False will 3717 /// <returns>True if the region accepts this agent. False if it does not. False will
3644 /// also return a reason.</returns> 3718 /// also return a reason.</returns>
@@ -3649,10 +3723,20 @@ namespace OpenSim.Region.Framework.Scenes
3649 3723
3650 /// <summary> 3724 /// <summary>
3651 /// Do the work necessary to initiate a new user connection for a particular scene. 3725 /// Do the work necessary to initiate a new user connection for a particular scene.
3652 /// At the moment, this consists of setting up the caps infrastructure 3726 /// </summary>
3727 /// <remarks>
3728 /// The return bool should allow for connections to be refused, but as not all calling paths
3729 /// take proper notice of it yet, we still allowed banned users in.
3730 ///
3731 /// At the moment this method consists of setting up the caps infrastructure
3653 /// The return bool should allow for connections to be refused, but as not all calling paths 3732 /// The return bool should allow for connections to be refused, but as not all calling paths
3654 /// take proper notice of it let, we allowed banned users in still. 3733 /// take proper notice of it let, we allowed banned users in still.
3655 /// </summary> 3734 ///
3735 /// This method is called by the login service (in the case of login) or another simulator (in the case of region
3736 /// cross or teleport) to initiate the connection. It is not triggered by the viewer itself - the connection
3737 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
3738 /// the LLUDP stack).
3739 /// </remarks>
3656 /// <param name="agent">CircuitData of the agent who is connecting</param> 3740 /// <param name="agent">CircuitData of the agent who is connecting</param>
3657 /// <param name="reason">Outputs the reason for the false response on this string</param> 3741 /// <param name="reason">Outputs the reason for the false response on this string</param>
3658 /// <param name="requirePresenceLookup">True for normal presence. False for NPC 3742 /// <param name="requirePresenceLookup">True for normal presence. False for NPC
@@ -3755,79 +3839,82 @@ namespace OpenSim.Region.Framework.Scenes
3755 sp = null; 3839 sp = null;
3756 } 3840 }
3757 3841
3758 3842 lock (agent)
3759 //On login test land permisions
3760 if (vialogin)
3761 { 3843 {
3762 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>(); 3844 //On login test land permisions
3763 if (cache != null) 3845 if (vialogin)
3764 cache.Remove(agent.firstname + " " + agent.lastname);
3765 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3766 { 3846 {
3767 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString()); 3847 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
3768 return false; 3848 if (cache != null)
3849 cache.Remove(agent.firstname + " " + agent.lastname);
3850 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3851 {
3852 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
3853 return false;
3854 }
3769 } 3855 }
3770 }
3771 3856
3772 if (sp == null) // We don't have an [child] agent here already 3857 if (sp == null) // We don't have an [child] agent here already
3773 {
3774 if (requirePresenceLookup)
3775 { 3858 {
3776 try 3859 if (requirePresenceLookup)
3777 { 3860 {
3778 if (!VerifyUserPresence(agent, out reason)) 3861 try
3862 {
3863 if (!VerifyUserPresence(agent, out reason))
3864 return false;
3865 } catch (Exception e)
3866 {
3867 m_log.ErrorFormat(
3868 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3779 return false; 3869 return false;
3780 } catch (Exception e) 3870 }
3871 }
3872
3873 try
3874 {
3875 // Always check estate if this is a login. Always
3876 // check if banned regions are to be blacked out.
3877 if (vialogin || (!m_seeIntoBannedRegion))
3878 {
3879 if (!AuthorizeUser(agent, out reason))
3880 return false;
3881 }
3882 }
3883 catch (Exception e)
3781 { 3884 {
3782 m_log.ErrorFormat( 3885 m_log.ErrorFormat(
3783 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); 3886 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3784 return false; 3887 return false;
3785 } 3888 }
3786 }
3787 3889
3788 try 3890 m_log.InfoFormat(
3789 { 3891 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3790 // Always check estate if this is a login. Always 3892 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
3791 // check if banned regions are to be blacked out. 3893 agent.AgentID, agent.circuitcode);
3792 if (vialogin || (!m_seeIntoBannedRegion)) 3894
3895 if (CapsModule != null)
3793 { 3896 {
3794 if (!AuthorizeUser(agent, out reason)) 3897 CapsModule.SetAgentCapsSeeds(agent);
3795 return false; 3898 CapsModule.CreateCaps(agent.AgentID);
3796 } 3899 }
3797 } 3900 }
3798 catch (Exception e) 3901 else
3799 { 3902 {
3800 m_log.ErrorFormat( 3903 // Let the SP know how we got here. This has a lot of interesting
3801 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); 3904 // uses down the line.
3802 return false; 3905 sp.TeleportFlags = (TPFlags)teleportFlags;
3803 }
3804
3805 m_log.InfoFormat(
3806 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3807 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
3808 agent.AgentID, agent.circuitcode);
3809 3906
3810 if (CapsModule != null) 3907 if (sp.IsChildAgent)
3811 { 3908 {
3812 CapsModule.SetAgentCapsSeeds(agent); 3909 m_log.DebugFormat(
3813 CapsModule.CreateCaps(agent.AgentID); 3910 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3814 } 3911 agent.AgentID, RegionInfo.RegionName);
3815 } else
3816 {
3817 // Let the SP know how we got here. This has a lot of interesting
3818 // uses down the line.
3819 sp.TeleportFlags = (TPFlags)teleportFlags;
3820 3912
3821 if (sp.IsChildAgent) 3913 sp.AdjustKnownSeeds();
3822 {
3823 m_log.DebugFormat(
3824 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3825 agent.AgentID, RegionInfo.RegionName);
3826 3914
3827 sp.AdjustKnownSeeds(); 3915 if (CapsModule != null)
3828 3916 CapsModule.SetAgentCapsSeeds(agent);
3829 if (CapsModule != null) 3917 }
3830 CapsModule.SetAgentCapsSeeds(agent);
3831 } 3918 }
3832 } 3919 }
3833 3920
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index a31a9ea..d5d8f26 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -3082,7 +3082,7 @@ namespace OpenSim.Region.Framework.Scenes
3082 // UUID, Name, TimeStampFull); 3082 // UUID, Name, TimeStampFull);
3083 3083
3084 if (ParentGroup.Scene != null) 3084 if (ParentGroup.Scene != null)
3085 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this); 3085 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, true);
3086 } 3086 }
3087 3087
3088 /// <summary> 3088 /// <summary>
@@ -3116,7 +3116,7 @@ namespace OpenSim.Region.Framework.Scenes
3116 } 3116 }
3117 3117
3118 if (ParentGroup.Scene != null) 3118 if (ParentGroup.Scene != null)
3119 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this); 3119 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, false);
3120 } 3120 }
3121 3121
3122 public void ScriptSetPhysicsStatus(bool UsePhysics) 3122 public void ScriptSetPhysicsStatus(bool UsePhysics)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 2a52e01..2e6b2da 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -263,7 +263,7 @@ public class BSCharacter : BSPhysObject
263 // A version of the sanity check that also makes sure a new position value is 263 // A version of the sanity check that also makes sure a new position value is
264 // pushed back to the physics engine. This routine would be used by anyone 264 // pushed back to the physics engine. This routine would be used by anyone
265 // who is not already pushing the value. 265 // who is not already pushing the value.
266 private bool PositionSanityCheck2(bool atTaintTime) 266 private bool PositionSanityCheck2(bool inTaintTime)
267 { 267 {
268 bool ret = false; 268 bool ret = false;
269 if (PositionSanityCheck()) 269 if (PositionSanityCheck())
@@ -275,7 +275,7 @@ public class BSCharacter : BSPhysObject
275 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 275 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 276 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
277 }; 277 };
278 if (atTaintTime) 278 if (inTaintTime)
279 sanityOperation(); 279 sanityOperation();
280 else 280 else
281 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation); 281 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
@@ -332,6 +332,13 @@ public class BSCharacter : BSPhysObject
332 }); 332 });
333 } 333 }
334 } 334 }
335 public override OMV.Vector3 ForceVelocity {
336 get { return _velocity; }
337 set {
338 _velocity = value;
339 BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
340 }
341 }
335 public override OMV.Vector3 Torque { 342 public override OMV.Vector3 Torque {
336 get { return _torque; } 343 get { return _torque; }
337 set { _torque = value; 344 set { _torque = value;
@@ -432,6 +439,10 @@ public class BSCharacter : BSPhysObject
432 get { return _rotationalVelocity; } 439 get { return _rotationalVelocity; }
433 set { _rotationalVelocity = value; } 440 set { _rotationalVelocity = value; }
434 } 441 }
442 public override OMV.Vector3 ForceRotationalVelocity {
443 get { return _rotationalVelocity; }
444 set { _rotationalVelocity = value; }
445 }
435 public override bool Kinematic { 446 public override bool Kinematic {
436 get { return _kinematic; } 447 get { return _kinematic; }
437 set { _kinematic = value; } 448 set { _kinematic = value; }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 63a4127..a20be3a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -49,9 +49,16 @@ public abstract class BSConstraint : IDisposable
49 if (m_enabled) 49 if (m_enabled)
50 { 50 {
51 m_enabled = false; 51 m_enabled = false;
52 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 52 if (m_constraint.ptr != IntPtr.Zero)
53 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); 53 {
54 m_constraint.ptr = System.IntPtr.Zero; 54 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
55 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
56 BSScene.DetailLogZero,
57 m_body1.ID, m_body1.ptr.ToString("X"),
58 m_body2.ID, m_body2.ptr.ToString("X"),
59 success);
60 m_constraint.ptr = System.IntPtr.Zero;
61 }
55 } 62 }
56 } 63 }
57 64
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 4ba2f62..56342b8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -462,7 +462,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
462 return; 462 return;
463 463
464 // Set the prim's inertia to zero. The vehicle code handles that and this 464 // Set the prim's inertia to zero. The vehicle code handles that and this
465 // removes the torque action introduced by Bullet. 465 // removes the motion and torque actions introduced by Bullet.
466 Vector3 inertia = Vector3.Zero; 466 Vector3 inertia = Vector3.Zero;
467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); 467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); 468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
@@ -481,7 +481,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
481 m_lastPositionVector = Prim.ForcePosition; 481 m_lastPositionVector = Prim.ForcePosition;
482 482
483 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 483 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
484 Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity); 484 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
485 }// end Step 485 }// end Step
486 486
487 // Apply the effect of the linear motor. 487 // Apply the effect of the linear motor.
@@ -540,7 +540,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
540 // add Gravity and Buoyancy 540 // add Gravity and Buoyancy
541 // There is some gravity, make a gravity force vector that is applied after object velocity. 541 // There is some gravity, make a gravity force vector that is applied after object velocity.
542 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 542 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
543 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy)); 543 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy));
544 544
545 /* 545 /*
546 * RA: Not sure why one would do this 546 * RA: Not sure why one would do this
@@ -678,10 +678,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
678 m_newVelocity.Z = 0; 678 m_newVelocity.Z = 0;
679 679
680 // Apply velocity 680 // Apply velocity
681 Prim.Velocity = m_newVelocity; 681 Prim.ForceVelocity = m_newVelocity;
682 // apply gravity force 682 // apply gravity force
683 // Why is this set here? The physics engine already does gravity. 683 // Why is this set here? The physics engine already does gravity.
684 // m_prim.AddForce(grav, false); 684 Prim.AddForce(grav, false, true);
685 685
686 // Apply friction 686 // Apply friction
687 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); 687 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep));
@@ -704,7 +704,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
704 // m_lastAngularVelocity // what was last applied to body 704 // m_lastAngularVelocity // what was last applied to body
705 705
706 // Get what the body is doing, this includes 'external' influences 706 // Get what the body is doing, this includes 'external' influences
707 Vector3 angularVelocity = Prim.RotationalVelocity; 707 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
708 708
709 if (m_angularMotorApply > 0) 709 if (m_angularMotorApply > 0)
710 { 710 {
@@ -810,7 +810,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
810 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; 810 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
811 811
812 // Apply to the body 812 // Apply to the body
813 Prim.RotationalVelocity = m_lastAngularVelocity; 813 Prim.ForceRotationalVelocity = m_lastAngularVelocity;
814 814
815 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity); 815 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
816 } //end MoveAngular 816 } //end MoveAngular
@@ -862,7 +862,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
862 private void VDetailLog(string msg, params Object[] args) 862 private void VDetailLog(string msg, params Object[] args)
863 { 863 {
864 if (Prim.PhysicsScene.VehicleLoggingEnabled) 864 if (Prim.PhysicsScene.VehicleLoggingEnabled)
865 Prim.PhysicsScene.PhysicsLogging.Write(msg, args); 865 Prim.PhysicsScene.DetailLog(msg, args);
866 } 866 }
867 } 867 }
868} 868}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 3e82642..43b1262 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -52,8 +52,8 @@ public class BSLinkset
52 // the physical 'taint' children separately. 52 // the physical 'taint' children separately.
53 // After taint processing and before the simulation step, these 53 // After taint processing and before the simulation step, these
54 // two lists must be the same. 54 // two lists must be the same.
55 private List<BSPhysObject> m_children; 55 private HashSet<BSPhysObject> m_children;
56 private List<BSPhysObject> m_taintChildren; 56 private HashSet<BSPhysObject> m_taintChildren;
57 57
58 // We lock the diddling of linkset classes to prevent any badness. 58 // We lock the diddling of linkset classes to prevent any badness.
59 // This locks the modification of the instances of this class. Changes 59 // This locks the modification of the instances of this class. Changes
@@ -90,8 +90,8 @@ public class BSLinkset
90 m_nextLinksetID = 1; 90 m_nextLinksetID = 1;
91 PhysicsScene = scene; 91 PhysicsScene = scene;
92 LinksetRoot = parent; 92 LinksetRoot = parent;
93 m_children = new List<BSPhysObject>(); 93 m_children = new HashSet<BSPhysObject>();
94 m_taintChildren = new List<BSPhysObject>(); 94 m_taintChildren = new HashSet<BSPhysObject>();
95 m_mass = parent.MassRaw; 95 m_mass = parent.MassRaw;
96 } 96 }
97 97
@@ -160,6 +160,28 @@ public class BSLinkset
160 return ret; 160 return ret;
161 } 161 }
162 162
163 // When physical properties are changed the linkset needs to recalculate
164 // its internal properties.
165 // May be called at runtime or taint-time (just pass the appropriate flag).
166 public void Refresh(BSPhysObject requestor, bool inTaintTime)
167 {
168 // If there are no children, not physical or not root, I am not the one that recomputes the constraints
169 // (For the moment, static linksets do create constraints so remove the test for physical.)
170 if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
171 return;
172
173 BSScene.TaintCallback refreshOperation = delegate()
174 {
175 RecomputeLinksetConstraintVariables();
176 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
177 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
178 };
179 if (inTaintTime)
180 refreshOperation();
181 else
182 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
183 }
184
163 // The object is going dynamic (physical). Do any setup necessary 185 // The object is going dynamic (physical). Do any setup necessary
164 // for a dynamic linkset. 186 // for a dynamic linkset.
165 // Only the state of the passed object can be modified. The rest of the linkset 187 // Only the state of the passed object can be modified. The rest of the linkset
@@ -182,22 +204,19 @@ public class BSLinkset
182 return false; 204 return false;
183 } 205 }
184 206
185 // When physical properties are changed the linkset needs to recalculate 207 // If the software is handling the movement of all the objects in a linkset
186 // its internal properties. 208 // (like if one doesn't use constraints for static linksets), this is called
187 // Called at runtime. 209 // when an update for the root of the linkset is received.
188 public void Refresh(BSPhysObject requestor) 210 // Called at taint-time!!
211 public void UpdateProperties(BSPhysObject physObject)
189 { 212 {
190 // If there are no children, there can't be any constraints to recompute 213 // The root local properties have been updated. Apply to the children if appropriate.
191 if (!HasAnyChildren) 214 if (IsRoot(physObject) && HasAnyChildren)
192 return;
193
194 // Only the root does the recomputation
195 if (IsRoot(requestor))
196 { 215 {
197 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() 216 if (!physObject.IsPhysical)
198 { 217 {
199 RecomputeLinksetConstraintVariables(); 218 // TODO: implement software linkset update for static object linksets
200 }); 219 }
201 } 220 }
202 } 221 }
203 222
@@ -215,13 +234,10 @@ public class BSLinkset
215 if (IsRoot(child)) 234 if (IsRoot(child))
216 { 235 {
217 // If the one with the dependency is root, must undo all children 236 // If the one with the dependency is root, must undo all children
218 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}", 237 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
219 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); 238 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
220 foreach (BSPhysObject bpo in m_taintChildren) 239
221 { 240 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
222 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
223 ret = true;
224 }
225 } 241 }
226 else 242 else
227 { 243 {
@@ -229,20 +245,16 @@ public class BSLinkset
229 child.LocalID, 245 child.LocalID,
230 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), 246 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
231 child.LocalID, child.BSBody.ptr.ToString("X")); 247 child.LocalID, child.BSBody.ptr.ToString("X"));
232 // Remove the dependency on the body of this one 248 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
233 if (m_taintChildren.Contains(child)) 249 // Despite the function name, this removes any link to the specified object.
234 { 250 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
235 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
236 ret = true;
237 }
238 } 251 }
239 } 252 }
240 return ret; 253 return ret;
241 } 254 }
242 255
243 // Routine used when rebuilding the body of the root of the linkset 256 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
244 // This is called after RemoveAllLinksToRoot() to restore all the constraints. 257 // this routine will restore the removed constraints.
245 // This is called when the root body has been changed.
246 // Called at taint-time!! 258 // Called at taint-time!!
247 public void RestoreBodyDependencies(BSPrim child) 259 public void RestoreBodyDependencies(BSPrim child)
248 { 260 {
@@ -254,7 +266,7 @@ public class BSLinkset
254 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); 266 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
255 foreach (BSPhysObject bpo in m_taintChildren) 267 foreach (BSPhysObject bpo in m_taintChildren)
256 { 268 {
257 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody); 269 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
258 } 270 }
259 } 271 }
260 else 272 else
@@ -263,7 +275,7 @@ public class BSLinkset
263 LinksetRoot.LocalID, 275 LinksetRoot.LocalID,
264 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), 276 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
265 child.LocalID, child.BSBody.ptr.ToString("X")); 277 child.LocalID, child.BSBody.ptr.ToString("X"));
266 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody); 278 PhysicallyLinkAChildToRoot(LinksetRoot, child);
267 } 279 }
268 } 280 }
269 } 281 }
@@ -330,22 +342,22 @@ public class BSLinkset
330 { 342 {
331 m_children.Add(child); 343 m_children.Add(child);
332 344
333 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now 345 BSPhysObject rootx = LinksetRoot; // capture the root as of now
334 BSPhysObject childx = child; 346 BSPhysObject childx = child;
335 347
336 DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 348 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
337 rootx.LocalID,
338 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
339 childx.LocalID, childx.BSBody.ptr.ToString("X"));
340 349
341 PhysicsScene.TaintedObject("AddChildToLinkset", delegate() 350 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
342 { 351 {
343 DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); 352 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
344 // build the physical binding between me and the child 353 rootx.LocalID,
345 m_taintChildren.Add(childx); 354 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
346 355 childx.LocalID, childx.BSBody.ptr.ToString("X"));
347 // Since this is taint-time, the body and shape could have changed for the child 356 // Since this is taint-time, the body and shape could have changed for the child
348 PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody); 357 rootx.ForcePosition = rootx.Position; // DEBUG
358 childx.ForcePosition = childx.Position; // DEBUG
359 PhysicallyLinkAChildToRoot(rootx, childx);
360 m_taintChildren.Add(child);
349 }); 361 });
350 } 362 }
351 return; 363 return;
@@ -378,10 +390,8 @@ public class BSLinkset
378 390
379 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() 391 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
380 { 392 {
381 if (m_taintChildren.Contains(childx)) 393 m_taintChildren.Remove(child);
382 m_taintChildren.Remove(childx); 394 PhysicallyUnlinkAChildFromRoot(rootx, childx);
383
384 PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody);
385 RecomputeLinksetConstraintVariables(); 395 RecomputeLinksetConstraintVariables();
386 }); 396 });
387 397
@@ -396,8 +406,7 @@ public class BSLinkset
396 406
397 // Create a constraint between me (root of linkset) and the passed prim (the child). 407 // Create a constraint between me (root of linkset) and the passed prim (the child).
398 // Called at taint time! 408 // Called at taint time!
399 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody, 409 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
400 BSPhysObject childPrim, BulletBody childBody)
401 { 410 {
402 // Zero motion for children so they don't interpolate 411 // Zero motion for children so they don't interpolate
403 childPrim.ZeroMotion(); 412 childPrim.ZeroMotion();
@@ -409,33 +418,17 @@ public class BSLinkset
409 // real world coordinate of midpoint between the two objects 418 // real world coordinate of midpoint between the two objects
410 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 419 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
411 420
412 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", 421 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
413 rootPrim.LocalID, 422 rootPrim.LocalID,
414 rootPrim.LocalID, rootBody.ptr.ToString("X"), 423 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
415 childPrim.LocalID, childBody.ptr.ToString("X"), 424 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
416 rootPrim.Position, childPrim.Position, midPoint); 425 rootPrim.Position, childPrim.Position, midPoint);
417 426
418 // create a constraint that allows no freedom of movement between the two objects 427 // create a constraint that allows no freedom of movement between the two objects
419 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 428 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
420 429
421 // There is great subtlty in these paramters. Notice the check for a ptr of zero.
422 // We pass the BulletBody structure into the taint in order to capture the pointer
423 // of the body at the time of constraint creation. This doesn't work for the very first
424 // construction because there is no body yet. The body
425 // is constructed later at taint time. Thus we use the body address at time of the
426 // taint creation but, if it is zero, use what's in the prim at the moment.
427 // There is a possible race condition since shape can change without a taint call
428 // (like changing to a mesh that is already constructed). The fix for that would be
429 // to only change BSShape at taint time thus syncronizing these operations at
430 // the cost of efficiency and lag.
431 BS6DofConstraint constrain = new BS6DofConstraint( 430 BS6DofConstraint constrain = new BS6DofConstraint(
432 PhysicsScene.World, 431 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
433 rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
434 childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
435 midPoint,
436 true,
437 true
438 );
439 432
440 /* NOTE: below is an attempt to build constraint with full frame computation, etc. 433 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
441 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms 434 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
@@ -452,7 +445,7 @@ public class BSLinkset
452 445
453 // create a constraint that allows no freedom of movement between the two objects 446 // create a constraint that allows no freedom of movement between the two objects
454 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 447 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
455 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); 448 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
456 BS6DofConstraint constrain = new BS6DofConstraint( 449 BS6DofConstraint constrain = new BS6DofConstraint(
457 PhysicsScene.World, rootPrim.Body, childPrim.Body, 450 PhysicsScene.World, rootPrim.Body, childPrim.Body,
458 OMV.Vector3.Zero, 451 OMV.Vector3.Zero,
@@ -486,39 +479,44 @@ public class BSLinkset
486 { 479 {
487 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); 480 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
488 } 481 }
489
490 RecomputeLinksetConstraintVariables();
491 } 482 }
492 483
493 // Remove linkage between myself and a particular child 484 // Remove linkage between myself and a particular child
494 // The root and child bodies are passed in because we need to remove the constraint between 485 // The root and child bodies are passed in because we need to remove the constraint between
495 // the bodies that were at unlink time. 486 // the bodies that were at unlink time.
496 // Called at taint time! 487 // Called at taint time!
497 private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody, 488 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
498 BSPhysObject childPrim, BulletBody childBody)
499 { 489 {
500 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", 490 bool ret = false;
491 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
501 rootPrim.LocalID, 492 rootPrim.LocalID,
502 rootPrim.LocalID, rootBody.ptr.ToString("X"), 493 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
503 childPrim.LocalID, childBody.ptr.ToString("X")); 494 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
504 495
505 // Find the constraint for this link and get rid of it from the overall collection and from my list 496 // Find the constraint for this link and get rid of it from the overall collection and from my list
506 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody); 497 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
498 {
499 // Make the child refresh its location
500 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
501 ret = true;
502 }
507 503
508 // Make the child refresh its location 504 return ret;
509 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
510 } 505 }
511 506
512 /*
513 // Remove linkage between myself and any possible children I might have. 507 // Remove linkage between myself and any possible children I might have.
514 // Called at taint time! 508 // Called at taint time!
515 private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) 509 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
516 { 510 {
517 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 511 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
512 bool ret = false;
518 513
519 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); 514 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
515 {
516 ret = true;
517 }
518 return ret;
520 } 519 }
521 */
522 520
523 // Call each of the constraints that make up this linkset and recompute the 521 // Call each of the constraints that make up this linkset and recompute the
524 // various transforms and variables. Used when objects are added or removed 522 // various transforms and variables. Used when objects are added or removed
@@ -550,11 +548,17 @@ public class BSLinkset
550 { 548 {
551 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass 549 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
552 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); 550 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
553 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); 551 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
552 centerOfMass, OMV.Quaternion.Identity);
553 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
554 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
554 foreach (BSPhysObject child in m_taintChildren) 555 foreach (BSPhysObject child in m_taintChildren)
555 { 556 {
556 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); 557 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
558 centerOfMass, OMV.Quaternion.Identity);
557 } 559 }
560
561 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
558 } 562 }
559 return; 563 return;
560 } 564 }
@@ -563,7 +567,8 @@ public class BSLinkset
563 // Invoke the detailed logger and output something if it's enabled. 567 // Invoke the detailed logger and output something if it's enabled.
564 private void DetailLog(string msg, params Object[] args) 568 private void DetailLog(string msg, params Object[] args)
565 { 569 {
566 PhysicsScene.PhysicsLogging.Write(msg, args); 570 if (PhysicsScene.PhysicsLogging.Enabled)
571 PhysicsScene.DetailLog(msg, args);
567 } 572 }
568 573
569} 574}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 1ac8c59..cae599c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -85,6 +85,10 @@ public abstract class BSPhysObject : PhysicsActor
85 85
86 public abstract OMV.Quaternion ForceOrientation { get; set; } 86 public abstract OMV.Quaternion ForceOrientation { get; set; }
87 87
88 public abstract OMV.Vector3 ForceVelocity { get; set; }
89
90 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
91
88 #region Collisions 92 #region Collisions
89 93
90 // Requested number of milliseconds between collision events. Zero means disabled. 94 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -207,7 +211,8 @@ public abstract class BSPhysObject : PhysicsActor
207 // High performance detailed logging routine used by the physical objects. 211 // High performance detailed logging routine used by the physical objects.
208 protected void DetailLog(string msg, params Object[] args) 212 protected void DetailLog(string msg, params Object[] args)
209 { 213 {
210 PhysicsScene.PhysicsLogging.Write(msg, args); 214 if (PhysicsScene.PhysicsLogging.Enabled)
215 PhysicsScene.DetailLog(msg, args);
211 } 216 }
212} 217}
213} 218}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index f7b68ba..6a4365c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -196,7 +196,7 @@ public sealed class BSPrim : BSPhysObject
196 _isSelected = value; 196 _isSelected = value;
197 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 197 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 { 198 {
199 // DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 199 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
200 SetObjectDynamic(false); 200 SetObjectDynamic(false);
201 }); 201 });
202 } 202 }
@@ -265,6 +265,11 @@ public sealed class BSPrim : BSPhysObject
265 return _position; 265 return _position;
266 } 266 }
267 set { 267 set {
268 // If you must push the position into the physics engine, use ForcePosition.
269 if (_position == value)
270 {
271 return;
272 }
268 _position = value; 273 _position = value;
269 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 274 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
270 PositionSanityCheck(); 275 PositionSanityCheck();
@@ -322,7 +327,7 @@ public sealed class BSPrim : BSPhysObject
322 // A version of the sanity check that also makes sure a new position value is 327 // A version of the sanity check that also makes sure a new position value is
323 // pushed back to the physics engine. This routine would be used by anyone 328 // pushed back to the physics engine. This routine would be used by anyone
324 // who is not already pushing the value. 329 // who is not already pushing the value.
325 private bool PositionSanityCheck2(bool atTaintTime) 330 private bool PositionSanityCheck2(bool inTaintTime)
326 { 331 {
327 bool ret = false; 332 bool ret = false;
328 if (PositionSanityCheck()) 333 if (PositionSanityCheck())
@@ -334,7 +339,7 @@ public sealed class BSPrim : BSPhysObject
334 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 339 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 340 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
336 }; 341 };
337 if (atTaintTime) 342 if (inTaintTime)
338 sanityOperation(); 343 sanityOperation();
339 else 344 else
340 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation); 345 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
@@ -453,7 +458,6 @@ public sealed class BSPrim : BSPhysObject
453 } 458 }
454 return; 459 return;
455 } 460 }
456
457 public override OMV.Vector3 Velocity { 461 public override OMV.Vector3 Velocity {
458 get { return _velocity; } 462 get { return _velocity; }
459 set { 463 set {
@@ -465,6 +469,13 @@ public sealed class BSPrim : BSPhysObject
465 }); 469 });
466 } 470 }
467 } 471 }
472 public override OMV.Vector3 ForceVelocity {
473 get { return _velocity; }
474 set {
475 _velocity = value;
476 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
477 }
478 }
468 public override OMV.Vector3 Torque { 479 public override OMV.Vector3 Torque {
469 get { return _torque; } 480 get { return _torque; }
470 set { _torque = value; 481 set { _torque = value;
@@ -490,6 +501,8 @@ public sealed class BSPrim : BSPhysObject
490 return _orientation; 501 return _orientation;
491 } 502 }
492 set { 503 set {
504 if (_orientation == value)
505 return;
493 _orientation = value; 506 _orientation = value;
494 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 507 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
495 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 508 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
@@ -570,7 +583,7 @@ public sealed class BSPrim : BSPhysObject
570 // Set up the object physicalness (does gravity and collisions move this object) 583 // Set up the object physicalness (does gravity and collisions move this object)
571 MakeDynamic(IsStatic); 584 MakeDynamic(IsStatic);
572 585
573 // Update vehicle specific parameters 586 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
574 _vehicle.Refresh(); 587 _vehicle.Refresh();
575 588
576 // Arrange for collision events if the simulator wants them 589 // Arrange for collision events if the simulator wants them
@@ -593,7 +606,7 @@ public sealed class BSPrim : BSPhysObject
593 // Recompute any linkset parameters. 606 // Recompute any linkset parameters.
594 // When going from non-physical to physical, this re-enables the constraints that 607 // When going from non-physical to physical, this re-enables the constraints that
595 // had been automatically disabled when the mass was set to zero. 608 // had been automatically disabled when the mass was set to zero.
596 Linkset.Refresh(this); 609 Linkset.Refresh(this, true);
597 610
598 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 611 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
599 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); 612 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
@@ -620,8 +633,10 @@ public sealed class BSPrim : BSPhysObject
620 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); 633 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
621 // There can be special things needed for implementing linksets 634 // There can be special things needed for implementing linksets
622 Linkset.MakeStatic(this); 635 Linkset.MakeStatic(this);
623 // The activation state is 'disabled' so Bullet will not try to act on it 636 // The activation state is 'disabled' so Bullet will not try to act on it.
624 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); 637 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
638 // Start it out sleeping and physical actions could wake it up.
639 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
625 640
626 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 641 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
627 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 642 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
@@ -638,6 +653,9 @@ public sealed class BSPrim : BSPhysObject
638 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 653 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
639 BulletSimAPI.ClearAllForces2(BSBody.ptr); 654 BulletSimAPI.ClearAllForces2(BSBody.ptr);
640 655
656 // For good measure, make sure the transform is set through to the motion state
657 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
658
641 // A dynamic object has mass 659 // A dynamic object has mass
642 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); 660 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
643 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass); 661 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
@@ -655,8 +673,8 @@ public sealed class BSPrim : BSPhysObject
655 673
656 // Force activation of the object so Bullet will act on it. 674 // Force activation of the object so Bullet will act on it.
657 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 675 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
658 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 676 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
659 BulletSimAPI.Activate2(BSBody.ptr, true); 677 // BulletSimAPI.Activate2(BSBody.ptr, true);
660 678
661 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 679 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
662 BSBody.collisionMask = CollisionFilterGroups.ObjectMask; 680 BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
@@ -774,6 +792,15 @@ public sealed class BSPrim : BSPhysObject
774 }); 792 });
775 } 793 }
776 } 794 }
795 public override OMV.Vector3 ForceRotationalVelocity {
796 get {
797 return _rotationalVelocity;
798 }
799 set {
800 _rotationalVelocity = value;
801 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
802 }
803 }
777 public override bool Kinematic { 804 public override bool Kinematic {
778 get { return _kinematic; } 805 get { return _kinematic; }
779 set { _kinematic = value; 806 set { _kinematic = value;
@@ -828,6 +855,9 @@ public sealed class BSPrim : BSPhysObject
828 855
829 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); 856 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
830 public override void AddForce(OMV.Vector3 force, bool pushforce) { 857 public override void AddForce(OMV.Vector3 force, bool pushforce) {
858 AddForce(force, pushforce, false);
859 }
860 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
831 // for an object, doesn't matter if force is a pushforce or not 861 // for an object, doesn't matter if force is a pushforce or not
832 if (force.IsFinite()) 862 if (force.IsFinite())
833 { 863 {
@@ -840,11 +870,12 @@ public sealed class BSPrim : BSPhysObject
840 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 870 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
841 return; 871 return;
842 } 872 }
843 PhysicsScene.TaintedObject("BSPrim.AddForce", delegate() 873 BSScene.TaintCallback addForceOperation = delegate()
844 { 874 {
845 OMV.Vector3 fSum = OMV.Vector3.Zero; 875 OMV.Vector3 fSum = OMV.Vector3.Zero;
846 lock (m_accumulatedForces) 876 lock (m_accumulatedForces)
847 { 877 {
878 // Sum the accumulated additional forces for one big force to apply once.
848 foreach (OMV.Vector3 v in m_accumulatedForces) 879 foreach (OMV.Vector3 v in m_accumulatedForces)
849 { 880 {
850 fSum += v; 881 fSum += v;
@@ -854,7 +885,11 @@ public sealed class BSPrim : BSPhysObject
854 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); 885 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
855 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. 886 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
856 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); 887 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
857 }); 888 };
889 if (inTaintTime)
890 addForceOperation();
891 else
892 PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
858 } 893 }
859 894
860 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 895 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@@ -1204,6 +1239,7 @@ public sealed class BSPrim : BSPhysObject
1204 { 1239 {
1205 // Called if the current prim body is about to be destroyed. 1240 // Called if the current prim body is about to be destroyed.
1206 // Remove all the physical dependencies on the old body. 1241 // Remove all the physical dependencies on the old body.
1242 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
1207 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1243 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1208 }); 1244 });
1209 1245
@@ -1294,6 +1330,8 @@ public sealed class BSPrim : BSPhysObject
1294 1330
1295 PositionSanityCheck2(true); 1331 PositionSanityCheck2(true);
1296 1332
1333 Linkset.UpdateProperties(this);
1334
1297 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1335 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1298 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1336 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1299 1337
@@ -1304,7 +1342,7 @@ public sealed class BSPrim : BSPhysObject
1304 /* 1342 /*
1305 else 1343 else
1306 { 1344 {
1307 // For debugging, we can also report the movement of children 1345 // For debugging, report the movement of children
1308 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1346 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1309 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1347 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1310 entprop.Acceleration, entprop.RotationalVelocity); 1348 entprop.Acceleration, entprop.RotationalVelocity);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index aaed7de..2c3c481 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,7 +39,6 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Move all logic out of the C++ code and into the C# code for easier future modifications.
43// Test sculpties (verified that they don't work) 42// Test sculpties (verified that they don't work)
44// Compute physics FPS reasonably 43// Compute physics FPS reasonably
45// Based on material, set density and friction 44// Based on material, set density and friction
@@ -90,10 +89,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
90 // let my minuions use my logger 89 // let my minuions use my logger
91 public ILog Logger { get { return m_log; } } 90 public ILog Logger { get { return m_log; } }
92 91
93 // If non-zero, the number of simulation steps between calls to the physics
94 // engine to output detailed physics stats. Debug logging level must be on also.
95 private int m_detailedStatsStep = 0;
96
97 public IMesher mesher; 92 public IMesher mesher;
98 // Level of Detail values kept as float because that's what the Meshmerizer wants 93 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD { get; private set; } 94 public float MeshLOD { get; private set; }
@@ -112,6 +107,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
112 private float m_fixedTimeStep; 107 private float m_fixedTimeStep;
113 private long m_simulationStep = 0; 108 private long m_simulationStep = 0;
114 public long SimulationStep { get { return m_simulationStep; } } 109 public long SimulationStep { get { return m_simulationStep; } }
110 private int m_taintsToProcessPerStep;
115 111
116 // A value of the time now so all the collision and update routines do not have to get their own 112 // A value of the time now so all the collision and update routines do not have to get their own
117 // Set to 'now' just before all the prims and actors are called for collisions and updates 113 // Set to 'now' just before all the prims and actors are called for collisions and updates
@@ -131,6 +127,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
131 127
132 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed 128 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
133 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes 129 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
130 public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
134 131
135 public float PID_D { get; private set; } // derivative 132 public float PID_D { get; private set; } // derivative
136 public float PID_P { get; private set; } // proportional 133 public float PID_P { get; private set; } // proportional
@@ -254,7 +251,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
254 251
255 // The bounding box for the simulated world. The origin is 0,0,0 unless we're 252 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
256 // a child in a mega-region. 253 // a child in a mega-region.
257 // Turns out that Bullet really doesn't care about the extents of the simulated 254 // Bullet actually doesn't care about the extents of the simulated
258 // area. It tracks active objects no matter where they are. 255 // area. It tracks active objects no matter where they are.
259 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 256 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
260 257
@@ -331,7 +328,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
331 // Called directly from unmanaged code so don't do much 328 // Called directly from unmanaged code so don't do much
332 private void BulletLoggerPhysLog(string msg) 329 private void BulletLoggerPhysLog(string msg)
333 { 330 {
334 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 331 DetailLog("[BULLETS UNMANAGED]:" + msg);
335 } 332 }
336 333
337 public override void Dispose() 334 public override void Dispose()
@@ -494,8 +491,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
494 m_simulationStep++; 491 m_simulationStep++;
495 int numSubSteps = 0; 492 int numSubSteps = 0;
496 493
497 // Sometimes needed for debugging to find out what happened before the step 494 // DEBUG
498 // PhysicsLogging.Flush(); 495 // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
499 496
500 try 497 try
501 { 498 {
@@ -505,8 +502,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
505 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 502 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
506 503
507 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 504 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
508 DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}", 505 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
509 DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 506 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
510 } 507 }
511 catch (Exception e) 508 catch (Exception e)
512 { 509 {
@@ -582,19 +579,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
582 } 579 }
583 } 580 }
584 581
585 // If enabled, call into the physics engine to dump statistics
586 if (m_detailedStatsStep > 0)
587 {
588 if ((m_simulationStep % m_detailedStatsStep) == 0)
589 {
590 BulletSimAPI.DumpBulletStatistics();
591 }
592 }
593
594 // The physics engine returns the number of milliseconds it simulated this call. 582 // The physics engine returns the number of milliseconds it simulated this call.
595 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 583 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
596 // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS. 584 // We multiply by 45 to give a recognizable running rate (45 or less).
597 return numSubSteps * m_fixedTimeStep * 1000; 585 return numSubSteps * m_fixedTimeStep * 1000 * 45;
586 // return timeStep * 1000 * 45;
598 } 587 }
599 588
600 // Something has collided 589 // Something has collided
@@ -617,7 +606,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
617 BSPhysObject collidee = null; 606 BSPhysObject collidee = null;
618 PhysObjects.TryGetValue(collidingWith, out collidee); 607 PhysObjects.TryGetValue(collidingWith, out collidee);
619 608
620 DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); 609 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
621 610
622 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 611 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
623 { 612 {
@@ -704,6 +693,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
704 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
705 { 694 {
706 // swizzle a new list into the list location so we can process what's there 695 // swizzle a new list into the list location so we can process what's there
696 int taintCount = m_taintsToProcessPerStep;
697 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
698 while (_taintedObjects.Count > 0 && taintCount-- > 0)
699 {
700 bool gotOne = false;
701 lock (_taintLock)
702 {
703 if (_taintedObjects.Count > 0)
704 {
705 oneCallback = _taintedObjects[0];
706 _taintedObjects.RemoveAt(0);
707 gotOne = true;
708 }
709 }
710 if (gotOne)
711 {
712 try
713 {
714 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
715 oneCallback.callback();
716 }
717 catch (Exception e)
718 {
719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
720 }
721 }
722 }
723 /*
724 // swizzle a new list into the list location so we can process what's there
707 List<TaintCallbackEntry> oldList; 725 List<TaintCallbackEntry> oldList;
708 lock (_taintLock) 726 lock (_taintLock)
709 { 727 {
@@ -715,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
715 { 733 {
716 try 734 try
717 { 735 {
736 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
718 tcbe.callback(); 737 tcbe.callback();
719 } 738 }
720 catch (Exception e) 739 catch (Exception e)
@@ -723,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
723 } 742 }
724 } 743 }
725 oldList.Clear(); 744 oldList.Clear();
745 */
726 } 746 }
727 } 747 }
728 748
@@ -834,6 +854,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
834 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 854 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
835 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, 855 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
836 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), 856 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
857 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
858 ConfigurationParameters.numericTrue,
859 (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
860 (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
861 (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
837 862
838 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 863 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
839 8f, 864 8f,
@@ -876,6 +901,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
876 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, 901 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
877 (s) => { return (float)s.m_maxUpdatesPerFrame; }, 902 (s) => { return (float)s.m_maxUpdatesPerFrame; },
878 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 903 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
904 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
905 100f,
906 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
907 (s) => { return (float)s.m_taintsToProcessPerStep; },
908 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
879 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 909 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
880 10000.01f, 910 10000.01f,
881 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, 911 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
@@ -1070,12 +1100,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1070 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1100 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1071 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1101 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1072 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", 1102 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1073 0.1f, 1103 0.001f,
1074 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1104 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1075 (s) => { return s.m_params[0].linkConstraintCFM; }, 1105 (s) => { return s.m_params[0].linkConstraintCFM; },
1076 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1106 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1077 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 1107 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1078 0.2f, 1108 0.8f,
1079 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1109 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1080 (s) => { return s.m_params[0].linkConstraintERP; }, 1110 (s) => { return s.m_params[0].linkConstraintERP; },
1081 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1111 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
@@ -1085,11 +1115,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1085 (s) => { return s.m_params[0].linkConstraintSolverIterations; }, 1115 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1086 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), 1116 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1087 1117
1088 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1118 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
1089 0f, 1119 0f,
1090 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1120 (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
1091 (s) => { return (float)s.m_detailedStatsStep; }, 1121 (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
1092 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1122 (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
1093 }; 1123 };
1094 1124
1095 // Convert a boolean to our numeric true and false values 1125 // Convert a boolean to our numeric true and false values
@@ -1270,6 +1300,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1270 public void DetailLog(string msg, params Object[] args) 1300 public void DetailLog(string msg, params Object[] args)
1271 { 1301 {
1272 PhysicsLogging.Write(msg, args); 1302 PhysicsLogging.Write(msg, args);
1303 // Add the Flush() if debugging crashes to get all the messages written out.
1304 // PhysicsLogging.Flush();
1273 } 1305 }
1274 // used to fill in the LocalID when there isn't one 1306 // used to fill in the LocalID when there isn't one
1275 public const string DetailLogZero = "0000000000"; 1307 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 399a133..d189f1d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -67,8 +67,8 @@ public class BSShapeCollection : IDisposable
67 public DateTime lastReferenced; 67 public DateTime lastReferenced;
68 } 68 }
69 69
70 private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>(); 70 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
71 private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>(); 71 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
72 private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>(); 72 private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
73 73
74 public BSShapeCollection(BSScene physScene) 74 public BSShapeCollection(BSScene physScene)
@@ -121,7 +121,7 @@ public class BSShapeCollection : IDisposable
121 // Track another user of a body 121 // Track another user of a body
122 // We presume the caller has allocated the body. 122 // We presume the caller has allocated the body.
123 // Bodies only have one user so the reference count is either 1 or 0. 123 // Bodies only have one user so the reference count is either 1 or 0.
124 public void ReferenceBody(BulletBody body, bool atTaintTime) 124 public void ReferenceBody(BulletBody body, bool inTaintTime)
125 { 125 {
126 lock (m_collectionActivityLock) 126 lock (m_collectionActivityLock)
127 { 127 {
@@ -136,7 +136,21 @@ public class BSShapeCollection : IDisposable
136 // New entry 136 // New entry
137 bodyDesc.ptr = body.ptr; 137 bodyDesc.ptr = body.ptr;
138 bodyDesc.referenceCount = 1; 138 bodyDesc.referenceCount = 1;
139 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount); 139 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
140 body.ID, body, bodyDesc.referenceCount);
141 BSScene.TaintCallback createOperation = delegate()
142 {
143 if (!BulletSimAPI.IsInWorld2(body.ptr))
144 {
145 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
146 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}",
147 body.ID, body);
148 }
149 };
150 if (inTaintTime)
151 createOperation();
152 else
153 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
140 } 154 }
141 bodyDesc.lastReferenced = System.DateTime.Now; 155 bodyDesc.lastReferenced = System.DateTime.Now;
142 Bodies[body.ID] = bodyDesc; 156 Bodies[body.ID] = bodyDesc;
@@ -160,21 +174,22 @@ public class BSShapeCollection : IDisposable
160 Bodies[body.ID] = bodyDesc; 174 Bodies[body.ID] = bodyDesc;
161 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount); 175 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
162 176
163 // If body is no longer being used, free it -- bodies are never shared. 177 // If body is no longer being used, free it -- bodies can never be shared.
164 if (bodyDesc.referenceCount == 0) 178 if (bodyDesc.referenceCount == 0)
165 { 179 {
166 Bodies.Remove(body.ID); 180 Bodies.Remove(body.ID);
167 BSScene.TaintCallback removeOperation = delegate() 181 BSScene.TaintCallback removeOperation = delegate()
168 { 182 {
169 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}", 183 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
170 body.ID, body.ptr.ToString("X")); 184 body.ID, body.ptr.ToString("X"), inTaintTime);
171 // If the caller needs to know the old body is going away, pass the event up. 185 // If the caller needs to know the old body is going away, pass the event up.
172 if (bodyCallback != null) bodyCallback(body); 186 if (bodyCallback != null) bodyCallback(body);
173 187
174 // Zero any reference to the shape so it is not freed when the body is deleted.
175 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
176 // It may have already been removed from the world in which case the next is a NOOP. 188 // It may have already been removed from the world in which case the next is a NOOP.
177 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 189 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
190
191 // Zero any reference to the shape so it is not freed when the body is deleted.
192 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
178 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 193 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
179 }; 194 };
180 // If already in taint-time, do the operations now. Otherwise queue for later. 195 // If already in taint-time, do the operations now. Otherwise queue for later.
@@ -208,7 +223,7 @@ public class BSShapeCollection : IDisposable
208 { 223 {
209 // There is an existing instance of this mesh. 224 // There is an existing instance of this mesh.
210 meshDesc.referenceCount++; 225 meshDesc.referenceCount++;
211 DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}", 226 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
212 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 227 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
213 } 228 }
214 else 229 else
@@ -217,7 +232,7 @@ public class BSShapeCollection : IDisposable
217 meshDesc.ptr = shape.ptr; 232 meshDesc.ptr = shape.ptr;
218 // We keep a reference to the underlying IMesh data so a hull can be built 233 // We keep a reference to the underlying IMesh data so a hull can be built
219 meshDesc.referenceCount = 1; 234 meshDesc.referenceCount = 1;
220 DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}", 235 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
221 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 236 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
222 ret = true; 237 ret = true;
223 } 238 }
@@ -230,7 +245,7 @@ public class BSShapeCollection : IDisposable
230 { 245 {
231 // There is an existing instance of this hull. 246 // There is an existing instance of this hull.
232 hullDesc.referenceCount++; 247 hullDesc.referenceCount++;
233 DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}", 248 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
234 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 249 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
235 } 250 }
236 else 251 else
@@ -238,7 +253,7 @@ public class BSShapeCollection : IDisposable
238 // This is a new reference to a hull 253 // This is a new reference to a hull
239 hullDesc.ptr = shape.ptr; 254 hullDesc.ptr = shape.ptr;
240 hullDesc.referenceCount = 1; 255 hullDesc.referenceCount = 1;
241 DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}", 256 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
242 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 257 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
243 ret = true; 258 ret = true;
244 259
@@ -257,7 +272,7 @@ public class BSShapeCollection : IDisposable
257 272
258 // Release the usage of a shape. 273 // Release the usage of a shape.
259 // The collisionObject is released since it is a copy of the real collision shape. 274 // The collisionObject is released since it is a copy of the real collision shape.
260 public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback) 275 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
261 { 276 {
262 if (shape.ptr == IntPtr.Zero) 277 if (shape.ptr == IntPtr.Zero)
263 return; 278 return;
@@ -279,14 +294,14 @@ public class BSShapeCollection : IDisposable
279 if (shape.ptr != IntPtr.Zero & shape.isNativeShape) 294 if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
280 { 295 {
281 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 296 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
282 BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime); 297 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
283 if (shapeCallback != null) shapeCallback(shape); 298 if (shapeCallback != null) shapeCallback(shape);
284 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 299 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
285 } 300 }
286 break; 301 break;
287 } 302 }
288 }; 303 };
289 if (atTaintTime) 304 if (inTaintTime)
290 { 305 {
291 lock (m_collectionActivityLock) 306 lock (m_collectionActivityLock)
292 { 307 {
@@ -358,7 +373,8 @@ public class BSShapeCollection : IDisposable
358 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 373 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
359 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 374 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
360 { 375 {
361 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 376 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
377 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
362 { 378 {
363 haveShape = true; 379 haveShape = true;
364 if (forceRebuild 380 if (forceRebuild
@@ -372,7 +388,7 @@ public class BSShapeCollection : IDisposable
372 prim.LocalID, forceRebuild, prim.BSShape); 388 prim.LocalID, forceRebuild, prim.BSShape);
373 } 389 }
374 } 390 }
375 else 391 if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
376 { 392 {
377 haveShape = true; 393 haveShape = true;
378 if (forceRebuild 394 if (forceRebuild
@@ -392,7 +408,7 @@ public class BSShapeCollection : IDisposable
392 // made. Native shapes are best used in either case. 408 // made. Native shapes are best used in either case.
393 if (!haveShape) 409 if (!haveShape)
394 { 410 {
395 if (prim.IsPhysical) 411 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
396 { 412 {
397 // Update prim.BSShape to reference a hull of this shape. 413 // Update prim.BSShape to reference a hull of this shape.
398 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); 414 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
@@ -426,7 +442,7 @@ public class BSShapeCollection : IDisposable
426 442
427 // Native shapes are always built independently. 443 // Native shapes are always built independently.
428 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); 444 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
429 newShape.shapeKey = (ulong)shapeKey; 445 newShape.shapeKey = (System.UInt64)shapeKey;
430 newShape.isNativeShape = true; 446 newShape.isNativeShape = true;
431 447
432 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked. 448 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
@@ -446,7 +462,7 @@ public class BSShapeCollection : IDisposable
446 BulletShape newShape = new BulletShape(IntPtr.Zero); 462 BulletShape newShape = new BulletShape(IntPtr.Zero);
447 463
448 float lod; 464 float lod;
449 ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); 465 System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
450 466
451 // if this new shape is the same as last time, don't recreate the mesh 467 // if this new shape is the same as last time, don't recreate the mesh
452 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) 468 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
@@ -469,7 +485,7 @@ public class BSShapeCollection : IDisposable
469 return true; // 'true' means a new shape has been added to this prim 485 return true; // 'true' means a new shape has been added to this prim
470 } 486 }
471 487
472 private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 488 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
473 { 489 {
474 IMesh meshData = null; 490 IMesh meshData = null;
475 IntPtr meshPtr; 491 IntPtr meshPtr;
@@ -516,7 +532,7 @@ public class BSShapeCollection : IDisposable
516 BulletShape newShape; 532 BulletShape newShape;
517 533
518 float lod; 534 float lod;
519 ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod); 535 System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
520 536
521 // if the hull hasn't changed, don't rebuild it 537 // if the hull hasn't changed, don't rebuild it
522 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) 538 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
@@ -525,7 +541,7 @@ public class BSShapeCollection : IDisposable
525 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", 541 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
526 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 542 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
527 543
528 // Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull. 544 // Remove usage of the previous shape.
529 DereferenceShape(prim.BSShape, true, shapeCallback); 545 DereferenceShape(prim.BSShape, true, shapeCallback);
530 546
531 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); 547 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
@@ -539,7 +555,7 @@ public class BSShapeCollection : IDisposable
539 } 555 }
540 556
541 List<ConvexResult> m_hulls; 557 List<ConvexResult> m_hulls;
542 private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 558 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
543 { 559 {
544 560
545 IntPtr hullPtr; 561 IntPtr hullPtr;
@@ -652,22 +668,23 @@ public class BSShapeCollection : IDisposable
652 668
653 // Create a hash of all the shape parameters to be used as a key 669 // Create a hash of all the shape parameters to be used as a key
654 // for this particular shape. 670 // for this particular shape.
655 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) 671 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
656 { 672 {
657 // level of detail based on size and type of the object 673 // level of detail based on size and type of the object
658 float lod = PhysicsScene.MeshLOD; 674 float lod = PhysicsScene.MeshLOD;
659 if (pbs.SculptEntry) 675 if (pbs.SculptEntry)
660 lod = PhysicsScene.SculptLOD; 676 lod = PhysicsScene.SculptLOD;
661 677
678 // Mega prims usually get more detail because one can interact with shape approximations at this size.
662 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); 679 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
663 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 680 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
664 lod = PhysicsScene.MeshMegaPrimLOD; 681 lod = PhysicsScene.MeshMegaPrimLOD;
665 682
666 retLod = lod; 683 retLod = lod;
667 return (ulong)pbs.GetMeshKey(shapeData.Size, lod); 684 return pbs.GetMeshKey(shapeData.Size, lod);
668 } 685 }
669 // For those who don't want the LOD 686 // For those who don't want the LOD
670 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) 687 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
671 { 688 {
672 float lod; 689 float lod;
673 return ComputeShapeKey(shapeData, pbs, out lod); 690 return ComputeShapeKey(shapeData, pbs, out lod);
@@ -701,6 +718,7 @@ public class BSShapeCollection : IDisposable
701 718
702 if (mustRebuild || forceRebuild) 719 if (mustRebuild || forceRebuild)
703 { 720 {
721 // Free any old body
704 DereferenceBody(prim.BSBody, true, bodyCallback); 722 DereferenceBody(prim.BSBody, true, bodyCallback);
705 723
706 BulletBody aBody; 724 BulletBody aBody;
@@ -709,13 +727,13 @@ public class BSShapeCollection : IDisposable
709 { 727 {
710 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 728 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
711 shapeData.ID, shapeData.Position, shapeData.Rotation); 729 shapeData.ID, shapeData.Position, shapeData.Rotation);
712 // DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 730 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
713 } 731 }
714 else 732 else
715 { 733 {
716 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 734 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
717 shapeData.ID, shapeData.Position, shapeData.Rotation); 735 shapeData.ID, shapeData.Position, shapeData.Rotation);
718 // DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 736 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
719 } 737 }
720 aBody = new BulletBody(shapeData.ID, bodyPtr); 738 aBody = new BulletBody(shapeData.ID, bodyPtr);
721 739
@@ -731,7 +749,8 @@ public class BSShapeCollection : IDisposable
731 749
732 private void DetailLog(string msg, params Object[] args) 750 private void DetailLog(string msg, params Object[] args)
733 { 751 {
734 PhysicsScene.PhysicsLogging.Write(msg, args); 752 if (PhysicsScene.PhysicsLogging.Enabled)
753 PhysicsScene.DetailLog(msg, args);
735 } 754 }
736} 755}
737} 756}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 70aa429..caf411e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -114,6 +114,8 @@ public class BSTerrainManager
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity)); 115 Vector3.Zero, Quaternion.Identity));
116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); 116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
117 // Ground plane does not move
118 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
117 // Everything collides with the ground plane. 119 // Everything collides with the ground plane.
118 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 120 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
119 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 121 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
@@ -201,10 +203,10 @@ public class BSTerrainManager
201 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when 203 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
202 // calling this routine from initialization or taint-time routines) or whether to delay 204 // calling this routine from initialization or taint-time routines) or whether to delay
203 // all the unmanaged activities to taint-time. 205 // all the unmanaged activities to taint-time.
204 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime) 206 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
205 { 207 {
206 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}", 208 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
207 BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime); 209 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
208 210
209 float minZ = float.MaxValue; 211 float minZ = float.MaxValue;
210 float maxZ = float.MinValue; 212 float maxZ = float.MinValue;
@@ -296,16 +298,16 @@ public class BSTerrainManager
296 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID, 298 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
297 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); 299 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
298 300
301 // Create the terrain shape from the mapInfo
302 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
303 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
304
299 // The terrain object initial position is at the center of the object 305 // The terrain object initial position is at the center of the object
300 Vector3 centerPos; 306 Vector3 centerPos;
301 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f); 307 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
302 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f); 308 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
303 centerPos.Z = minZ + ((maxZ - minZ) / 2f); 309 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
304 310
305 // Create the terrain shape from the mapInfo
306 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
307 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
308
309 mapInfo.terrainBody = new BulletBody(mapInfo.ID, 311 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
310 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr, 312 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
311 id, centerPos, Quaternion.Identity)); 313 id, centerPos, Quaternion.Identity));
@@ -320,9 +322,6 @@ public class BSTerrainManager
320 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 322 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
321 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 323 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
322 324
323 BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
324 BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
325
326 // Return the new terrain to the world of physical objects 325 // Return the new terrain to the world of physical objects
327 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); 326 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
328 327
@@ -342,7 +341,7 @@ public class BSTerrainManager
342 341
343 // There is the option to do the changes now (we're already in 'taint time'), or 342 // There is the option to do the changes now (we're already in 'taint time'), or
344 // to do the Bullet operations later. 343 // to do the Bullet operations later.
345 if (atTaintTime) 344 if (inTaintTime)
346 rebuildOperation(); 345 rebuildOperation();
347 else 346 else
348 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation); 347 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
@@ -381,7 +380,7 @@ public class BSTerrainManager
381 }; 380 };
382 381
383 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time. 382 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
384 if (atTaintTime) 383 if (inTaintTime)
385 createOperation(); 384 createOperation();
386 else 385 else
387 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation); 386 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index a43880d..276111c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -101,9 +101,8 @@ public struct BulletShape
101 } 101 }
102 public IntPtr ptr; 102 public IntPtr ptr;
103 public ShapeData.PhysicsShapeType type; 103 public ShapeData.PhysicsShapeType type;
104 public ulong shapeKey; 104 public System.UInt64 shapeKey;
105 public bool isNativeShape; 105 public bool isNativeShape;
106 // Hulls have an underlying mesh. A pointer to it is hidden here.
107 public override string ToString() 106 public override string ToString()
108 { 107 {
109 StringBuilder buff = new StringBuilder(); 108 StringBuilder buff = new StringBuilder();
@@ -192,8 +191,9 @@ public struct ShapeData
192 SHAPE_SPHERE = 5, 191 SHAPE_SPHERE = 5,
193 SHAPE_MESH = 6, 192 SHAPE_MESH = 6,
194 SHAPE_HULL = 7, 193 SHAPE_HULL = 7,
195 SHAPE_GROUNDPLANE = 8, 194 // following defined by BulletSim
196 SHAPE_TERRAIN = 9, 195 SHAPE_GROUNDPLANE = 20,
196 SHAPE_TERRAIN = 21,
197 }; 197 };
198 public uint ID; 198 public uint ID;
199 public PhysicsShapeType Type; 199 public PhysicsShapeType Type;
@@ -305,6 +305,8 @@ public struct ConfigurationParameters
305 public float linkConstraintCFM; 305 public float linkConstraintCFM;
306 public float linkConstraintSolverIterations; 306 public float linkConstraintSolverIterations;
307 307
308 public float physicsLoggingFrames;
309
308 public const float numericTrue = 1f; 310 public const float numericTrue = 1f;
309 public const float numericFalse = 0f; 311 public const float numericFalse = 0f;
310} 312}
@@ -1037,18 +1039,6 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1037public static extern int GetNumConstraintRefs2(IntPtr obj); 1039public static extern int GetNumConstraintRefs2(IntPtr obj);
1038 1040
1039[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1041[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1040public static extern Vector3 GetDeltaLinearVelocity2(IntPtr obj);
1041
1042[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1043public static extern Vector3 GetDeltaAngularVelocity2(IntPtr obj);
1044
1045[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1046public static extern Vector3 GetPushVelocity2(IntPtr obj);
1047
1048[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1049public static extern Vector3 GetTurnVelocity2(IntPtr obj);
1050
1051[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1052public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); 1042public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
1053 1043
1054// ===================================================================================== 1044// =====================================================================================
@@ -1108,6 +1098,15 @@ public static extern float GetMargin2(IntPtr shape);
1108public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); 1098public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1109 1099
1110[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1100[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1101public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1102
1103[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1104public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1105
1106[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1107public static extern void DumpAllInfo2(IntPtr sim);
1108
1109[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1111public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); 1110public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1112 1111
1113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1112[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
index f3b0630..c736557 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -100,7 +100,7 @@ namespace OpenSim.Region.Physics.OdePlugin
100 private bool m_hackSentFly = false; 100 private bool m_hackSentFly = false;
101 private int m_requestedUpdateFrequency = 0; 101 private int m_requestedUpdateFrequency = 0;
102 private Vector3 m_taintPosition; 102 private Vector3 m_taintPosition;
103 103 internal bool m_avatarplanted = false;
104 /// <summary> 104 /// <summary>
105 /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force 105 /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force
106 /// while calculatios are going on 106 /// while calculatios are going on
@@ -413,7 +413,7 @@ namespace OpenSim.Region.Physics.OdePlugin
413 set 413 set
414 { 414 {
415 m_iscollidingObj = value; 415 m_iscollidingObj = value;
416 if (value) 416 if (value && !m_avatarplanted)
417 m_pidControllerActive = false; 417 m_pidControllerActive = false;
418 else 418 else
419 m_pidControllerActive = true; 419 m_pidControllerActive = true;
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 7a50c4c..cbe21e2 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -501,6 +501,8 @@ namespace OpenSim.Region.Physics.OdePlugin
501 public int physics_logging_interval = 0; 501 public int physics_logging_interval = 0;
502 public bool physics_logging_append_existing_logfile = false; 502 public bool physics_logging_append_existing_logfile = false;
503 503
504 private bool avplanted = false;
505 private bool av_av_collisions_off = false;
504 506
505 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); 507 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
506 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); 508 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
@@ -644,6 +646,9 @@ namespace OpenSim.Region.Physics.OdePlugin
644 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); 646 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
645 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); 647 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
646 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); 648 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
649 avplanted = physicsconfig.GetBoolean("av_planted", false);
650 av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
651
647 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); 652 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
648 653
649 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); 654 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
@@ -663,6 +668,8 @@ namespace OpenSim.Region.Physics.OdePlugin
663 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); 668 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
664 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); 669 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
665 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); 670 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
671
672
666 673
667 if (Environment.OSVersion.Platform == PlatformID.Unix) 674 if (Environment.OSVersion.Platform == PlatformID.Unix)
668 { 675 {
@@ -1309,6 +1316,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1309 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) 1316 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1310 skipThisContact = true; // No collision on volume detect prims 1317 skipThisContact = true; // No collision on volume detect prims
1311 1318
1319 if (av_av_collisions_off)
1320 if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
1321 skipThisContact = true;
1322
1312 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) 1323 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1313 skipThisContact = true; // No collision on volume detect prims 1324 skipThisContact = true; // No collision on volume detect prims
1314 1325
@@ -1972,7 +1983,8 @@ namespace OpenSim.Region.Physics.OdePlugin
1972 1983
1973 newAv.Flying = isFlying; 1984 newAv.Flying = isFlying;
1974 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; 1985 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1975 1986 newAv.m_avatarplanted = avplanted;
1987
1976 return newAv; 1988 return newAv;
1977 } 1989 }
1978 1990
@@ -1987,6 +1999,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1987 1999
1988 internal void AddCharacter(OdeCharacter chr) 2000 internal void AddCharacter(OdeCharacter chr)
1989 { 2001 {
2002 chr.m_avatarplanted = avplanted;
1990 if (!_characters.Contains(chr)) 2003 if (!_characters.Contains(chr))
1991 { 2004 {
1992 _characters.Add(chr); 2005 _characters.Add(chr);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 2c682d4..17277d7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -3600,7 +3600,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3600 /// <returns></returns> 3600 /// <returns></returns>
3601 public void osSetContentType(LSL_Key id, string type) 3601 public void osSetContentType(LSL_Key id, string type)
3602 { 3602 {
3603 CheckThreatLevel(ThreatLevel.High,"osSetResponseType"); 3603 CheckThreatLevel(ThreatLevel.High, "osSetContentType");
3604
3604 if (m_UrlModule != null) 3605 if (m_UrlModule != null)
3605 m_UrlModule.HttpContentType(new UUID(id),type); 3606 m_UrlModule.HttpContentType(new UUID(id),type);
3606 } 3607 }
@@ -3611,7 +3612,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3611 /// <returns>boolean indicating whether an error was shouted.</returns> 3612 /// <returns>boolean indicating whether an error was shouted.</returns>
3612 protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix) 3613 protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix)
3613 { 3614 {
3614 CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachment");
3615 m_host.AddScriptLPS(1); 3615 m_host.AddScriptLPS(1);
3616 bool fail = false; 3616 bool fail = false;
3617 if (m_item.PermsGranter != m_host.OwnerID) 3617 if (m_item.PermsGranter != m_host.OwnerID)
diff --git a/OpenSim/Server/ServerMain.cs b/OpenSim/Server/ServerMain.cs
index 21fb678..45c13fb 100644
--- a/OpenSim/Server/ServerMain.cs
+++ b/OpenSim/Server/ServerMain.cs
@@ -60,7 +60,25 @@ namespace OpenSim.Server
60 } 60 }
61 61
62 string connList = serverConfig.GetString("ServiceConnectors", String.Empty); 62 string connList = serverConfig.GetString("ServiceConnectors", String.Empty);
63 string[] conns = connList.Split(new char[] {',', ' '}); 63
64 IConfig servicesConfig = m_Server.Config.Configs["ServiceList"];
65 if (servicesConfig != null)
66 {
67 List<string> servicesList = new List<string>();
68 if (connList != String.Empty)
69 servicesList.Add(connList);
70
71 foreach (string k in servicesConfig.GetKeys())
72 {
73 string v = servicesConfig.GetString(k);
74 if (v != String.Empty)
75 servicesList.Add(v);
76 }
77
78 connList = String.Join(",", servicesList.ToArray());
79 }
80
81 string[] conns = connList.Split(new char[] {',', ' ', '\n', '\r', '\t'});
64 82
65// int i = 0; 83// int i = 0;
66 foreach (string c in conns) 84 foreach (string c in conns)
@@ -130,4 +148,4 @@ namespace OpenSim.Server
130 return 0; 148 return 0;
131 } 149 }
132 } 150 }
133} \ No newline at end of file 151}
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
index 67a10b0..20eaa3a 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
@@ -395,8 +395,8 @@ namespace OpenSim.Services.Connectors.SimianGrid
395 if (response["Success"].AsBoolean()) 395 if (response["Success"].AsBoolean())
396 { 396 {
397 OSDMap extraData = response["ExtraData"] as OSDMap; 397 OSDMap extraData = response["ExtraData"] as OSDMap;
398 int enabled = response["Enabled"].AsBoolean() ? (int) OpenSim.Data.RegionFlags.RegionOnline : 0; 398 int enabled = response["Enabled"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.RegionOnline : 0;
399 int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int) OpenSim.Data.RegionFlags.Hyperlink : 0; 399 int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.Hyperlink : 0;
400 int flags = enabled | hypergrid; 400 int flags = enabled | hypergrid;
401 m_log.DebugFormat("[SGGC] enabled - {0} hg - {1} flags - {2}", enabled, hypergrid, flags); 401 m_log.DebugFormat("[SGGC] enabled - {0} hg - {1} flags - {2}", enabled, hypergrid, flags);
402 return flags; 402 return flags;
diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs
index 5bdea06..ee3b858 100644
--- a/OpenSim/Services/GridService/GridService.cs
+++ b/OpenSim/Services/GridService/GridService.cs
@@ -151,11 +151,11 @@ namespace OpenSim.Services.GridService
151 // 151 //
152 // Get it's flags 152 // Get it's flags
153 // 153 //
154 OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(region.Data["flags"]); 154 OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(region.Data["flags"]);
155 155
156 // Is this a reservation? 156 // Is this a reservation?
157 // 157 //
158 if ((rflags & OpenSim.Data.RegionFlags.Reservation) != 0) 158 if ((rflags & OpenSim.Framework.RegionFlags.Reservation) != 0)
159 { 159 {
160 // Regions reserved for the null key cannot be taken. 160 // Regions reserved for the null key cannot be taken.
161 if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString()) 161 if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString())
@@ -166,10 +166,10 @@ namespace OpenSim.Services.GridService
166 // NOTE: Fudging the flags value here, so these flags 166 // NOTE: Fudging the flags value here, so these flags
167 // should not be used elsewhere. Don't optimize 167 // should not be used elsewhere. Don't optimize
168 // this with the later retrieval of the same flags! 168 // this with the later retrieval of the same flags!
169 rflags |= OpenSim.Data.RegionFlags.Authenticate; 169 rflags |= OpenSim.Framework.RegionFlags.Authenticate;
170 } 170 }
171 171
172 if ((rflags & OpenSim.Data.RegionFlags.Authenticate) != 0) 172 if ((rflags & OpenSim.Framework.RegionFlags.Authenticate) != 0)
173 { 173 {
174 // Can we authenticate at all? 174 // Can we authenticate at all?
175 // 175 //
@@ -205,10 +205,10 @@ namespace OpenSim.Services.GridService
205 if ((region != null) && (region.RegionID == regionInfos.RegionID) && 205 if ((region != null) && (region.RegionID == regionInfos.RegionID) &&
206 ((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY))) 206 ((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY)))
207 { 207 {
208 if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Data.RegionFlags.NoMove) != 0) 208 if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.NoMove) != 0)
209 return "Can't move this region"; 209 return "Can't move this region";
210 210
211 if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Data.RegionFlags.LockedOut) != 0) 211 if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.LockedOut) != 0)
212 return "Region locked out"; 212 return "Region locked out";
213 213
214 // Region reregistering in other coordinates. Delete the old entry 214 // Region reregistering in other coordinates. Delete the old entry
@@ -233,7 +233,7 @@ namespace OpenSim.Services.GridService
233 { 233 {
234 int oldFlags = Convert.ToInt32(region.Data["flags"]); 234 int oldFlags = Convert.ToInt32(region.Data["flags"]);
235 235
236 oldFlags &= ~(int)OpenSim.Data.RegionFlags.Reservation; 236 oldFlags &= ~(int)OpenSim.Framework.RegionFlags.Reservation;
237 237
238 rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags 238 rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags
239 } 239 }
@@ -252,7 +252,7 @@ namespace OpenSim.Services.GridService
252 } 252 }
253 253
254 int flags = Convert.ToInt32(rdata.Data["flags"]); 254 int flags = Convert.ToInt32(rdata.Data["flags"]);
255 flags |= (int)OpenSim.Data.RegionFlags.RegionOnline; 255 flags |= (int)OpenSim.Framework.RegionFlags.RegionOnline;
256 rdata.Data["flags"] = flags.ToString(); 256 rdata.Data["flags"] = flags.ToString();
257 257
258 try 258 try
@@ -283,9 +283,9 @@ namespace OpenSim.Services.GridService
283 283
284 int flags = Convert.ToInt32(region.Data["flags"]); 284 int flags = Convert.ToInt32(region.Data["flags"]);
285 285
286 if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Data.RegionFlags.Persistent) != 0) 286 if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Framework.RegionFlags.Persistent) != 0)
287 { 287 {
288 flags &= ~(int)OpenSim.Data.RegionFlags.RegionOnline; 288 flags &= ~(int)OpenSim.Framework.RegionFlags.RegionOnline;
289 region.Data["flags"] = flags.ToString(); 289 region.Data["flags"] = flags.ToString();
290 region.Data["last_seen"] = Util.UnixTimeSinceEpoch(); 290 region.Data["last_seen"] = Util.UnixTimeSinceEpoch();
291 try 291 try
@@ -320,7 +320,7 @@ namespace OpenSim.Services.GridService
320 if (rdata.RegionID != regionID) 320 if (rdata.RegionID != regionID)
321 { 321 {
322 int flags = Convert.ToInt32(rdata.Data["flags"]); 322 int flags = Convert.ToInt32(rdata.Data["flags"]);
323 if ((flags & (int)Data.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours 323 if ((flags & (int)Framework.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours
324 rinfos.Add(RegionData2RegionInfo(rdata)); 324 rinfos.Add(RegionData2RegionInfo(rdata));
325 } 325 }
326 } 326 }
@@ -470,7 +470,7 @@ namespace OpenSim.Services.GridService
470 470
471 foreach (RegionData r in regions) 471 foreach (RegionData r in regions)
472 { 472 {
473 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) 473 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
474 ret.Add(RegionData2RegionInfo(r)); 474 ret.Add(RegionData2RegionInfo(r));
475 } 475 }
476 476
@@ -486,7 +486,7 @@ namespace OpenSim.Services.GridService
486 486
487 foreach (RegionData r in regions) 487 foreach (RegionData r in regions)
488 { 488 {
489 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) 489 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
490 ret.Add(RegionData2RegionInfo(r)); 490 ret.Add(RegionData2RegionInfo(r));
491 } 491 }
492 492
@@ -502,7 +502,7 @@ namespace OpenSim.Services.GridService
502 502
503 foreach (RegionData r in regions) 503 foreach (RegionData r in regions)
504 { 504 {
505 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) 505 if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
506 ret.Add(RegionData2RegionInfo(r)); 506 ret.Add(RegionData2RegionInfo(r));
507 } 507 }
508 508
@@ -629,7 +629,7 @@ namespace OpenSim.Services.GridService
629 629
630 private void OutputRegionToConsole(RegionData r) 630 private void OutputRegionToConsole(RegionData r)
631 { 631 {
632 OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); 632 OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
633 633
634 ConsoleDisplayList dispList = new ConsoleDisplayList(); 634 ConsoleDisplayList dispList = new ConsoleDisplayList();
635 dispList.AddRow("Region Name", r.RegionName); 635 dispList.AddRow("Region Name", r.RegionName);
@@ -659,7 +659,7 @@ namespace OpenSim.Services.GridService
659 659
660 foreach (RegionData r in regions) 660 foreach (RegionData r in regions)
661 { 661 {
662 OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); 662 OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
663 dispTable.AddRow( 663 dispTable.AddRow(
664 r.RegionName, 664 r.RegionName,
665 r.RegionID.ToString(), 665 r.RegionID.ToString(),
@@ -673,7 +673,7 @@ namespace OpenSim.Services.GridService
673 673
674 private int ParseFlags(int prev, string flags) 674 private int ParseFlags(int prev, string flags)
675 { 675 {
676 OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)prev; 676 OpenSim.Framework.RegionFlags f = (OpenSim.Framework.RegionFlags)prev;
677 677
678 string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries); 678 string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries);
679 679
@@ -685,18 +685,18 @@ namespace OpenSim.Services.GridService
685 { 685 {
686 if (p.StartsWith("+")) 686 if (p.StartsWith("+"))
687 { 687 {
688 val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1)); 688 val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
689 f |= (OpenSim.Data.RegionFlags)val; 689 f |= (OpenSim.Framework.RegionFlags)val;
690 } 690 }
691 else if (p.StartsWith("-")) 691 else if (p.StartsWith("-"))
692 { 692 {
693 val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1)); 693 val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
694 f &= ~(OpenSim.Data.RegionFlags)val; 694 f &= ~(OpenSim.Framework.RegionFlags)val;
695 } 695 }
696 else 696 else
697 { 697 {
698 val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p); 698 val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p);
699 f |= (OpenSim.Data.RegionFlags)val; 699 f |= (OpenSim.Framework.RegionFlags)val;
700 } 700 }
701 } 701 }
702 catch (Exception) 702 catch (Exception)
@@ -728,7 +728,7 @@ namespace OpenSim.Services.GridService
728 int flags = Convert.ToInt32(r.Data["flags"]); 728 int flags = Convert.ToInt32(r.Data["flags"]);
729 flags = ParseFlags(flags, cmd[4]); 729 flags = ParseFlags(flags, cmd[4]);
730 r.Data["flags"] = flags.ToString(); 730 r.Data["flags"] = flags.ToString();
731 OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)flags; 731 OpenSim.Framework.RegionFlags f = (OpenSim.Framework.RegionFlags)flags;
732 732
733 MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f)); 733 MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f));
734 m_Database.Store(r); 734 m_Database.Store(r);
diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs
index 78eab3d..743d089 100644
--- a/OpenSim/Services/GridService/HypergridLinker.cs
+++ b/OpenSim/Services/GridService/HypergridLinker.cs
@@ -390,8 +390,8 @@ namespace OpenSim.Services.GridService
390 List<RegionData> regions = m_Database.Get(mapName, m_ScopeID); 390 List<RegionData> regions = m_Database.Get(mapName, m_ScopeID);
391 if (regions != null && regions.Count > 0) 391 if (regions != null && regions.Count > 0)
392 { 392 {
393 OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]); 393 OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]);
394 if ((rflags & OpenSim.Data.RegionFlags.Hyperlink) != 0) 394 if ((rflags & OpenSim.Framework.RegionFlags.Hyperlink) != 0)
395 { 395 {
396 regInfo = new GridRegion(); 396 regInfo = new GridRegion();
397 regInfo.RegionID = regions[0].RegionID; 397 regInfo.RegionID = regions[0].RegionID;
@@ -460,7 +460,7 @@ namespace OpenSim.Services.GridService
460 private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle) 460 private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle)
461 { 461 {
462 RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo); 462 RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo);
463 int flags = (int)OpenSim.Data.RegionFlags.Hyperlink + (int)OpenSim.Data.RegionFlags.NoDirectLogin + (int)OpenSim.Data.RegionFlags.RegionOnline; 463 int flags = (int)OpenSim.Framework.RegionFlags.Hyperlink + (int)OpenSim.Framework.RegionFlags.NoDirectLogin + (int)OpenSim.Framework.RegionFlags.RegionOnline;
464 rdata.Data["flags"] = flags.ToString(); 464 rdata.Data["flags"] = flags.ToString();
465 465
466 m_Database.Store(rdata); 466 m_Database.Store(rdata);
diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs
index cdcb961..3f4c958 100644
--- a/OpenSim/Services/Interfaces/IGridService.cs
+++ b/OpenSim/Services/Interfaces/IGridService.cs
@@ -100,6 +100,19 @@ namespace OpenSim.Services.Interfaces
100 List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y); 100 List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y);
101 List<GridRegion> GetHyperlinks(UUID scopeID); 101 List<GridRegion> GetHyperlinks(UUID scopeID);
102 102
103 /// <summary>
104 /// Get internal OpenSimulator region flags.
105 /// </summary>
106 /// <remarks>
107 /// See OpenSimulator.Framework.RegionFlags. These are not returned in the GridRegion structure -
108 /// they currently need to be requested separately. Possibly this should change to avoid multiple service calls
109 /// in some situations.
110 /// </remarks>
111 /// <returns>
112 /// The region flags.
113 /// </returns>
114 /// <param name='scopeID'></param>
115 /// <param name='regionID'></param>
103 int GetRegionFlags(UUID scopeID, UUID regionID); 116 int GetRegionFlags(UUID scopeID, UUID regionID);
104 } 117 }
105 118