aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorBlueWall2012-12-07 15:36:43 -0500
committerBlueWall2012-12-07 15:36:43 -0500
commit0b455d2882a51ce0841d003f12d4c35ad9edb753 (patch)
treec48c95f48786f8fe435fc5c90477ac3b7c9eaf6c
parentMerge branch 'master' into connector_plugin (diff)
parentMerge branch 'master' of ssh://opensimulator.org/var/git/opensim (diff)
downloadopensim-SC_OLD-0b455d2882a51ce0841d003f12d4c35ad9edb753.zip
opensim-SC_OLD-0b455d2882a51ce0841d003f12d4c35ad9edb753.tar.gz
opensim-SC_OLD-0b455d2882a51ce0841d003f12d4c35ad9edb753.tar.bz2
opensim-SC_OLD-0b455d2882a51ce0841d003f12d4c35ad9edb753.tar.xz
Merge branch 'master' into connector_plugin
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs35
-rw-r--r--OpenSim/Data/Tests/BasicDataServiceTest.cs8
-rw-r--r--OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs508
-rw-r--r--OpenSim/Framework/PrimitiveBaseShape.cs21
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs2
-rw-r--r--OpenSim/Framework/Tests/MundaneFrameworkTests.cs8
-rw-r--r--OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs28
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs5
-rw-r--r--OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs60
-rw-r--r--OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs1
-rw-r--r--OpenSim/Region/Framework/Scenes/EntityManager.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs15
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs82
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs863
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs376
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs96
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs97
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs46
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs68
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs12
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs37
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs34
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs74
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt142
-rw-r--r--OpenSim/Region/Physics/Manager/IMesher.cs1
-rw-r--r--OpenSim/Region/Physics/Manager/ZeroMesher.cs7
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs26
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs5
-rw-r--r--OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs10
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs7
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs25
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs51
-rw-r--r--OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs2
-rw-r--r--OpenSim/Services/HypergridService/HGInstantMessageService.cs35
-rw-r--r--OpenSim/Services/Interfaces/IOfflineIMService.cs115
-rw-r--r--bin/OpenMetaverse.dll.config2
-rwxr-xr-xbin/lib32/BulletSim.dllbin551424 -> 552960 bytes
-rwxr-xr-xbin/lib32/libBulletSim.sobin1707625 -> 1720874 bytes
-rwxr-xr-xbin/lib64/BulletSim.dllbin699904 -> 702464 bytes
-rwxr-xr-xbin/lib64/libBulletSim.sobin1844588 -> 1859487 bytes
-rw-r--r--prebuild.xml4
54 files changed, 2176 insertions, 797 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
index 04cc33a..b497fde 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
@@ -246,6 +246,11 @@ namespace OpenSim.Capabilities.Handlers
246 } 246 }
247 else 247 else
248 { 248 {
249 // Handle the case where no second range value was given. This is equivalent to requesting
250 // the rest of the entity.
251 if (end == -1)
252 end = int.MaxValue;
253
249 end = Utils.Clamp(end, 0, texture.Data.Length - 1); 254 end = Utils.Clamp(end, 0, texture.Data.Length - 1);
250 start = Utils.Clamp(start, 0, end); 255 start = Utils.Clamp(start, 0, end);
251 int len = end - start + 1; 256 int len = end - start + 1;
@@ -299,15 +304,43 @@ namespace OpenSim.Capabilities.Handlers
299// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); 304// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
300 } 305 }
301 306
307 /// <summary>
308 /// Parse a range header.
309 /// </summary>
310 /// <remarks>
311 /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
312 /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
313 /// Where there is no value, -1 is returned.
314 /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
315 /// for start.</remarks>
316 /// <returns></returns>
317 /// <param name='header'></param>
318 /// <param name='start'>Start of the range. Undefined if this was not a number.</param>
319 /// <param name='end'>End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number.</param>
302 private bool TryParseRange(string header, out int start, out int end) 320 private bool TryParseRange(string header, out int start, out int end)
303 { 321 {
322 start = end = 0;
323
304 if (header.StartsWith("bytes=")) 324 if (header.StartsWith("bytes="))
305 { 325 {
306 string[] rangeValues = header.Substring(6).Split('-'); 326 string[] rangeValues = header.Substring(6).Split('-');
327
307 if (rangeValues.Length == 2) 328 if (rangeValues.Length == 2)
308 { 329 {
309 if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) 330 if (!Int32.TryParse(rangeValues[0], out start))
331 return false;
332
333 string rawEnd = rangeValues[1];
334
335 if (rawEnd == "")
336 {
337 end = -1;
338 return true;
339 }
340 else if (Int32.TryParse(rawEnd, out end))
341 {
310 return true; 342 return true;
343 }
311 } 344 }
312 } 345 }
313 346
diff --git a/OpenSim/Data/Tests/BasicDataServiceTest.cs b/OpenSim/Data/Tests/BasicDataServiceTest.cs
index d8019ba..69b79bf 100644
--- a/OpenSim/Data/Tests/BasicDataServiceTest.cs
+++ b/OpenSim/Data/Tests/BasicDataServiceTest.cs
@@ -44,9 +44,15 @@ namespace OpenSim.Data.Tests
44 /// <summary>This is a base class for testing any Data service for any DBMS. 44 /// <summary>This is a base class for testing any Data service for any DBMS.
45 /// Requires NUnit 2.5 or better (to support the generics). 45 /// Requires NUnit 2.5 or better (to support the generics).
46 /// </summary> 46 /// </summary>
47 /// <remarks>
48 /// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with
49 /// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
50 /// and similar on EstateTests, InventoryTests and RegionTests.
51 /// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts.
52 /// </remarks>
47 /// <typeparam name="TConn"></typeparam> 53 /// <typeparam name="TConn"></typeparam>
48 /// <typeparam name="TService"></typeparam> 54 /// <typeparam name="TService"></typeparam>
49 public class BasicDataServiceTest<TConn, TService> : OpenSimTestCase 55 public class BasicDataServiceTest<TConn, TService>
50 where TConn : DbConnection, new() 56 where TConn : DbConnection, new()
51 where TService : class, new() 57 where TService : class, new()
52 { 58 {
diff --git a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
new file mode 100644
index 0000000..9056548
--- /dev/null
+++ b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
@@ -0,0 +1,508 @@
1/*
2 * Copyright (c) 2008, openmetaverse.org, http://opensimulator.org/
3 * All rights reserved.
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 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27using System;
28using System.Threading;
29using System.Collections.Generic;
30
31namespace OpenSim.Framework
32{
33 /// <summary>
34 /// A double dictionary that is thread abort safe.
35 /// </summary>
36 /// <remarks>
37 /// This adapts OpenMetaverse.DoubleDictionary to be thread-abort safe by acquiring ReaderWriterLockSlim within
38 /// a finally section (which can't be interrupted by Thread.Abort()).
39 /// </remarks>
40 public class DoubleDictionaryThreadAbortSafe<TKey1, TKey2, TValue>
41 {
42 Dictionary<TKey1, TValue> Dictionary1;
43 Dictionary<TKey2, TValue> Dictionary2;
44 ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
45
46 public DoubleDictionaryThreadAbortSafe()
47 {
48 Dictionary1 = new Dictionary<TKey1,TValue>();
49 Dictionary2 = new Dictionary<TKey2,TValue>();
50 }
51
52 public DoubleDictionaryThreadAbortSafe(int capacity)
53 {
54 Dictionary1 = new Dictionary<TKey1, TValue>(capacity);
55 Dictionary2 = new Dictionary<TKey2, TValue>(capacity);
56 }
57
58 public void Add(TKey1 key1, TKey2 key2, TValue value)
59 {
60 bool gotLock = false;
61
62 try
63 {
64 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
65 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
66 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
67 try {}
68 finally
69 {
70 rwLock.EnterWriteLock();
71 gotLock = true;
72 }
73
74 if (Dictionary1.ContainsKey(key1))
75 {
76 if (!Dictionary2.ContainsKey(key2))
77 throw new ArgumentException("key1 exists in the dictionary but not key2");
78 }
79 else if (Dictionary2.ContainsKey(key2))
80 {
81 if (!Dictionary1.ContainsKey(key1))
82 throw new ArgumentException("key2 exists in the dictionary but not key1");
83 }
84
85 Dictionary1[key1] = value;
86 Dictionary2[key2] = value;
87 }
88 finally
89 {
90 if (gotLock)
91 rwLock.ExitWriteLock();
92 }
93 }
94
95 public bool Remove(TKey1 key1, TKey2 key2)
96 {
97 bool success;
98 bool gotLock = false;
99
100 try
101 {
102 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
103 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
104 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
105 try {}
106 finally
107 {
108 rwLock.EnterWriteLock();
109 gotLock = true;
110 }
111
112 Dictionary1.Remove(key1);
113 success = Dictionary2.Remove(key2);
114 }
115 finally
116 {
117 if (gotLock)
118 rwLock.ExitWriteLock();
119 }
120
121 return success;
122 }
123
124 public bool Remove(TKey1 key1)
125 {
126 bool found = false;
127 bool gotLock = false;
128
129 try
130 {
131 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
132 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
133 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
134 try {}
135 finally
136 {
137 rwLock.EnterWriteLock();
138 gotLock = true;
139 }
140
141 // This is an O(n) operation!
142 TValue value;
143 if (Dictionary1.TryGetValue(key1, out value))
144 {
145 foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
146 {
147 if (kvp.Value.Equals(value))
148 {
149 Dictionary1.Remove(key1);
150 Dictionary2.Remove(kvp.Key);
151 found = true;
152 break;
153 }
154 }
155 }
156 }
157 finally
158 {
159 if (gotLock)
160 rwLock.ExitWriteLock();
161 }
162
163 return found;
164 }
165
166 public bool Remove(TKey2 key2)
167 {
168 bool found = false;
169 bool gotLock = false;
170
171 try
172 {
173 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
174 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
175 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
176 try {}
177 finally
178 {
179 rwLock.EnterWriteLock();
180 gotLock = true;
181 }
182
183 // This is an O(n) operation!
184 TValue value;
185 if (Dictionary2.TryGetValue(key2, out value))
186 {
187 foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
188 {
189 if (kvp.Value.Equals(value))
190 {
191 Dictionary2.Remove(key2);
192 Dictionary1.Remove(kvp.Key);
193 found = true;
194 break;
195 }
196 }
197 }
198 }
199 finally
200 {
201 if (gotLock)
202 rwLock.ExitWriteLock();
203 }
204
205 return found;
206 }
207
208 public void Clear()
209 {
210 bool gotLock = false;
211
212 try
213 {
214 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
215 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
216 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
217 try {}
218 finally
219 {
220 rwLock.EnterWriteLock();
221 gotLock = true;
222 }
223
224 Dictionary1.Clear();
225 Dictionary2.Clear();
226 }
227 finally
228 {
229 if (gotLock)
230 rwLock.ExitWriteLock();
231 }
232 }
233
234 public int Count
235 {
236 get { return Dictionary1.Count; }
237 }
238
239 public bool ContainsKey(TKey1 key)
240 {
241 return Dictionary1.ContainsKey(key);
242 }
243
244 public bool ContainsKey(TKey2 key)
245 {
246 return Dictionary2.ContainsKey(key);
247 }
248
249 public bool TryGetValue(TKey1 key, out TValue value)
250 {
251 bool success;
252 bool gotLock = false;
253
254 try
255 {
256 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
257 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
258 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
259 try {}
260 finally
261 {
262 rwLock.EnterReadLock();
263 gotLock = true;
264 }
265
266 success = Dictionary1.TryGetValue(key, out value);
267 }
268 finally
269 {
270 if (gotLock)
271 rwLock.ExitReadLock();
272 }
273
274 return success;
275 }
276
277 public bool TryGetValue(TKey2 key, out TValue value)
278 {
279 bool success;
280 bool gotLock = false;
281
282 try
283 {
284 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
285 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
286 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
287 try {}
288 finally
289 {
290 rwLock.EnterReadLock();
291 gotLock = true;
292 }
293
294 success = Dictionary2.TryGetValue(key, out value);
295 }
296 finally
297 {
298 if (gotLock)
299 rwLock.ExitReadLock();
300 }
301
302 return success;
303 }
304
305 public void ForEach(Action<TValue> action)
306 {
307 bool gotLock = false;
308
309 try
310 {
311 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
312 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
313 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
314 try {}
315 finally
316 {
317 rwLock.EnterReadLock();
318 gotLock = true;
319 }
320
321 foreach (TValue value in Dictionary1.Values)
322 action(value);
323 }
324 finally
325 {
326 if (gotLock)
327 rwLock.ExitReadLock();
328 }
329 }
330
331 public void ForEach(Action<KeyValuePair<TKey1, TValue>> action)
332 {
333 bool gotLock = false;
334
335 try
336 {
337 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
338 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
339 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
340 try {}
341 finally
342 {
343 rwLock.EnterReadLock();
344 gotLock = true;
345 }
346
347 foreach (KeyValuePair<TKey1, TValue> entry in Dictionary1)
348 action(entry);
349 }
350 finally
351 {
352 if (gotLock)
353 rwLock.ExitReadLock();
354 }
355 }
356
357 public void ForEach(Action<KeyValuePair<TKey2, TValue>> action)
358 {
359 bool gotLock = false;
360
361 try
362 {
363 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
364 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
365 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
366 try {}
367 finally
368 {
369 rwLock.EnterReadLock();
370 gotLock = true;
371 }
372
373 foreach (KeyValuePair<TKey2, TValue> entry in Dictionary2)
374 action(entry);
375 }
376 finally
377 {
378 if (gotLock)
379 rwLock.ExitReadLock();
380 }
381 }
382
383 public TValue FindValue(Predicate<TValue> predicate)
384 {
385 bool gotLock = false;
386
387 try
388 {
389 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
390 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
391 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
392 try {}
393 finally
394 {
395 rwLock.EnterReadLock();
396 gotLock = true;
397 }
398
399 foreach (TValue value in Dictionary1.Values)
400 {
401 if (predicate(value))
402 return value;
403 }
404 }
405 finally
406 {
407 if (gotLock)
408 rwLock.ExitReadLock();
409 }
410
411 return default(TValue);
412 }
413
414 public IList<TValue> FindAll(Predicate<TValue> predicate)
415 {
416 IList<TValue> list = new List<TValue>();
417 bool gotLock = false;
418
419 try
420 {
421 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
422 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
423 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
424 try {}
425 finally
426 {
427 rwLock.EnterReadLock();
428 gotLock = true;
429 }
430
431 foreach (TValue value in Dictionary1.Values)
432 {
433 if (predicate(value))
434 list.Add(value);
435 }
436 }
437 finally
438 {
439 if (gotLock)
440 rwLock.ExitReadLock();
441 }
442
443 return list;
444 }
445
446 public int RemoveAll(Predicate<TValue> predicate)
447 {
448 IList<TKey1> list = new List<TKey1>();
449 bool gotUpgradeableLock = false;
450
451 try
452 {
453 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
454 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
455 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
456 try {}
457 finally
458 {
459 rwLock.EnterUpgradeableReadLock();
460 gotUpgradeableLock = true;
461 }
462
463 foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
464 {
465 if (predicate(kvp.Value))
466 list.Add(kvp.Key);
467 }
468
469 IList<TKey2> list2 = new List<TKey2>(list.Count);
470 foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
471 {
472 if (predicate(kvp.Value))
473 list2.Add(kvp.Key);
474 }
475
476 bool gotWriteLock = false;
477
478 try
479 {
480 try {}
481 finally
482 {
483 rwLock.EnterUpgradeableReadLock();
484 gotWriteLock = true;
485 }
486
487 for (int i = 0; i < list.Count; i++)
488 Dictionary1.Remove(list[i]);
489
490 for (int i = 0; i < list2.Count; i++)
491 Dictionary2.Remove(list2[i]);
492 }
493 finally
494 {
495 if (gotWriteLock)
496 rwLock.ExitWriteLock();
497 }
498 }
499 finally
500 {
501 if (gotUpgradeableLock)
502 rwLock.ExitUpgradeableReadLock();
503 }
504
505 return list.Count;
506 }
507 }
508} \ No newline at end of file
diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs
index 76dcfca..4c36819 100644
--- a/OpenSim/Framework/PrimitiveBaseShape.cs
+++ b/OpenSim/Framework/PrimitiveBaseShape.cs
@@ -192,18 +192,7 @@ namespace OpenSim.Framework
192 192
193 public PrimitiveBaseShape() 193 public PrimitiveBaseShape()
194 { 194 {
195 PCode = (byte) PCodeEnum.Primitive;
196 ExtraParams = new byte[1];
197 m_textureEntry = DEFAULT_TEXTURE;
198 }
199
200 public PrimitiveBaseShape(bool noShape)
201 {
202 if (noShape)
203 return;
204
205 PCode = (byte)PCodeEnum.Primitive; 195 PCode = (byte)PCodeEnum.Primitive;
206 ExtraParams = new byte[1];
207 m_textureEntry = DEFAULT_TEXTURE; 196 m_textureEntry = DEFAULT_TEXTURE;
208 } 197 }
209 198
@@ -216,7 +205,6 @@ namespace OpenSim.Framework
216// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID); 205// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID);
217 206
218 PCode = (byte)prim.PrimData.PCode; 207 PCode = (byte)prim.PrimData.PCode;
219 ExtraParams = new byte[1];
220 208
221 State = prim.PrimData.State; 209 State = prim.PrimData.State;
222 PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); 210 PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
@@ -248,7 +236,10 @@ namespace OpenSim.Framework
248 SculptTexture = prim.Sculpt.SculptTexture; 236 SculptTexture = prim.Sculpt.SculptTexture;
249 SculptType = (byte)prim.Sculpt.Type; 237 SculptType = (byte)prim.Sculpt.Type;
250 } 238 }
251 else SculptType = (byte)OpenMetaverse.SculptType.None; 239 else
240 {
241 SculptType = (byte)OpenMetaverse.SculptType.None;
242 }
252 } 243 }
253 244
254 [XmlIgnore] 245 [XmlIgnore]
@@ -340,9 +331,9 @@ namespace OpenSim.Framework
340 _scale = new Vector3(side, side, side); 331 _scale = new Vector3(side, side, side);
341 } 332 }
342 333
343 public void SetHeigth(float heigth) 334 public void SetHeigth(float height)
344 { 335 {
345 _scale.Z = heigth; 336 _scale.Z = height;
346 } 337 }
347 338
348 public void SetRadius(float radius) 339 public void SetRadius(float radius)
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 2cd626f..8a0340f 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -436,7 +436,7 @@ namespace OpenSim.Framework.Servers.HttpServer
436// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); 436// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
437 //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); 437 //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
438 438
439 Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); 439 Culture.SetCurrentCulture();
440 440
441// // This is the REST agent interface. We require an agent to properly identify 441// // This is the REST agent interface. We require an agent to properly identify
442// // itself. If the REST handler recognizes the prefix it will attempt to 442// // itself. If the REST handler recognizes the prefix it will attempt to
diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
index 47fe599..1dc8053 100644
--- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
+++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
@@ -303,10 +303,6 @@ namespace OpenSim.Framework.Tests
303 Culture.SetCurrentCulture(); 303 Culture.SetCurrentCulture();
304 Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US"); 304 Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US");
305 305
306 } 306 }
307
308
309
310 } 307 }
311} 308} \ No newline at end of file
312
diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
index 0872cc8..fd02b08 100644
--- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
+++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs
@@ -53,8 +53,10 @@ namespace OpenSim.Region.CoreModules.Asset.Tests
53 protected FlotsamAssetCache m_cache; 53 protected FlotsamAssetCache m_cache;
54 54
55 [SetUp] 55 [SetUp]
56 public void SetUp() 56 public override void SetUp()
57 { 57 {
58 base.SetUp();
59
58 IConfigSource config = new IniConfigSource(); 60 IConfigSource config = new IniConfigSource();
59 61
60 config.AddConfig("Modules"); 62 config.AddConfig("Modules");
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
index af54c1a..b735c61 100644
--- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
@@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
81 } 81 }
82 82
83 if (groupsConfig.GetString("Module", "Default") != "Default") 83 if (groupsConfig.GetString("Module", "Default") != "Default")
84 {
85 m_Enabled = false;
84 return; 86 return;
87 }
85 } 88 }
86 89
87 } 90 }
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index 3983369..fa935cd 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -146,7 +146,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
146 if (sp != null && !sp.IsChildAgent) 146 if (sp != null && !sp.IsChildAgent)
147 { 147 {
148 // Local message 148 // Local message
149 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID); 149// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID);
150 150
151 sp.ControllingClient.SendInstantMessage(im); 151 sp.ControllingClient.SendInstantMessage(im);
152 152
@@ -159,14 +159,14 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
159 // try child avatar second 159 // try child avatar second
160 foreach (Scene scene in m_Scenes) 160 foreach (Scene scene in m_Scenes)
161 { 161 {
162 m_log.DebugFormat( 162// m_log.DebugFormat(
163 "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); 163// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
164 164
165 ScenePresence sp = scene.GetScenePresence(toAgentID); 165 ScenePresence sp = scene.GetScenePresence(toAgentID);
166 if (sp != null) 166 if (sp != null)
167 { 167 {
168 // Local message 168 // Local message
169 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID); 169// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID);
170 170
171 sp.ControllingClient.SendInstantMessage(im); 171 sp.ControllingClient.SendInstantMessage(im);
172 172
@@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
176 } 176 }
177 } 177 }
178 178
179 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); 179// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
180 180
181 SendGridInstantMessageViaXMLRPC(im, result); 181 SendGridInstantMessageViaXMLRPC(im, result);
182 } 182 }
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index 4aaf1fe..7d763fa 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
@@ -186,17 +186,21 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
186 186
187 foreach (GridInstantMessage im in msglist) 187 foreach (GridInstantMessage im in msglist)
188 { 188 {
189 // client.SendInstantMessage(im); 189 if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
190 190 // send it directly or else the item will be given twice
191 // Send through scene event manager so all modules get a chance 191 client.SendInstantMessage(im);
192 // to look at this message before it gets delivered. 192 else
193 // 193 {
194 // Needed for proper state management for stored group 194 // Send through scene event manager so all modules get a chance
195 // invitations 195 // to look at this message before it gets delivered.
196 // 196 //
197 Scene s = FindScene(client.AgentId); 197 // Needed for proper state management for stored group
198 if (s != null) 198 // invitations
199 s.EventManager.TriggerIncomingInstantMessage(im); 199 //
200 Scene s = FindScene(client.AgentId);
201 if (s != null)
202 s.EventManager.TriggerIncomingInstantMessage(im);
203 }
200 } 204 }
201 } 205 }
202 } 206 }
@@ -215,7 +219,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
215 if (!m_ForwardOfflineGroupMessages) 219 if (!m_ForwardOfflineGroupMessages)
216 { 220 {
217 if (im.dialog == (byte)InstantMessageDialog.GroupNotice || 221 if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
218 im.dialog != (byte)InstantMessageDialog.GroupInvitation) 222 im.dialog == (byte)InstantMessageDialog.GroupInvitation)
219 return; 223 return;
220 } 224 }
221 225
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
index b768257..ac25a93 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
@@ -57,8 +57,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
57 protected TestClient m_tc; 57 protected TestClient m_tc;
58 58
59 [SetUp] 59 [SetUp]
60 public void SetUp() 60 public override void SetUp()
61 { 61 {
62 base.SetUp();
63
62 m_iam = new BasicInventoryAccessModule(); 64 m_iam = new BasicInventoryAccessModule();
63 65
64 IConfigSource config = new IniConfigSource(); 66 IConfigSource config = new IniConfigSource();
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
index 7e365ca..69bac82 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs
@@ -46,8 +46,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests
46 public class PresenceConnectorsTests : OpenSimTestCase 46 public class PresenceConnectorsTests : OpenSimTestCase
47 { 47 {
48 LocalPresenceServicesConnector m_LocalConnector; 48 LocalPresenceServicesConnector m_LocalConnector;
49 private void SetUp() 49
50 public override void SetUp()
50 { 51 {
52 base.SetUp();
53
51 IConfigSource config = new IniConfigSource(); 54 IConfigSource config = new IniConfigSource();
52 config.AddConfig("Modules"); 55 config.AddConfig("Modules");
53 config.AddConfig("PresenceService"); 56 config.AddConfig("PresenceService");
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
index 14eca42..0945b43 100644
--- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
+++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs
@@ -60,8 +60,10 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests
60 protected ILandObject m_lo2; 60 protected ILandObject m_lo2;
61 61
62 [SetUp] 62 [SetUp]
63 public void SetUp() 63 public override void SetUp()
64 { 64 {
65 base.SetUp();
66
65 m_pcm = new PrimCountModule(); 67 m_pcm = new PrimCountModule();
66 LandManagementModule lmm = new LandManagementModule(); 68 LandManagementModule lmm = new LandManagementModule();
67 m_scene = new SceneHelpers().SetupScene(); 69 m_scene = new SceneHelpers().SetupScene();
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
index ba4b041..03a96a4 100644
--- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
+++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs
@@ -50,8 +50,10 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests
50 protected MoapModule m_module; 50 protected MoapModule m_module;
51 51
52 [SetUp] 52 [SetUp]
53 public void SetUp() 53 public override void SetUp()
54 { 54 {
55 base.SetUp();
56
55 m_module = new MoapModule(); 57 m_module = new MoapModule();
56 m_scene = new SceneHelpers().SetupScene(); 58 m_scene = new SceneHelpers().SetupScene();
57 SceneHelpers.SetupSceneModules(m_scene, m_module); 59 SceneHelpers.SetupSceneModules(m_scene, m_module);
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index ab8f143..7b235ae 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
365 365
366 if (mainParams.Count < 4) 366 if (mainParams.Count < 4)
367 { 367 {
368 m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); 368 //m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
369 m_console.OutputFormat("Usage: show part id <UUID-or-localID>");
369 return; 370 return;
370 } 371 }
371 372
@@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
405 406
406 if (mainParams.Count < 5) 407 if (mainParams.Count < 5)
407 { 408 {
409 //m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>");
408 m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); 410 m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
409 return; 411 return;
410 } 412 }
@@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
445 447
446 if (mainParams.Count < 4) 448 if (mainParams.Count < 4)
447 { 449 {
448 m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); 450 m_console.OutputFormat("Usage: show part name [--regex] <name>");
451 //m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
449 return; 452 return;
450 } 453 }
451 454
@@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
577 cdl.AddRow("Link number", sop.LinkNum); 580 cdl.AddRow("Link number", sop.LinkNum);
578 cdl.AddRow("Flags", sop.Flags); 581 cdl.AddRow("Flags", sop.Flags);
579 582
583 if (showFull)
584 {
585 PrimitiveBaseShape s = sop.Shape;
586 cdl.AddRow("FlexiDrag", s.FlexiDrag);
587 cdl.AddRow("FlexiEntry", s.FlexiEntry);
588 cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ));
589 cdl.AddRow("FlexiGravity", s.FlexiGravity);
590 cdl.AddRow("FlexiSoftness", s.FlexiSoftness);
591 cdl.AddRow("HollowShape", s.HollowShape);
592 cdl.AddRow(
593 "LightColor",
594 string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
595 cdl.AddRow("FlexiDrag", s.LightCutoff);
596 cdl.AddRow("FlexiDrag", s.LightEntry);
597 cdl.AddRow("FlexiDrag", s.LightFalloff);
598 cdl.AddRow("FlexiDrag", s.LightIntensity);
599 cdl.AddRow("FlexiDrag", s.LightRadius);
600 cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
601 cdl.AddRow("PathBegin", s.PathBegin);
602 cdl.AddRow("PathEnd", s.PathEnd);
603 cdl.AddRow("PathCurve", s.PathCurve);
604 cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset);
605 cdl.AddRow("PathRevolutions", s.PathRevolutions);
606 cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY));
607 cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY));
608 cdl.AddRow("FlexiDrag", s.PathSkew);
609 cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY));
610 cdl.AddRow("PathTwist", s.PathTwist);
611 cdl.AddRow("PathTwistBegin", s.PathTwistBegin);
612 cdl.AddRow("PCode", s.PCode);
613 cdl.AddRow("ProfileBegin", s.ProfileBegin);
614 cdl.AddRow("ProfileEnd", s.ProfileEnd);
615 cdl.AddRow("ProfileHollow", s.ProfileHollow);
616 cdl.AddRow("ProfileShape", s.ProfileShape);
617 cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance);
618 cdl.AddRow("ProjectionEntry", s.ProjectionEntry);
619 cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
620 cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
621 cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
622 cdl.AddRow("Scale", s.Scale);
623 cdl.AddRow(
624 "SculptData",
625 string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a"));
626 cdl.AddRow("SculptEntry", s.SculptEntry);
627 cdl.AddRow("SculptTexture", s.SculptTexture);
628 cdl.AddRow("SculptType", s.SculptType);
629 cdl.AddRow("State", s.State);
630
631 // TODO, unpack and display texture entries
632 //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
633 }
634
580 object itemsOutput; 635 object itemsOutput;
581 if (showFull) 636 if (showFull)
582 { 637 {
@@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
588 itemsOutput = sop.Inventory.Count; 643 itemsOutput = sop.Inventory.Count;
589 } 644 }
590 645
591
592 cdl.AddRow("Items", itemsOutput); 646 cdl.AddRow("Items", itemsOutput);
593 647
594 return sb.Append(cdl.ToString()); 648 return sb.Append(cdl.ToString());
diff --git a/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs b/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs
index 6db6674..093d3f0 100644
--- a/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs
+++ b/OpenSim/Region/Framework/Interfaces/IXmlRpcRouter.cs
@@ -34,5 +34,6 @@ namespace OpenSim.Region.Framework.Interfaces
34 void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url); 34 void RegisterNewReceiver(IScriptModule scriptEngine, UUID channelID, UUID objectID, UUID itemID, string url);
35 void ScriptRemoved(UUID itemID); 35 void ScriptRemoved(UUID itemID);
36 void ObjectRemoved(UUID objectID); 36 void ObjectRemoved(UUID objectID);
37 void UnRegisterReceiver(string channelID, UUID itemID);
37 } 38 }
38} 39}
diff --git a/OpenSim/Region/Framework/Scenes/EntityManager.cs b/OpenSim/Region/Framework/Scenes/EntityManager.cs
index b788a3c..7181313 100644
--- a/OpenSim/Region/Framework/Scenes/EntityManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EntityManager.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
31using System.Reflection; 31using System.Reflection;
32using log4net; 32using log4net;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework;
34 35
35namespace OpenSim.Region.Framework.Scenes 36namespace OpenSim.Region.Framework.Scenes
36{ 37{
@@ -38,7 +39,8 @@ namespace OpenSim.Region.Framework.Scenes
38 { 39 {
39// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 40// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 41
41 private readonly DoubleDictionary<UUID, uint, EntityBase> m_entities = new DoubleDictionary<UUID, uint, EntityBase>(); 42 private readonly DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase> m_entities
43 = new DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase>();
42 44
43 public int Count 45 public int Count
44 { 46 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 1ad5edd..cca295c 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -5638,10 +5638,17 @@ namespace OpenSim.Region.Framework.Scenes
5638 return m_SpawnPoint - 1; 5638 return m_SpawnPoint - 1;
5639 } 5639 }
5640 5640
5641 // Wrappers to get physics modules retrieve assets. Has to be done this way 5641 /// <summary>
5642 // because we can't assign the asset service to physics directly - at the 5642 /// Wrappers to get physics modules retrieve assets.
5643 // time physics are instantiated it's not registered but it will be by 5643 /// </summary>
5644 // the time the first prim exists. 5644 /// <remarks>
5645 /// Has to be done this way
5646 /// because we can't assign the asset service to physics directly - at the
5647 /// time physics are instantiated it's not registered but it will be by
5648 /// the time the first prim exists.
5649 /// </remarks>
5650 /// <param name="assetID"></param>
5651 /// <param name="callback"></param>
5645 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback) 5652 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
5646 { 5653 {
5647 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived); 5654 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
index 6120a81..709d389 100644
--- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
@@ -46,6 +46,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
46{ 46{
47 public class XmlRpcInfo 47 public class XmlRpcInfo
48 { 48 {
49 public UUID item;
49 public UUID channel; 50 public UUID channel;
50 public string uri; 51 public string uri;
51 } 52 }
@@ -88,6 +89,14 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
88 return; 89 return;
89 90
90 scene.RegisterModuleInterface<IXmlRpcRouter>(this); 91 scene.RegisterModuleInterface<IXmlRpcRouter>(this);
92
93 IScriptModule scriptEngine = scene.RequestModuleInterface<IScriptModule>();
94 if ( scriptEngine != null )
95 {
96 scriptEngine.OnScriptRemoved += this.ScriptRemoved;
97 scriptEngine.OnObjectRemoved += this.ObjectRemoved;
98
99 }
91 } 100 }
92 101
93 public void RegionLoaded(Scene scene) 102 public void RegionLoaded(Scene scene)
@@ -120,22 +129,36 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
120 129
121 public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) 130 public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri)
122 { 131 {
123 if (!m_Channels.ContainsKey(itemID)) 132 if (!m_Enabled)
124 { 133 return;
125 XmlRpcInfo info = new XmlRpcInfo();
126 info.channel = channel;
127 info.uri = uri;
128 134
129 bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>( 135 m_log.InfoFormat("[XMLRPC GRID ROUTER]: New receiver Obj: {0} Ch: {1} ID: {2} URI: {3}",
130 "POST", m_ServerURI+"/RegisterChannel/", info); 136 objectID.ToString(), channel.ToString(), itemID.ToString(), uri);
131 137
132 if (!success) 138 XmlRpcInfo info = new XmlRpcInfo();
133 { 139 info.channel = channel;
134 m_log.Error("[XMLRPC GRID ROUTER] Error contacting server"); 140 info.uri = uri;
135 } 141 info.item = itemID;
142
143 bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>(
144 "POST", m_ServerURI+"/RegisterChannel/", info);
136 145
137 m_Channels[itemID] = channel; 146 if (!success)
147 {
148 m_log.Error("[XMLRPC GRID ROUTER] Error contacting server");
138 } 149 }
150
151 m_Channels[itemID] = channel;
152
153 }
154
155 public void UnRegisterReceiver(string channelID, UUID itemID)
156 {
157 if (!m_Enabled)
158 return;
159
160 RemoveChannel(itemID);
161
139 } 162 }
140 163
141 public void ScriptRemoved(UUID itemID) 164 public void ScriptRemoved(UUID itemID)
@@ -143,10 +166,33 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
143 if (!m_Enabled) 166 if (!m_Enabled)
144 return; 167 return;
145 168
146 if (m_Channels.ContainsKey(itemID)) 169 RemoveChannel(itemID);
170
171 }
172
173 public void ObjectRemoved(UUID objectID)
174 {
175 // m_log.InfoFormat("[XMLRPC GRID ROUTER]: Object Removed {0}",objectID.ToString());
176 }
177
178 private bool RemoveChannel(UUID itemID)
179 {
180 if(!m_Channels.ContainsKey(itemID))
181 {
182 m_log.InfoFormat("[XMLRPC GRID ROUTER]: Attempted to unregister non-existing Item: {0}", itemID.ToString());
183 return false;
184 }
185
186 XmlRpcInfo info = new XmlRpcInfo();
187
188 info.channel = m_Channels[itemID];
189 info.item = itemID;
190 info.uri = "http://0.0.0.0:00";
191
192 if (info != null)
147 { 193 {
148 bool success = SynchronousRestObjectRequester.MakeRequest<UUID, bool>( 194 bool success = SynchronousRestObjectRequester.MakeRequest<XmlRpcInfo, bool>(
149 "POST", m_ServerURI+"/RemoveChannel/", m_Channels[itemID]); 195 "POST", m_ServerURI+"/RemoveChannel/", info);
150 196
151 if (!success) 197 if (!success)
152 { 198 {
@@ -154,11 +200,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcGridRouterModule
154 } 200 }
155 201
156 m_Channels.Remove(itemID); 202 m_Channels.Remove(itemID);
203 return true;
157 } 204 }
158 } 205 return false;
159
160 public void ObjectRemoved(UUID objectID)
161 {
162 } 206 }
163 } 207 }
164} 208}
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
index 4783f4c..ad0b83d 100644
--- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
@@ -101,12 +101,18 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule
101 scriptEngine.PostScriptEvent(itemID, "xmlrpc_uri", new Object[] {uri}); 101 scriptEngine.PostScriptEvent(itemID, "xmlrpc_uri", new Object[] {uri});
102 } 102 }
103 103
104 public void UnRegisterReceiver(string channelID, UUID itemID)
105 {
106 }
107
104 public void ScriptRemoved(UUID itemID) 108 public void ScriptRemoved(UUID itemID)
105 { 109 {
110 System.Console.WriteLine("TEST Script Removed!");
106 } 111 }
107 112
108 public void ObjectRemoved(UUID objectID) 113 public void ObjectRemoved(UUID objectID)
109 { 114 {
115 System.Console.WriteLine("TEST Obj Removed!");
110 } 116 }
111 } 117 }
112} 118}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..21aa9be 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -165,8 +165,8 @@ public sealed class BSCharacter : BSPhysObject
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
166 166
167 // Do this after the object has been added to the world 167 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, 168 BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr,
169 (uint)CollisionFilterGroups.AvatarFilter, 169 (uint)CollisionFilterGroups.AvatarGroup,
170 (uint)CollisionFilterGroups.AvatarMask); 170 (uint)CollisionFilterGroups.AvatarMask);
171 } 171 }
172 172
@@ -307,7 +307,7 @@ public sealed class BSCharacter : BSPhysObject
307 } 307 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 309 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 310 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 311 if (Position.Z < waterHeight)
312 { 312 {
313 _position.Z = waterHeight; 313 _position.Z = waterHeight;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 95a4134..fa3110c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -24,30 +24,17 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * 26 *
27 27 * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28 * are Copyright (c) 2009 Linden Research, Inc and are used under their license
29 * call the BulletSim system. 29 * of Creative Commons Attribution-Share Alike 3.0
30 */ 30 * (http://creativecommons.org/licenses/by-sa/3.0/).
31/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
32 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
33 * ODEPrim.cs contains methods dealing with Prim editing, Prim
34 * characteristics and Kinetic motion.
35 * ODEDynamics.cs contains methods dealing with Prim Physical motion
36 * (dynamics) and the associated settings. Old Linear and angular
37 * motors for dynamic motion have been replace with MoveLinear()
38 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
39 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
40 * switch between 'VEHICLE' parameter use and general dynamics
41 * settings use.
42 */ 31 */
43 32
44using System; 33using System;
45using System.Collections.Generic; 34using System.Collections.Generic;
46using System.Reflection; 35using System.Reflection;
47using System.Runtime.InteropServices; 36using System.Runtime.InteropServices;
48using log4net;
49using OpenMetaverse; 37using OpenMetaverse;
50using OpenSim.Framework;
51using OpenSim.Region.Physics.Manager; 38using OpenSim.Region.Physics.Manager;
52 39
53namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.Physics.BulletSPlugin
@@ -100,7 +87,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
100 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 87 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
101 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 88 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
102 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 89 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
103 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body 90 private Vector3 m_lastAngularCorrection = Vector3.Zero;
104 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 91 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
105 92
106 //Deflection properties 93 //Deflection properties
@@ -125,8 +112,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
125 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. 112 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
126 113
127 //Attractor properties 114 //Attractor properties
128 private float m_verticalAttractionEfficiency = 1.0f; // damped 115 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
129 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 116 private float m_verticalAttractionEfficiency = 1.0f; // damped
117 private float m_verticalAttractionCutoff = 500f; // per the documentation
118 // Timescale > cutoff means no vert attractor.
119 private float m_verticalAttractionTimescale = 510f;
130 120
131 public BSDynamics(BSScene myScene, BSPrim myPrim) 121 public BSDynamics(BSScene myScene, BSPrim myPrim)
132 { 122 {
@@ -153,7 +143,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
153 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 143 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
154 break; 144 break;
155 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 145 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
156 m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); 146 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
157 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; 147 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
158 break; 148 break;
159 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 149 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
@@ -161,7 +151,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
161 m_angularMotor.TimeScale = m_angularMotorTimescale; 151 m_angularMotor.TimeScale = m_angularMotorTimescale;
162 break; 152 break;
163 case Vehicle.BANKING_EFFICIENCY: 153 case Vehicle.BANKING_EFFICIENCY:
164 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 154 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
165 break; 155 break;
166 case Vehicle.BANKING_MIX: 156 case Vehicle.BANKING_MIX:
167 m_bankingMix = Math.Max(pValue, 0.01f); 157 m_bankingMix = Math.Max(pValue, 0.01f);
@@ -170,10 +160,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
170 m_bankingTimescale = Math.Max(pValue, 0.01f); 160 m_bankingTimescale = Math.Max(pValue, 0.01f);
171 break; 161 break;
172 case Vehicle.BUOYANCY: 162 case Vehicle.BUOYANCY:
173 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 163 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
174 break; 164 break;
175 case Vehicle.HOVER_EFFICIENCY: 165 case Vehicle.HOVER_EFFICIENCY:
176 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 166 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
177 break; 167 break;
178 case Vehicle.HOVER_HEIGHT: 168 case Vehicle.HOVER_HEIGHT:
179 m_VhoverHeight = pValue; 169 m_VhoverHeight = pValue;
@@ -188,7 +178,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
188 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 178 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
189 break; 179 break;
190 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 180 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
191 m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); 181 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
192 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; 182 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
193 break; 183 break;
194 case Vehicle.LINEAR_MOTOR_TIMESCALE: 184 case Vehicle.LINEAR_MOTOR_TIMESCALE:
@@ -196,10 +186,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
196 m_linearMotor.TimeScale = m_linearMotorTimescale; 186 m_linearMotor.TimeScale = m_linearMotorTimescale;
197 break; 187 break;
198 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 188 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
199 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 189 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
190 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
200 break; 191 break;
201 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 192 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
202 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 193 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
194 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
203 break; 195 break;
204 196
205 // These are vector properties but the engine lets you use a single float value to 197 // These are vector properties but the engine lets you use a single float value to
@@ -239,9 +231,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
239 break; 231 break;
240 case Vehicle.ANGULAR_MOTOR_DIRECTION: 232 case Vehicle.ANGULAR_MOTOR_DIRECTION:
241 // Limit requested angular speed to 2 rps= 4 pi rads/sec 233 // Limit requested angular speed to 2 rps= 4 pi rads/sec
242 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); 234 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
243 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 235 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
244 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 236 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
245 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 237 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
246 m_angularMotor.SetTarget(m_angularMotorDirection); 238 m_angularMotor.SetTarget(m_angularMotorDirection);
247 break; 239 break;
@@ -314,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
314 m_VhoverEfficiency = 0; 306 m_VhoverEfficiency = 0;
315 m_VhoverTimescale = 0; 307 m_VhoverTimescale = 0;
316 m_VehicleBuoyancy = 0; 308 m_VehicleBuoyancy = 0;
317 309
318 m_linearDeflectionEfficiency = 1; 310 m_linearDeflectionEfficiency = 1;
319 m_linearDeflectionTimescale = 1; 311 m_linearDeflectionTimescale = 1;
320 312
@@ -363,13 +355,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
363 m_bankingMix = 1; 355 m_bankingMix = 1;
364 356
365 m_referenceFrame = Quaternion.Identity; 357 m_referenceFrame = Quaternion.Identity;
366 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY 358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
367 | VehicleFlag.HOVER_TERRAIN_ONLY 359 | VehicleFlag.HOVER_TERRAIN_ONLY
368 | VehicleFlag.HOVER_GLOBAL_HEIGHT 360 | VehicleFlag.HOVER_GLOBAL_HEIGHT
369 | VehicleFlag.HOVER_UP_ONLY); 361 | VehicleFlag.HOVER_UP_ONLY);
370 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 362 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
371 | VehicleFlag.LIMIT_ROLL_ONLY 363 | VehicleFlag.LIMIT_ROLL_ONLY
372 | VehicleFlag.LIMIT_MOTOR_UP); 364 | VehicleFlag.LIMIT_MOTOR_UP);
365
373 break; 366 break;
374 case Vehicle.TYPE_CAR: 367 case Vehicle.TYPE_CAR:
375 m_linearMotorDirection = Vector3.Zero; 368 m_linearMotorDirection = Vector3.Zero;
@@ -513,6 +506,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
513 m_bankingEfficiency = 0; 506 m_bankingEfficiency = 0;
514 m_bankingMix = 0.7f; 507 m_bankingMix = 0.7f;
515 m_bankingTimescale = 5; 508 m_bankingTimescale = 5;
509
516 m_referenceFrame = Quaternion.Identity; 510 m_referenceFrame = Quaternion.Identity;
517 511
518 m_referenceFrame = Quaternion.Identity; 512 m_referenceFrame = Quaternion.Identity;
@@ -530,13 +524,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
530 Refresh(); 524 Refresh();
531 525
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, 526 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale, 1f); 527 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
528 1f);
534 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) 529 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
530
535 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, 531 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
536 m_angularMotorDecayTimescale, m_angularFrictionTimescale, 1f); 532 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
533 1f);
537 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) 534 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
538 535
539 // m_bankingMotor = new BSVMotor("BankingMotor", ...); 536 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
537 BSMotor.Infinite, BSMotor.InfiniteVector,
538 m_verticalAttractionEfficiency);
539 // Z goes away and we keep X and Y
540 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
541 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
540 } 542 }
541 543
542 // Some of the properties of this prim may have changed. 544 // Some of the properties of this prim may have changed.
@@ -545,9 +547,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
545 { 547 {
546 if (IsActive) 548 if (IsActive)
547 { 549 {
550 // Remember the mass so we don't have to fetch it every step
548 m_vehicleMass = Prim.Linkset.LinksetMass; 551 m_vehicleMass = Prim.Linkset.LinksetMass;
549 552
550 // Friction effects are handled by this vehicle code 553 // Friction affects are handled by this vehicle code
551 float friction = 0f; 554 float friction = 0f;
552 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); 555 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
553 556
@@ -557,14 +560,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
557 float angularDamping = PhysicsScene.Params.vehicleAngularDamping; 560 float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
558 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); 561 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
559 562
563 // Vehicles report collision events so we know when it's on the ground
564 BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
565
560 // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet 566 // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
561 // Vector3 localInertia = new Vector3(1f, 1f, 1f); 567 // Vector3 localInertia = new Vector3(1f, 1f, 1f);
562 Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); 568 // Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
569 Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass);
563 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); 570 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
571 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
564 572
565 VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", 573 VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
566 Prim.LocalID, friction, localInertia, angularDamping); 574 Prim.LocalID, friction, localInertia, angularDamping);
567 } 575 }
576 else
577 {
578 BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
579 }
568 } 580 }
569 581
570 public bool RemoveBodyDependencies(BSPhysObject prim) 582 public bool RemoveBodyDependencies(BSPhysObject prim)
@@ -585,60 +597,288 @@ namespace OpenSim.Region.Physics.BulletSPlugin
585 Refresh(); 597 Refresh();
586 } 598 }
587 599
600 #region Known vehicle value functions
601 // Vehicle physical parameters that we buffer from constant getting and setting.
602 // The "m_known*" variables are initialized to 'null', fetched only if referenced
603 // and stored back into the physics engine only if updated.
604 // This does two things: 1) saves continuious calls into unmanaged code, and
605 // 2) signals when a physics property update must happen back to the simulator
606 // to update values modified for the vehicle.
607 private int m_knownChanged;
608 private float? m_knownTerrainHeight;
609 private float? m_knownWaterLevel;
610 private Vector3? m_knownPosition;
611 private Vector3? m_knownVelocity;
612 private Vector3 m_knownForce;
613 private Quaternion? m_knownOrientation;
614 private Vector3? m_knownRotationalVelocity;
615 private Vector3 m_knownRotationalForce;
616 private float? m_knownForwardSpeed;
617
618 private const int m_knownChangedPosition = 1 << 0;
619 private const int m_knownChangedVelocity = 1 << 1;
620 private const int m_knownChangedForce = 1 << 2;
621 private const int m_knownChangedOrientation = 1 << 3;
622 private const int m_knownChangedRotationalVelocity = 1 << 4;
623 private const int m_knownChangedRotationalForce = 1 << 5;
624
625 private void ForgetKnownVehicleProperties()
626 {
627 m_knownTerrainHeight = null;
628 m_knownWaterLevel = null;
629 m_knownPosition = null;
630 m_knownVelocity = null;
631 m_knownForce = Vector3.Zero;
632 m_knownOrientation = null;
633 m_knownRotationalVelocity = null;
634 m_knownRotationalForce = Vector3.Zero;
635 m_knownForwardSpeed = null;
636 m_knownChanged = 0;
637 }
638 private void PushKnownChanged()
639 {
640 if (m_knownChanged != 0)
641 {
642 if ((m_knownChanged & m_knownChangedPosition) != 0)
643 Prim.ForcePosition = VehiclePosition;
644 if ((m_knownChanged & m_knownChangedOrientation) != 0)
645 Prim.ForceOrientation = VehicleOrientation;
646 if ((m_knownChanged & m_knownChangedVelocity) != 0)
647 {
648 Prim.ForceVelocity = VehicleVelocity;
649 BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity);
650 }
651 if ((m_knownChanged & m_knownChangedForce) != 0)
652 Prim.AddForce((Vector3)m_knownForce, false, true);
653
654 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
655 {
656 Prim.ForceRotationalVelocity = VehicleRotationalVelocity;
657 // Fake out Bullet by making it think the velocity is the same as last time.
658 BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity);
659 }
660 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
661 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true);
662
663 // If we set one of the values (ie, the physics engine didn't do it) we must force
664 // an UpdateProperties event to send the changes up to the simulator.
665 BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr);
666 }
667 }
668
669 // Since the computation of terrain height can be a little involved, this routine
670 // is used ot fetch the height only once for each vehicle simulation step.
671 private float GetTerrainHeight(Vector3 pos)
672 {
673 if (m_knownTerrainHeight == null)
674 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
675 return (float)m_knownTerrainHeight;
676 }
677
678 // Since the computation of water level can be a little involved, this routine
679 // is used ot fetch the level only once for each vehicle simulation step.
680 private float GetWaterLevel(Vector3 pos)
681 {
682 if (m_knownWaterLevel == null)
683 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
684 return (float)m_knownWaterLevel;
685 }
686
687 private Vector3 VehiclePosition
688 {
689 get
690 {
691 if (m_knownPosition == null)
692 m_knownPosition = Prim.ForcePosition;
693 return (Vector3)m_knownPosition;
694 }
695 set
696 {
697 m_knownPosition = value;
698 m_knownChanged |= m_knownChangedPosition;
699 }
700 }
701
702 private Quaternion VehicleOrientation
703 {
704 get
705 {
706 if (m_knownOrientation == null)
707 m_knownOrientation = Prim.ForceOrientation;
708 return (Quaternion)m_knownOrientation;
709 }
710 set
711 {
712 m_knownOrientation = value;
713 m_knownChanged |= m_knownChangedOrientation;
714 }
715 }
716
717 private Vector3 VehicleVelocity
718 {
719 get
720 {
721 if (m_knownVelocity == null)
722 m_knownVelocity = Prim.ForceVelocity;
723 return (Vector3)m_knownVelocity;
724 }
725 set
726 {
727 m_knownVelocity = value;
728 m_knownChanged |= m_knownChangedVelocity;
729 }
730 }
731
732 private void VehicleAddForce(Vector3 aForce)
733 {
734 m_knownForce += aForce;
735 m_knownChanged |= m_knownChangedForce;
736 }
737
738 private Vector3 VehicleRotationalVelocity
739 {
740 get
741 {
742 if (m_knownRotationalVelocity == null)
743 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
744 return (Vector3)m_knownRotationalVelocity;
745 }
746 set
747 {
748 m_knownRotationalVelocity = value;
749 m_knownChanged |= m_knownChangedRotationalVelocity;
750 }
751 }
752 private void VehicleAddAngularForce(Vector3 aForce)
753 {
754 m_knownRotationalForce += aForce;
755 m_knownChanged |= m_knownChangedRotationalForce;
756 }
757 private float VehicleForwardSpeed
758 {
759 get
760 {
761 if (m_knownForwardSpeed == null)
762 m_knownForwardSpeed = (VehicleVelocity * Quaternion.Inverse(VehicleOrientation)).X;
763 return (float)m_knownForwardSpeed;
764 }
765 }
766
767 #endregion // Known vehicle value functions
768
588 // One step of the vehicle properties for the next 'pTimestep' seconds. 769 // One step of the vehicle properties for the next 'pTimestep' seconds.
589 internal void Step(float pTimestep) 770 internal void Step(float pTimestep)
590 { 771 {
591 if (!IsActive) return; 772 if (!IsActive) return;
592 773
774 ForgetKnownVehicleProperties();
775
593 MoveLinear(pTimestep); 776 MoveLinear(pTimestep);
594 MoveAngular(pTimestep); 777 MoveAngular(pTimestep);
595 778
596 LimitRotation(pTimestep); 779 LimitRotation(pTimestep);
597 780
598 // remember the position so next step we can limit absolute movement effects 781 // remember the position so next step we can limit absolute movement effects
599 m_lastPositionVector = Prim.ForcePosition; 782 m_lastPositionVector = VehiclePosition;
783
784 // If we forced the changing of some vehicle parameters, update the values and
785 // for the physics engine to note the changes so an UpdateProperties event will happen.
786 PushKnownChanged();
600 787
601 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 788 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
602 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 789 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity);
603 } 790 }
604 791
605 // Apply the effect of the linear motor. 792 // Apply the effect of the linear motor and other linear motions (like hover and float).
606 // Also does hover and float.
607 private void MoveLinear(float pTimestep) 793 private void MoveLinear(float pTimestep)
608 { 794 {
609 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); 795 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
610 796
611 // Rotate new object velocity from vehicle relative to world coordinates 797 // The movement computed in the linear motor is relative to the vehicle
612 linearMotorContribution *= Prim.ForceOrientation; 798 // coordinates. Rotate the movement to world coordinates.
799 linearMotorContribution *= VehicleOrientation;
613 800
614 // ================================================================== 801 // ==================================================================
615 // Gravity and Buoyancy 802 // Buoyancy: force to overcome gravity.
616 // There is some gravity, make a gravity force vector that is applied after object velocity.
617 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 803 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
618 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); 804 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
805 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
806
807 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
808
809 Vector3 hoverContribution = ComputeLinearHover(pTimestep);
810
811 ComputeLinearBlockingEndPoint(pTimestep);
812
813 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep);
814
815 // ==================================================================
816 Vector3 newVelocity = linearMotorContribution
817 + terrainHeightContribution
818 + hoverContribution
819 + limitMotorUpContribution;
820
821 // If not changing some axis, reduce out velocity
822 if ((m_flags & (VehicleFlag.NO_X)) != 0)
823 newVelocity.X = 0;
824 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
825 newVelocity.Y = 0;
826 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
827 newVelocity.Z = 0;
619 828
620 // Current vehicle position 829 // ==================================================================
621 Vector3 pos = Prim.ForcePosition; 830 // Clamp high or low velocities
831 float newVelocityLengthSq = newVelocity.LengthSquared();
832 // if (newVelocityLengthSq > 1e6f)
833 if (newVelocityLengthSq > 1000f)
834 {
835 newVelocity /= newVelocity.Length();
836 newVelocity *= 1000f;
837 }
838 // else if (newVelocityLengthSq < 1e-6f)
839 else if (newVelocityLengthSq < 0.001f)
840 newVelocity = Vector3.Zero;
622 841
623 // ================================================================== 842 // ==================================================================
624 Vector3 terrainHeightContribution = Vector3.Zero; 843 // Stuff new linear velocity into the vehicle.
844 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us.
845 VehicleVelocity = newVelocity;
846
847 // Other linear forces are applied as forces.
848 Vector3 totalDownForce = buoyancyContribution * m_vehicleMass;
849 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
850 {
851 VehicleAddForce(totalDownForce);
852 }
853
854 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}",
855 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding);
856 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
857 Prim.LocalID,
858 linearMotorContribution, terrainHeightContribution, hoverContribution,
859 limitMotorUpContribution, buoyancyContribution
860 );
861
862 } // end MoveLinear()
863
864 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep)
865 {
866 Vector3 ret = Vector3.Zero;
625 // If below the terrain, move us above the ground a little. 867 // If below the terrain, move us above the ground a little.
626 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 868 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
627 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 869 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
628 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
629 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
630 // if (rotatedSize.Z < terrainHeight)
631 if (pos.Z < terrainHeight)
632 { 870 {
633 // TODO: correct position by applying force rather than forcing position. 871 // TODO: correct position by applying force rather than forcing position.
634 pos.Z = terrainHeight + 2; 872 VehiclePosition += new Vector3(0f, 0f, GetTerrainHeight(VehiclePosition) + 2f);
635 Prim.ForcePosition = pos; 873 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
636 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
637 } 874 }
875 return ret;
876 }
877
878 public Vector3 ComputeLinearHover(float pTimestep)
879 {
880 Vector3 ret = Vector3.Zero;
638 881
639 // ==================================================================
640 Vector3 hoverContribution = Vector3.Zero;
641 // Check if hovering
642 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 882 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
643 // m_VhoverTimescale: time to achieve height 883 // m_VhoverTimescale: time to achieve height
644 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 884 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -646,11 +886,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
646 // We should hover, get the target height 886 // We should hover, get the target height
647 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 887 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
648 { 888 {
649 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 889 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
650 } 890 }
651 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 891 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
652 { 892 {
653 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; 893 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
654 } 894 }
655 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 895 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
656 { 896 {
@@ -660,43 +900,47 @@ namespace OpenSim.Region.Physics.BulletSPlugin
660 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 900 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
661 { 901 {
662 // If body is already heigher, use its height as target height 902 // If body is already heigher, use its height as target height
663 if (pos.Z > m_VhoverTargetHeight) 903 if (VehiclePosition.Z > m_VhoverTargetHeight)
664 m_VhoverTargetHeight = pos.Z; 904 m_VhoverTargetHeight = VehiclePosition.Z;
665 } 905 }
906
666 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 907 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
667 { 908 {
668 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 909 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
669 { 910 {
911 Vector3 pos = VehiclePosition;
670 pos.Z = m_VhoverTargetHeight; 912 pos.Z = m_VhoverTargetHeight;
671 Prim.ForcePosition = pos; 913 VehiclePosition = pos;
672 } 914 }
673 } 915 }
674 else 916 else
675 { 917 {
676 float verticalError = pos.Z - m_VhoverTargetHeight; 918 // Error is positive if below the target and negative if above.
677 // RA: where does the 50 come from? 919 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z;
678 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 920 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
679 // Replace Vertical speed with correction figure if significant 921
680 if (verticalError > 0.01f) 922 // TODO: implement m_VhoverEfficiency correctly
681 { 923 if (Math.Abs(verticalError) > m_VhoverEfficiency)
682 hoverContribution = new Vector3(0f, 0f, verticalCorrectionVelocity);
683 //KF: m_VhoverEfficiency is not yet implemented
684 }
685 else if (verticalError < -0.01)
686 { 924 {
687 hoverContribution = new Vector3(0f, 0f, -verticalCorrectionVelocity); 925 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
688 } 926 }
689 } 927 }
690 928
691 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", 929 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}",
692 Prim.LocalID, pos, hoverContribution, m_VhoverHeight, m_VhoverTargetHeight); 930 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight);
693 } 931 }
694 932
695 // ================================================================== 933 return ret;
934 }
935
936 public bool ComputeLinearBlockingEndPoint(float pTimestep)
937 {
938 bool changed = false;
939
940 Vector3 pos = VehiclePosition;
696 Vector3 posChange = pos - m_lastPositionVector; 941 Vector3 posChange = pos - m_lastPositionVector;
697 if (m_BlockingEndPoint != Vector3.Zero) 942 if (m_BlockingEndPoint != Vector3.Zero)
698 { 943 {
699 bool changed = false;
700 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 944 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
701 { 945 {
702 pos.X -= posChange.X + 1; 946 pos.X -= posChange.X + 1;
@@ -724,240 +968,111 @@ namespace OpenSim.Region.Physics.BulletSPlugin
724 } 968 }
725 if (changed) 969 if (changed)
726 { 970 {
727 Prim.ForcePosition = pos; 971 VehiclePosition = pos;
728 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 972 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
729 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 973 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
730 } 974 }
731 } 975 }
976 return changed;
977 }
978
979 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
980 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
981 // used with conjunction with banking: the strength of the banking will decay when the
982 // vehicle no longer experiences collisions. The decay timescale is the same as
983 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
984 // when they are in mid jump.
985 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
986 // This is just using the ground and a general collision check. Should really be using
987 // a downward raycast to find what is below.
988 public Vector3 ComputeLinearMotorUp(float pTimestep)
989 {
990 Vector3 ret = Vector3.Zero;
732 991
733 // ==================================================================
734 Vector3 limitMotorUpContribution = Vector3.Zero;
735 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 992 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
736 { 993 {
737 // If the vehicle is motoring into the sky, get it going back down. 994 // If the vehicle is motoring into the sky, get it going back down.
738 float distanceAboveGround = pos.Z - terrainHeight; 995 float distanceAboveGround = VehiclePosition.Z - GetTerrainHeight(VehiclePosition);
739 if (distanceAboveGround > 1f) 996 // Not colliding if the vehicle is off the ground
997 if (!Prim.IsColliding)
740 { 998 {
741 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); 999 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
742 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1000 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
743 limitMotorUpContribution = new Vector3(0, 0, -distanceAboveGround); 1001 ret = new Vector3(0, 0, -distanceAboveGround);
744 } 1002 }
745 // TODO: this calculation is all wrong. From the description at 1003 // TODO: this calculation is wrong. From the description at
746 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1004 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
747 // has a decay factor. This says this force should 1005 // has a decay factor. This says this force should
748 // be computed with a motor. 1006 // be computed with a motor.
749 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 1007 // TODO: add interaction with banking.
750 Prim.LocalID, distanceAboveGround, limitMotorUpContribution); 1008 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
751 } 1009 Prim.LocalID, distanceAboveGround, ret);
752
753 // ==================================================================
754 Vector3 newVelocity = linearMotorContribution
755 + terrainHeightContribution
756 + hoverContribution
757 + limitMotorUpContribution;
758
759 // If not changing some axis, reduce out velocity
760 if ((m_flags & (VehicleFlag.NO_X)) != 0)
761 newVelocity.X = 0;
762 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
763 newVelocity.Y = 0;
764 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
765 newVelocity.Z = 0;
766
767 // ==================================================================
768 // Clamp REALLY high or low velocities
769 float newVelocityLengthSq = newVelocity.LengthSquared();
770 if (newVelocityLengthSq > 1e6f)
771 {
772 newVelocity /= newVelocity.Length();
773 newVelocity *= 1000f;
774 }
775 else if (newVelocityLengthSq < 1e-6f)
776 newVelocity = Vector3.Zero;
777
778 // ==================================================================
779 // Stuff new linear velocity into the vehicle
780 Prim.ForceVelocity = newVelocity;
781 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
782
783 // Other linear forces are applied as forces.
784 Vector3 totalDownForce = grav * m_vehicleMass;
785 if (totalDownForce != Vector3.Zero)
786 {
787 Prim.AddForce(totalDownForce, false);
788 } 1010 }
789 1011 return ret;
790 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", 1012 }
791 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
792 newVelocity, Prim.Velocity, totalDownForce);
793
794 } // end MoveLinear()
795 1013
796 // ======================================================================= 1014 // =======================================================================
797 // ======================================================================= 1015 // =======================================================================
798 // Apply the effect of the angular motor. 1016 // Apply the effect of the angular motor.
1017 // The 'contribution' is how much angular correction velocity each function wants.
1018 // All the contributions are added together and the resulting velocity is
1019 // set directly on the vehicle.
799 private void MoveAngular(float pTimestep) 1020 private void MoveAngular(float pTimestep)
800 { 1021 {
801 // m_angularMotorDirection // angular velocity requested by LSL motor 1022 // The user wants how many radians per second angular change?
802 // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
803 // m_angularMotorTimescale // motor angular velocity ramp up time
804 // m_angularMotorDecayTimescale // motor angular velocity decay rate
805 // m_angularFrictionTimescale // body angular velocity decay rate
806 // m_lastAngularVelocity // what was last applied to body
807
808 if (m_angularMotorDirection.LengthSquared() > 0.0001)
809 {
810 Vector3 origVel = m_angularMotorVelocity;
811 Vector3 origDir = m_angularMotorDirection;
812
813 // new velocity += error / ( time to get there / step interval)
814 // requested direction - current vehicle direction
815 m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep);
816 // decay requested direction
817 m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale));
818
819 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}",
820 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
821 }
822 else
823 {
824 m_angularMotorVelocity = Vector3.Zero;
825 }
826
827 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); 1023 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
828 1024
829 // ================================================================== 1025 // ==================================================================
830 Vector3 verticalAttractionContribution = Vector3.Zero; 1026 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
831 // If vertical attaction timescale is reasonable and we applied an angular force last time... 1027 // This flag prevents linear deflection parallel to world z-axis. This is useful
832 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 1028 // for preventing ground vehicles with large linear deflection, like bumper cars,
1029 // from climbing their linear deflection into the sky.
1030 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1031 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
833 { 1032 {
834 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; 1033 angularMotorContribution.X = 0f;
835 if (Prim.IsColliding) 1034 angularMotorContribution.Y = 0f;
836 VAservo = pTimestep * 0.05f / m_verticalAttractionTimescale; 1035 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
837 1036 }
838 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
839
840 // Create a vector of the vehicle "up" in world coordinates
841 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
842 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
843 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
844 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
845 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
846 // modulated to prevent a stable inverted body.
847
848 // Error is 0 (no error) to +/- 2 (max error)
849 if (verticalError.Z < 0.0f)
850 {
851 verticalError.X = 2.0f - verticalError.X;
852 verticalError.Y = 2.0f - verticalError.Y;
853 }
854 // scale it by VAservo (timestep and timescale)
855 verticalError = verticalError * VAservo;
856 1037
857 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y 1038 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
858 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
859 // Z is not changed.
860 verticalAttractionContribution.X = verticalError.Y;
861 verticalAttractionContribution.Y = - verticalError.X;
862 verticalAttractionContribution.Z = 0f;
863 1039
864 // scaling appears better usingsquare-law 1040 Vector3 deflectionContribution = ComputeAngularDeflection();
865 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
866 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
867 verticalAttractionContribution.X += bounce * angularVelocity.X;
868 verticalAttractionContribution.Y += bounce * angularVelocity.Y;
869 1041
870 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", 1042 Vector3 bankingContribution = ComputeAngularBanking();
871 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, verticalAttractionContribution);
872 1043
873 } 1044 // ==================================================================
1045 m_lastVertAttractor = verticalAttractionContribution;
1046
1047 // Sum corrections
1048 m_lastAngularCorrection = angularMotorContribution
1049 + verticalAttractionContribution
1050 + deflectionContribution
1051 + bankingContribution;
874 1052
875 // ================================================================== 1053 // ==================================================================
876 Vector3 deflectionContribution = Vector3.Zero; 1054 // Apply the correction velocity.
877 if (m_angularDeflectionEfficiency != 0) 1055 // TODO: Should this be applied as an angular force (torque)?
1056 if (!m_lastAngularCorrection.ApproxEquals(Vector3.Zero, 0.01f))
878 { 1057 {
879 // Compute a scaled vector that points in the preferred axis (X direction) 1058 Vector3 scaledCorrection = m_lastAngularCorrection * pTimestep;
880 Vector3 scaledDefaultDirection = 1059 VehicleRotationalVelocity = scaledCorrection;
881 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); 1060
882 // Adding the current vehicle orientation and reference frame displaces the orientation to the frame. 1061 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5},scaledCorr={6}",
883 // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point. 1062 Prim.LocalID,
884 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); 1063 angularMotorContribution, verticalAttractionContribution,
885 1064 bankingContribution, deflectionContribution,
886 // Scale by efficiency and timescale 1065 m_lastAngularCorrection, scaledCorrection
887 deflectionContribution = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; 1066 );
888
889 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
890 Prim.LocalID, preferredAxisOfMotion, deflectionContribution);
891 // This deflection computation is not correct.
892 deflectionContribution = Vector3.Zero;
893 } 1067 }
894 1068 else
895 // ==================================================================
896 Vector3 bankingContribution = Vector3.Zero;
897 if (m_bankingEfficiency != 0)
898 { 1069 {
899 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1070 // The vehicle is not adding anything angular wise.
900 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); 1071 VehicleRotationalVelocity = Vector3.Zero;
901 //Changes which way it banks in and out of turns 1072 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
902
903 //Use the square of the efficiency, as it looks much more how SL banking works
904 float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
905 if (m_bankingEfficiency < 0)
906 effSquared *= -1; //Keep the negative!
907
908 float mix = Math.Abs(m_bankingMix);
909 if (m_angularMotorVelocity.X == 0)
910 {
911 // The vehicle is stopped
912 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
913 {
914 Vector3 axisAngle;
915 float angle;
916 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
917 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
918 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
919 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
920 else
921 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
922 }*/
923 }
924 else
925 {
926 bankingContribution.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
927 }
928
929 //If they are colliding, we probably shouldn't shove the prim around... probably
930 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
931 {
932 float angVelZ = m_angularMotorVelocity.X*-1;
933 /*if(angVelZ > mix)
934 angVelZ = mix;
935 else if(angVelZ < -mix)
936 angVelZ = -mix;*/
937 //This controls how fast and how far the banking occurs
938 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
939 if (bankingRot.X > 3)
940 bankingRot.X = 3;
941 else if (bankingRot.X < -3)
942 bankingRot.X = -3;
943 bankingRot *= Prim.ForceOrientation;
944 bankingContribution += bankingRot;
945 }
946 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
947 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
948 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, bankingContribution);
949 } 1073 }
950 1074
951 // ================================================================== 1075 // ==================================================================
952 m_lastVertAttractor = verticalAttractionContribution;
953
954 // Sum velocities
955 m_lastAngularVelocity = angularMotorContribution
956 + verticalAttractionContribution
957 + bankingContribution
958 + deflectionContribution;
959
960 // ==================================================================
961 //Offset section 1076 //Offset section
962 if (m_linearMotorOffset != Vector3.Zero) 1077 if (m_linearMotorOffset != Vector3.Zero)
963 { 1078 {
@@ -983,41 +1098,166 @@ namespace OpenSim.Region.Physics.BulletSPlugin
983 torqueFromOffset.Y = 0; 1098 torqueFromOffset.Y = 0;
984 if (float.IsNaN(torqueFromOffset.Z)) 1099 if (float.IsNaN(torqueFromOffset.Z))
985 torqueFromOffset.Z = 0; 1100 torqueFromOffset.Z = 0;
986 torqueFromOffset *= m_vehicleMass; 1101
987 Prim.ApplyTorqueImpulse(torqueFromOffset, true); 1102 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
988 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1103 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
989 } 1104 }
990 1105
991 // ================================================================== 1106 }
992 // NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement 1107 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
993 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1108 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1109 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1110 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1111 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1112 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1113 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1114 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1115 public Vector3 ComputeAngularVerticalAttraction()
1116 {
1117 Vector3 ret = Vector3.Zero;
1118
1119 // If vertical attaction timescale is reasonable and we applied an angular force last time...
1120 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff)
994 { 1121 {
995 m_lastAngularVelocity.X = 0; 1122 // Take a vector pointing up and convert it from world to vehicle relative coords.
996 m_lastAngularVelocity.Y = 0; 1123 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
997 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1124 verticalError.Normalize();
1125
1126 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1127 // is now leaning to one side (rotated around the X axis) and the Y value will
1128 // go from zero (nearly straight up) to one (completely to the side) or leaning
1129 // front-to-back (rotated around the Y axis) and the value of X will be between
1130 // zero and one.
1131 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1132
1133 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1134 if (verticalError.Z < 0f)
1135 {
1136 verticalError.X = 2f - verticalError.X;
1137 verticalError.Y = 2f - verticalError.Y;
1138 }
1139
1140 // Y error means needed rotation around X axis and visa versa.
1141 ret.X = verticalError.Y;
1142 ret.Y = - verticalError.X;
1143 ret.Z = 0f;
1144
1145 // Scale the correction force by how far we're off from vertical.
1146 // Z error of one says little error. As Z gets smaller, the vehicle is leaning farther over.
1147 float clampedSqrZError = ClampInRange(0.01f, verticalError.Z * verticalError.Z, 1f);
1148 float vertForce = 1f / clampedSqrZError;
1149
1150 ret *= vertForce;
1151
1152 // Correction happens over a number of seconds.
1153 Vector3 unscaledContrib = ret;
1154 ret /= m_verticalAttractionTimescale;
1155
1156 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},vertForce={3},eff={4},vertAttr={5}",
1157 Prim.LocalID, verticalError, unscaledContrib, vertForce, m_verticalAttractionEfficiency, ret);
998 } 1158 }
1159 return ret;
1160 }
999 1161
1000 // ================================================================== 1162 // Return the angular correction to correct the direction the vehicle is pointing to be
1001 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1163 // the direction is should want to be pointing.
1164 // The vehicle is moving in some direction and correct its orientation to it is pointing
1165 // in that direction.
1166 // TODO: implement reference frame.
1167 public Vector3 ComputeAngularDeflection()
1168 {
1169 Vector3 ret = Vector3.Zero;
1170 return ret; // DEBUG DEBUG DEBUG debug one force at a time
1171
1172 if (m_angularDeflectionEfficiency != 0)
1002 { 1173 {
1003 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1174 // The direction the vehicle is moving
1004 Prim.ZeroAngularMotion(true); 1175 Vector3 movingDirection = VehicleVelocity;
1005 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1176 movingDirection.Normalize();
1177
1178 // The direction the vehicle is pointing
1179 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1180 pointingDirection.Normalize();
1181
1182 // The difference between what is and what should be
1183 Vector3 deflectionError = movingDirection - pointingDirection;
1184
1185 // Scale the correction by recovery timescale and efficiency
1186 ret = (-deflectionError * VehicleForwardSpeed) * m_angularDeflectionEfficiency;
1187 ret /= m_angularDeflectionTimescale;
1188
1189 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1190 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
1006 } 1191 }
1007 else 1192 return ret;
1193 }
1194
1195 // Return an angular change to rotate the vehicle around the Z axis when the vehicle
1196 // is tipped around the X axis.
1197 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1198 // The vertical attractor feature must be enabled in order for the banking behavior to
1199 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1200 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1201 // of the yaw effect will be proportional to the
1202 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1203 // velocity along its preferred axis of motion.
1204 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1205 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1206 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1207 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1208 // Negating the banking coefficient will make it so that the vehicle leans to the
1209 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1210 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1211 // banking vehicles do what you want rather than what the laws of physics allow.
1212 // For example, consider a real motorcycle...it must be moving forward in order for
1213 // it to turn while banking, however video-game motorcycles are often configured
1214 // to turn in place when at a dead stop--because they are often easier to control
1215 // that way using the limited interface of the keyboard or game controller. The
1216 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1217 // banking by functioning as a slider between a banking that is correspondingly
1218 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1219 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1220 // to "dynamic" where the banking is also proportional to its velocity along its
1221 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1222 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1223 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1224 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1225 // make a sluggish vehicle by giving it a timescale of several seconds.
1226 public Vector3 ComputeAngularBanking()
1227 {
1228 Vector3 ret = Vector3.Zero;
1229
1230 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1008 { 1231 {
1009 // Apply to the body. 1232 // This works by rotating a unit vector to the orientation of the vehicle. The
1010 // The above calculates the absolute angular velocity needed. Angular velocity is massless. 1233 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1011 // Since we are stuffing the angular velocity directly into the object, the computed 1234 // up to one for full over).
1012 // velocity needs to be scaled by the timestep. 1235 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1013 // Also remove any motion that is on the object so added motion is only from vehicle. 1236
1014 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) 1237 // Figure out the yaw value for this much roll.
1015 - Prim.ForceRotationalVelocity); 1238 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency;
1016 Prim.ForceRotationalVelocity = applyAngularForce; 1239 // Keep the sign
1017 1240 if (rollComponents.Y < 0f)
1018 VDetailLog("{0},MoveAngular,done,newRotVel={1},lastAngular={2}", 1241 turnComponent = -turnComponent;
1019 Prim.LocalID, applyAngularForce, m_lastAngularVelocity); 1242
1243 // TODO: there must be a better computation of the banking force.
1244 float bankingTurnForce = turnComponent;
1245
1246 // actual error = static turn error + dynamic turn error
1247 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed;
1248 // TODO: the banking effect should not go to infinity but what to limit it to?
1249 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f);
1250
1251 // Build the force vector to change rotation from what it is to what it should be
1252 ret.Z = -mixedBankingError;
1253
1254 // Don't do it all at once.
1255 ret /= m_bankingTimescale;
1256
1257 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}",
1258 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret);
1020 } 1259 }
1260 return ret;
1021 } 1261 }
1022 1262
1023 // This is from previous instantiations of XXXDynamics.cs. 1263 // This is from previous instantiations of XXXDynamics.cs.
@@ -1026,7 +1266,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1026 // Should this be in MoveAngular()? 1266 // Should this be in MoveAngular()?
1027 internal void LimitRotation(float timestep) 1267 internal void LimitRotation(float timestep)
1028 { 1268 {
1029 Quaternion rotq = Prim.ForceOrientation; 1269 Quaternion rotq = VehicleOrientation;
1030 Quaternion m_rot = rotq; 1270 Quaternion m_rot = rotq;
1031 if (m_RollreferenceFrame != Quaternion.Identity) 1271 if (m_RollreferenceFrame != Quaternion.Identity)
1032 { 1272 {
@@ -1054,12 +1294,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1054 } 1294 }
1055 if (rotq != m_rot) 1295 if (rotq != m_rot)
1056 { 1296 {
1057 Prim.ForceOrientation = m_rot; 1297 VehicleOrientation = m_rot;
1058 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1298 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1059 } 1299 }
1060 1300
1061 } 1301 }
1062 1302
1303 private float ClampInRange(float low, float val, float high)
1304 {
1305 return Math.Max(low, Math.Min(val, high));
1306 }
1307
1063 // Invoke the detailed logger and output something if it's enabled. 1308 // Invoke the detailed logger and output something if it's enabled.
1064 private void VDetailLog(string msg, params Object[] args) 1309 private void VDetailLog(string msg, params Object[] args)
1065 { 1310 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
index 663b6f4..390c2f9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -1,191 +1,185 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using System.Reflection; 30using System.Reflection;
31using Nini.Config; 31using Nini.Config;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 35
36public struct MaterialAttributes 36public struct MaterialAttributes
37{ 37{
38 // Material type values that correspond with definitions for LSL 38 // Material type values that correspond with definitions for LSL
39 public enum Material : int 39 public enum Material : int
40 { 40 {
41 Stone = 0, 41 Stone = 0,
42 Metal, 42 Metal,
43 Glass, 43 Glass,
44 Wood, 44 Wood,
45 Flesh, 45 Flesh,
46 Plastic, 46 Plastic,
47 Rubber, 47 Rubber,
48 Light, 48 Light,
49 // Hereafter are BulletSim additions 49 // Hereafter are BulletSim additions
50 Avatar, 50 Avatar,
51 NumberOfTypes // the count of types in the enum. 51 NumberOfTypes // the count of types in the enum.
52 } 52 }
53 // Names must be in the order of the above enum. 53 // Names must be in the order of the above enum.
54 public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", 54 public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
55 "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; 55 "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
56 public static string[] MaterialAttribs = { "Density", "Friction", "Restitution", 56 public static string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
57 "ccdMotionThreshold", "ccdSweptSphereRadius" }; 57
58 58 public MaterialAttributes(string t, float d, float f, float r)
59 public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS) 59 {
60 { 60 type = t;
61 type = t; 61 density = d;
62 density = d; 62 friction = f;
63 friction = f; 63 restitution = r;
64 restitution = r; 64 }
65 ccdMotionThreshold = ccdM; 65 public string type;
66 ccdSweptSphereRadius = ccdS; 66 public float density;
67 } 67 public float friction;
68 public string type; 68 public float restitution;
69 public float density; 69}
70 public float friction; 70
71 public float restitution; 71public static class BSMaterials
72 public float ccdMotionThreshold; 72{
73 public float ccdSweptSphereRadius; 73 public static MaterialAttributes[] Attributes;
74} 74
75 75 static BSMaterials()
76public static class BSMaterials 76 {
77{ 77 // Attribute sets for both the non-physical and physical instances of materials.
78 public static MaterialAttributes[] Attributes; 78 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
79 79 }
80 static BSMaterials() 80
81 { 81 // This is where all the default material attributes are defined.
82 // Attribute sets for both the non-physical and physical instances of materials. 82 public static void InitializeFromDefaults(ConfigurationParameters parms)
83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; 83 {
84 } 84 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
85 85 // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
86 // This is where all the default material attributes are defined. 86 // "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
87 public static void InitializeFromDefaults(ConfigurationParameters parms) 87 float dFriction = parms.defaultFriction;
88 { 88 float dRestitution = parms.defaultRestitution;
89 // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", 89 float dDensity = parms.defaultDensity;
90 // "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; 90 Attributes[(int)MaterialAttributes.Material.Stone] =
91 float dFriction = parms.defaultFriction; 91 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
92 float dRestitution = parms.defaultRestitution; 92 Attributes[(int)MaterialAttributes.Material.Metal] =
93 float dDensity = parms.defaultDensity; 93 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
94 float dCcdM = parms.ccdMotionThreshold; 94 Attributes[(int)MaterialAttributes.Material.Glass] =
95 float dCcdS = parms.ccdSweptSphereRadius; 95 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
96 Attributes[(int)MaterialAttributes.Material.Stone] = 96 Attributes[(int)MaterialAttributes.Material.Wood] =
97 new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 97 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
98 Attributes[(int)MaterialAttributes.Material.Metal] = 98 Attributes[(int)MaterialAttributes.Material.Flesh] =
99 new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 99 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
100 Attributes[(int)MaterialAttributes.Material.Glass] = 100 Attributes[(int)MaterialAttributes.Material.Plastic] =
101 new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 101 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
102 Attributes[(int)MaterialAttributes.Material.Wood] = 102 Attributes[(int)MaterialAttributes.Material.Rubber] =
103 new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 103 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
104 Attributes[(int)MaterialAttributes.Material.Flesh] = 104 Attributes[(int)MaterialAttributes.Material.Light] =
105 new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 105 new MaterialAttributes("light",dDensity, dFriction, dRestitution);
106 Attributes[(int)MaterialAttributes.Material.Plastic] = 106 Attributes[(int)MaterialAttributes.Material.Avatar] =
107 new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 107 new MaterialAttributes("avatar",60f, 0.2f, 0f);
108 Attributes[(int)MaterialAttributes.Material.Rubber] = 108
109 new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 109 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
110 Attributes[(int)MaterialAttributes.Material.Light] = 110 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
111 new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 111 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
112 Attributes[(int)MaterialAttributes.Material.Avatar] = 112 new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f);
113 new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 113 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
114 114 new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f);
115 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = 115 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
116 new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 116 new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f);
117 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = 117 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
118 new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 118 new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f);
119 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = 119 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
120 new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 120 new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f);
121 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = 121 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
122 new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 122 new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f);
123 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = 123 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
124 new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 124 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
125 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = 125 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
126 new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 126 new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f);
127 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = 127 }
128 new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 128
129 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = 129 // Under the [BulletSim] section, one can change the individual material
130 new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 130 // attribute values. The format of the configuration parameter is:
131 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = 131 // <materialName><Attribute>["Physical"] = floatValue
132 new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); 132 // For instance:
133 } 133 // [BulletSim]
134 134 // StoneFriction = 0.2
135 // Under the [BulletSim] section, one can change the individual material 135 // FleshRestitutionPhysical = 0.8
136 // attribute values. The format of the configuration parameter is: 136 // Materials can have different parameters for their static and
137 // <materialName><Attribute>["Physical"] = floatValue 137 // physical instantiations. When setting the non-physical value,
138 // For instance: 138 // both values are changed. Setting the physical value only changes
139 // [BulletSim] 139 // the physical value.
140 // StoneFriction = 0.2 140 public static void InitializefromParameters(IConfig pConfig)
141 // FleshRestitutionPhysical = 0.8 141 {
142 // Materials can have different parameters for their static and 142 int matType = 0;
143 // physical instantiations. When setting the non-physical value, 143 foreach (string matName in MaterialAttributes.MaterialNames)
144 // both values are changed. Setting the physical value only changes 144 {
145 // the physical value. 145 foreach (string attribName in MaterialAttributes.MaterialAttribs)
146 public static void InitializefromParameters(IConfig pConfig) 146 {
147 { 147 string paramName = matName + attribName;
148 int matType = 0; 148 if (pConfig.Contains(paramName))
149 foreach (string matName in MaterialAttributes.MaterialNames) 149 {
150 { 150 float paramValue = pConfig.GetFloat(paramName);
151 foreach (string attribName in MaterialAttributes.MaterialAttribs) 151 SetAttributeValue(matType, attribName, paramValue);
152 { 152 // set the physical value also
153 string paramName = matName + attribName; 153 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
154 if (pConfig.Contains(paramName)) 154 }
155 { 155 paramName += "Physical";
156 float paramValue = pConfig.GetFloat(paramName); 156 if (pConfig.Contains(paramName))
157 SetAttributeValue(matType, attribName, paramValue); 157 {
158 // set the physical value also 158 float paramValue = pConfig.GetFloat(paramName);
159 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); 159 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
160 } 160 }
161 paramName += "Physical"; 161 }
162 if (pConfig.Contains(paramName)) 162 matType++;
163 { 163 }
164 float paramValue = pConfig.GetFloat(paramName); 164 }
165 SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); 165
166 } 166 private static void SetAttributeValue(int matType, string attribName, float val)
167 } 167 {
168 matType++; 168 MaterialAttributes thisAttrib = Attributes[matType];
169 } 169 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
170 } 170 if (fieldInfo != null)
171 171 {
172 private static void SetAttributeValue(int matType, string attribName, float val) 172 fieldInfo.SetValue(thisAttrib, val);
173 { 173 Attributes[matType] = thisAttrib;
174 MaterialAttributes thisAttrib = Attributes[matType]; 174 }
175 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName); 175 }
176 if (fieldInfo != null) 176
177 { 177 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
178 fieldInfo.SetValue(thisAttrib, val); 178 {
179 Attributes[matType] = thisAttrib; 179 int ind = (int)type;
180 } 180 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
181 } 181 return Attributes[ind];
182 182 }
183 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) 183
184 { 184}
185 int ind = (int)type; 185}
186 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
187 return Attributes[ind];
188 }
189
190}
191}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index 480da2c..851d508 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,3 +1,30 @@
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 */
1using System; 28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3using System.Text; 30using System.Text;
@@ -7,6 +34,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
7{ 34{
8public abstract class BSMotor 35public abstract class BSMotor
9{ 36{
37 // Timescales and other things can be turned off by setting them to 'infinite'.
38 public const float Infinite = 12345f;
39 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
40
10 public BSMotor(string useName) 41 public BSMotor(string useName)
11 { 42 {
12 UseName = useName; 43 UseName = useName;
@@ -15,7 +46,9 @@ public abstract class BSMotor
15 public virtual void Reset() { } 46 public virtual void Reset() { }
16 public virtual void Zero() { } 47 public virtual void Zero() { }
17 48
49 // A name passed at motor creation for easily identifyable debugging messages.
18 public string UseName { get; private set; } 50 public string UseName { get; private set; }
51
19 // Used only for outputting debug information. Might not be set so check for null. 52 // Used only for outputting debug information. Might not be set so check for null.
20 public BSScene PhysicsScene { get; set; } 53 public BSScene PhysicsScene { get; set; }
21 protected void MDetailLog(string msg, params Object[] parms) 54 protected void MDetailLog(string msg, params Object[] parms)
@@ -30,10 +63,23 @@ public abstract class BSMotor
30 } 63 }
31} 64}
32// Can all the incremental stepping be replaced with motor classes? 65// Can all the incremental stepping be replaced with motor classes?
66
67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
68// The TargetValue is decays in TargetValueDecayTimeScale and
69// the CurrentValue will be held back by FrictionTimeScale.
70// TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay.
71
72// For instance, if something is moving at speed X and the desired speed is Y,
73// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
74// values of CurrentValue are returned that approach the TargetValue.
75// The feature of decaying TargetValue is so vehicles will eventually
76// come to a stop rather than run forever. This can be disabled by
77// setting TargetValueDecayTimescale to 'infinite'.
78// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
33public class BSVMotor : BSMotor 79public class BSVMotor : BSMotor
34{ 80{
35 public Vector3 FrameOfReference { get; set; } 81 // public Vector3 FrameOfReference { get; set; }
36 public Vector3 Offset { get; set; } 82 // public Vector3 Offset { get; set; }
37 83
38 public float TimeScale { get; set; } 84 public float TimeScale { get; set; }
39 public float TargetValueDecayTimeScale { get; set; } 85 public float TargetValueDecayTimeScale { get; set; }
@@ -46,8 +92,9 @@ public class BSVMotor : BSMotor
46 public BSVMotor(string useName) 92 public BSVMotor(string useName)
47 : base(useName) 93 : base(useName)
48 { 94 {
49 TimeScale = TargetValueDecayTimeScale = Efficiency = 1f; 95 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
50 FrictionTimescale = Vector3.Zero; 96 Efficiency = 1f;
97 FrictionTimescale = BSMotor.InfiniteVector;
51 CurrentValue = TargetValue = Vector3.Zero; 98 CurrentValue = TargetValue = Vector3.Zero;
52 } 99 }
53 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 100 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
@@ -67,6 +114,14 @@ public class BSVMotor : BSMotor
67 { 114 {
68 TargetValue = target; 115 TargetValue = target;
69 } 116 }
117
118 // A form of stepping that does not take the time quantum into account.
119 // The caller must do the right thing later.
120 public Vector3 Step()
121 {
122 return Step(1f);
123 }
124
70 public Vector3 Step(float timeStep) 125 public Vector3 Step(float timeStep)
71 { 126 {
72 Vector3 returnCurrent = Vector3.Zero; 127 Vector3 returnCurrent = Vector3.Zero;
@@ -78,23 +133,36 @@ public class BSVMotor : BSMotor
78 // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete 133 // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
79 Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; 134 Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
80 CurrentValue += addAmount; 135 CurrentValue += addAmount;
136
81 returnCurrent = CurrentValue; 137 returnCurrent = CurrentValue;
82 138
83 // The desired value reduces to zero when also reduces the difference with current. 139 // The desired value reduces to zero which also reduces the difference with current.
84 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; 140 // If the decay time is infinite, don't decay at all.
85 TargetValue *= (1f - decayFactor); 141 float decayFactor = 0f;
142 if (TargetValueDecayTimeScale != BSMotor.Infinite)
143 {
144 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
145 TargetValue *= (1f - decayFactor);
146 }
86 147
87 Vector3 frictionFactor = Vector3.Zero; 148 Vector3 frictionFactor = Vector3.Zero;
88 frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; 149 if (FrictionTimescale != BSMotor.InfiniteVector)
89 CurrentValue *= (Vector3.One - frictionFactor); 150 {
151 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
152 // Individual friction components can be 'infinite' so compute each separately.
153 frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
154 frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
155 frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
156 CurrentValue *= (Vector3.One - frictionFactor);
157 }
90 158
91 MDetailLog("{0},BSVMotor.Step,nonZero,{1},origTarget={2},origCurr={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}", 159 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
92 BSScene.DetailLogZero, UseName, origTarget, origCurrVal, 160 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
93 timeStep, TimeScale, addAmount, 161 timeStep, TimeScale, addAmount,
94 TargetValueDecayTimeScale, decayFactor, 162 TargetValueDecayTimeScale, decayFactor,
95 FrictionTimescale, frictionFactor); 163 FrictionTimescale, frictionFactor);
96 MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", 164 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
97 BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, 165 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
98 addAmount, decayFactor, frictionFactor, returnCurrent); 166 addAmount, decayFactor, frictionFactor, returnCurrent);
99 } 167 }
100 else 168 else
@@ -103,7 +171,7 @@ public class BSVMotor : BSMotor
103 CurrentValue = Vector3.Zero; 171 CurrentValue = Vector3.Zero;
104 TargetValue = Vector3.Zero; 172 TargetValue = Vector3.Zero;
105 173
106 MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", 174 MDetailLog("{0}, BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
107 BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); 175 BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
108 176
109 } 177 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index caa6c46..62aaf80 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 253 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 255 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 256 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 257 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
258 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
258 }); 259 });
259 } 260 }
260 261
@@ -329,7 +330,7 @@ public sealed class BSPrim : BSPhysObject
329 330
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 331 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 332 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 333 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 334 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 335 if (Math.Abs(Position.Z - waterHeight) > 0.1f)
335 { 336 {
@@ -347,7 +348,9 @@ public sealed class BSPrim : BSPhysObject
347 if (ret) 348 if (ret)
348 { 349 {
349 // Apply upforce and overcome gravity. 350 // Apply upforce and overcome gravity.
350 AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime); 351 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
352 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
353 AddForce(correctionForce, false, inTaintTime);
351 } 354 }
352 return ret; 355 return ret;
353 } 356 }
@@ -643,9 +646,13 @@ public sealed class BSPrim : BSPhysObject
643 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 646 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
644 647
645 // Collision filter can be set only when the object is in the world 648 // Collision filter can be set only when the object is in the world
646 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) 649 if (PhysBody.collisionGroup != 0 || PhysBody.collisionMask != 0)
647 { 650 {
648 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); 651 if (!BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, (uint)PhysBody.collisionGroup, (uint)PhysBody.collisionMask))
652 {
653 PhysicsScene.Logger.ErrorFormat("{0} Failure setting prim collision mask. localID={1}, grp={2:X}, mask={3:X}",
654 LogHeader, LocalID, PhysBody.collisionGroup, PhysBody.collisionMask);
655 }
649 } 656 }
650 657
651 // Recompute any linkset parameters. 658 // Recompute any linkset parameters.
@@ -684,11 +691,11 @@ public sealed class BSPrim : BSPhysObject
684 // There can be special things needed for implementing linksets 691 // There can be special things needed for implementing linksets
685 Linkset.MakeStatic(this); 692 Linkset.MakeStatic(this);
686 // The activation state is 'disabled' so Bullet will not try to act on it. 693 // The activation state is 'disabled' so Bullet will not try to act on it.
687 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 694 // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
688 // Start it out sleeping and physical actions could wake it up. 695 // Start it out sleeping and physical actions could wake it up.
689 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 696 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
690 697
691 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 698 PhysBody.collisionGroup = CollisionFilterGroups.StaticObjectGroup;
692 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 699 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
693 } 700 }
694 else 701 else
@@ -734,7 +741,7 @@ public sealed class BSPrim : BSPhysObject
734 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 741 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
735 // BulletSimAPI.Activate2(BSBody.ptr, true); 742 // BulletSimAPI.Activate2(BSBody.ptr, true);
736 743
737 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 744 PhysBody.collisionGroup = CollisionFilterGroups.ObjectGroup;
738 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; 745 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
739 } 746 }
740 } 747 }
@@ -762,7 +769,7 @@ public sealed class BSPrim : BSPhysObject
762 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 769 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
763 } 770 }
764 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 771 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
765 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 772 PhysBody.collisionGroup = CollisionFilterGroups.VolumeDetectGroup;
766 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 773 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
767 } 774 }
768 } 775 }
@@ -838,15 +845,6 @@ public sealed class BSPrim : BSPhysObject
838 } 845 }
839 public override OMV.Vector3 RotationalVelocity { 846 public override OMV.Vector3 RotationalVelocity {
840 get { 847 get {
841 /*
842 OMV.Vector3 pv = OMV.Vector3.Zero;
843 // if close to zero, report zero
844 // This is copied from ODE but I'm not sure why it returns zero but doesn't
845 // zero the property in the physics engine.
846 if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
847 return pv;
848 */
849
850 return _rotationalVelocity; 848 return _rotationalVelocity;
851 } 849 }
852 set { 850 set {
@@ -1012,6 +1010,9 @@ public sealed class BSPrim : BSPhysObject
1012 }); 1010 });
1013 } 1011 }
1014 // A torque impulse. 1012 // A torque impulse.
1013 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1014 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1015 // Computed as: angularVelocity += impulse * inertia;
1015 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1016 { 1017 {
1017 OMV.Vector3 applyImpulse = impulse; 1018 OMV.Vector3 applyImpulse = impulse;
@@ -1380,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject
1380 1381
1381 public override void UpdateProperties(EntityProperties entprop) 1382 public override void UpdateProperties(EntityProperties entprop)
1382 { 1383 {
1383 /* 1384 // Updates only for individual prims and for the root object of a linkset.
1384 UpdatedProperties changed = 0; 1385 if (Linkset.IsRoot(this))
1385 // assign to the local variables so the normal set action does not happen
1386 // if (_position != entprop.Position)
1387 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1388 {
1389 _position = entprop.Position;
1390 changed |= UpdatedProperties.Position;
1391 }
1392 // if (_orientation != entprop.Rotation)
1393 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1394 {
1395 _orientation = entprop.Rotation;
1396 changed |= UpdatedProperties.Rotation;
1397 }
1398 // if (_velocity != entprop.Velocity)
1399 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1400 {
1401 _velocity = entprop.Velocity;
1402 changed |= UpdatedProperties.Velocity;
1403 }
1404 // if (_acceleration != entprop.Acceleration)
1405 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1406 {
1407 _acceleration = entprop.Acceleration;
1408 changed |= UpdatedProperties.Acceleration;
1409 }
1410 // if (_rotationalVelocity != entprop.RotationalVelocity)
1411 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1412 {
1413 _rotationalVelocity = entprop.RotationalVelocity;
1414 changed |= UpdatedProperties.RotationalVel;
1415 }
1416 if (changed != 0)
1417 { 1386 {
1418 // Only update the position of single objects and linkset roots 1387 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1419 if (Linkset.IsRoot(this)) 1388 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1389 if (_vehicle.IsActive)
1420 { 1390 {
1421 base.RequestPhysicsterseUpdate(); 1391 entprop.RotationalVelocity = OMV.Vector3.Zero;
1422 } 1392 }
1423 }
1424 */
1425 1393
1426 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1427
1428 // Updates only for individual prims and for the root object of a linkset.
1429 if (Linkset.IsRoot(this))
1430 {
1431 // Assign directly to the local variables so the normal set action does not happen 1394 // Assign directly to the local variables so the normal set action does not happen
1432 _position = entprop.Position; 1395 _position = entprop.Position;
1433 _orientation = entprop.Rotation; 1396 _orientation = entprop.Rotation;
@@ -1436,7 +1399,7 @@ public sealed class BSPrim : BSPhysObject
1436 _rotationalVelocity = entprop.RotationalVelocity; 1399 _rotationalVelocity = entprop.RotationalVelocity;
1437 1400
1438 // The sanity check can change the velocity and/or position. 1401 // The sanity check can change the velocity and/or position.
1439 if (PositionSanityCheck(true)) 1402 if (IsPhysical && PositionSanityCheck(true))
1440 { 1403 {
1441 entprop.Position = _position; 1404 entprop.Position = _position;
1442 entprop.Velocity = _velocity; 1405 entprop.Velocity = _velocity;
@@ -1446,12 +1409,10 @@ public sealed class BSPrim : BSPhysObject
1446 LastEntityProperties = CurrentEntityProperties; 1409 LastEntityProperties = CurrentEntityProperties;
1447 CurrentEntityProperties = entprop; 1410 CurrentEntityProperties = entprop;
1448 1411
1449 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; 1412 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1450 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", 1413 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1451 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); 1414 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1452 1415
1453 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1454
1455 base.RequestPhysicsterseUpdate(); 1416 base.RequestPhysicsterseUpdate();
1456 } 1417 }
1457 /* 1418 /*
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 805e670..f72bd74 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -96,6 +96,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
96 public long SimulationStep { get { return m_simulationStep; } } 96 public long SimulationStep { get { return m_simulationStep; } }
97 private int m_taintsToProcessPerStep; 97 private int m_taintsToProcessPerStep;
98 98
99 public delegate void PreStepAction(float timeStep);
100 public event PreStepAction BeforeStep;
101
99 // A value of the time now so all the collision and update routines do not have to get their own 102 // A value of the time now so all the collision and update routines do not have to get their own
100 // Set to 'now' just before all the prims and actors are called for collisions and updates 103 // Set to 'now' just before all the prims and actors are called for collisions and updates
101 public int SimulationNowTime { get; private set; } 104 public int SimulationNowTime { get; private set; }
@@ -127,7 +130,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
127 public const uint GROUNDPLANE_ID = 1; 130 public const uint GROUNDPLANE_ID = 1;
128 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here 131 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
129 132
130 private float m_waterLevel; 133 public float SimpleWaterLevel { get; set; }
131 public BSTerrainManager TerrainManager { get; private set; } 134 public BSTerrainManager TerrainManager { get; private set; }
132 135
133 public ConfigurationParameters Params 136 public ConfigurationParameters Params
@@ -182,6 +185,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
182 private string m_physicsLoggingDir; 185 private string m_physicsLoggingDir;
183 private string m_physicsLoggingPrefix; 186 private string m_physicsLoggingPrefix;
184 private int m_physicsLoggingFileMinutes; 187 private int m_physicsLoggingFileMinutes;
188 private bool m_physicsLoggingDoFlush;
185 // 'true' of the vehicle code is to log lots of details 189 // 'true' of the vehicle code is to log lots of details
186 public bool VehicleLoggingEnabled { get; private set; } 190 public bool VehicleLoggingEnabled { get; private set; }
187 191
@@ -290,6 +294,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
290 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 294 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
291 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); 295 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
292 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 296 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
297 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
293 // Very detailed logging for vehicle debugging 298 // Very detailed logging for vehicle debugging
294 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 299 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
295 300
@@ -485,8 +490,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
485 ProcessTaints(); 490 ProcessTaints();
486 491
487 // Some of the prims operate with special vehicle properties 492 // Some of the prims operate with special vehicle properties
488 ProcessVehicles(timeStep); 493 DoPreStepActions(timeStep);
489 ProcessTaints(); // the vehicles might have added taints 494
495 // the prestep actions might have added taints
496 ProcessTaints();
490 497
491 // step the physical world one interval 498 // step the physical world one interval
492 m_simulationStep++; 499 m_simulationStep++;
@@ -515,9 +522,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
515 collidersCount = 0; 522 collidersCount = 0;
516 } 523 }
517 524
518 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 525 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
519 526
520 // Get a value for 'now' so all the collision and update routines don't have to get their own 527 // Get a value for 'now' so all the collision and update routines don't have to get their own.
521 SimulationNowTime = Util.EnvironmentTickCount(); 528 SimulationNowTime = Util.EnvironmentTickCount();
522 529
523 // If there were collisions, process them by sending the event to the prim. 530 // If there were collisions, process them by sending the event to the prim.
@@ -563,6 +570,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
563 ObjectsWithCollisions.Remove(po); 570 ObjectsWithCollisions.Remove(po);
564 ObjectsWithNoMoreCollisions.Clear(); 571 ObjectsWithNoMoreCollisions.Clear();
565 } 572 }
573 // Done with collisions.
566 574
567 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 575 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
568 if (updatedEntityCount > 0) 576 if (updatedEntityCount > 0)
@@ -586,9 +594,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
586 594
587 // The physics engine returns the number of milliseconds it simulated this call. 595 // The physics engine returns the number of milliseconds it simulated this call.
588 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 596 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
589 // We multiply by 55 to give a recognizable running rate (55 or less). 597 // Multiply by 55 to give a nominal frame rate of 55.
590 return numSubSteps * m_fixedTimeStep * 1000 * 55; 598 return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
591 // return timeStep * 1000 * 55;
592 } 599 }
593 600
594 // Something has collided 601 // Something has collided
@@ -634,12 +641,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
634 641
635 public override void SetWaterLevel(float baseheight) 642 public override void SetWaterLevel(float baseheight)
636 { 643 {
637 m_waterLevel = baseheight; 644 SimpleWaterLevel = baseheight;
638 }
639 // Someday....
640 public float GetWaterLevelAtXYZ(Vector3 loc)
641 {
642 return m_waterLevel;
643 } 645 }
644 646
645 public override void DeleteTerrain() 647 public override void DeleteTerrain()
@@ -910,6 +912,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
910 } 912 }
911 } 913 }
912 914
915 private void DoPreStepActions(float timeStep)
916 {
917 ProcessVehicles(timeStep);
918
919 PreStepAction actions = BeforeStep;
920 if (actions != null)
921 actions(timeStep);
922
923 }
924
913 // Some prims have extra vehicle actions 925 // Some prims have extra vehicle actions
914 // Called at taint time! 926 // Called at taint time!
915 private void ProcessVehicles(float timeStep) 927 private void ProcessVehicles(float timeStep)
@@ -974,6 +986,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
974 // Should handle fetching the right type from the ini file and converting it. 986 // Should handle fetching the right type from the ini file and converting it.
975 // -- a delegate for getting the value as a float 987 // -- a delegate for getting the value as a float
976 // -- a delegate for setting the value from a float 988 // -- a delegate for setting the value from a float
989 // -- an optional delegate to update the value in the world. Most often used to
990 // push the new value to an in-world object.
977 // 991 //
978 // The single letter parameters for the delegates are: 992 // The single letter parameters for the delegates are:
979 // s = BSScene 993 // s = BSScene
@@ -1172,7 +1186,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1172 (s) => { return s.m_params[0].avatarFriction; }, 1186 (s) => { return s.m_params[0].avatarFriction; },
1173 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), 1187 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1174 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", 1188 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1175 0.99f, 1189 10.0f,
1176 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, 1190 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1177 (s) => { return s.m_params[0].avatarStandingFriction; }, 1191 (s) => { return s.m_params[0].avatarStandingFriction; },
1178 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), 1192 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
@@ -1493,7 +1507,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1493 { 1507 {
1494 PhysicsLogging.Write(msg, args); 1508 PhysicsLogging.Write(msg, args);
1495 // Add the Flush() if debugging crashes. Gets all the messages written out. 1509 // Add the Flush() if debugging crashes. Gets all the messages written out.
1496 // PhysicsLogging.Flush(); 1510 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
1497 } 1511 }
1498 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 1512 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1499 public const string DetailLogZero = "0000000000"; 1513 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..e77b6ba 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); 65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); 66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67 67
68 private bool DDetail = false;
69
68 public BSShapeCollection(BSScene physScene) 70 public BSShapeCollection(BSScene physScene)
69 { 71 {
70 PhysicsScene = physScene; 72 PhysicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging
76 // statements can be commented/removed.
77 DDetail = true;
71 } 78 }
72 79
73 public void Dispose() 80 public void Dispose()
@@ -126,13 +133,13 @@ public sealed class BSShapeCollection : IDisposable
126 { 133 {
127 lock (m_collectionActivityLock) 134 lock (m_collectionActivityLock)
128 { 135 {
129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); 136 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() 137 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
131 { 138 {
132 if (!BulletSimAPI.IsInWorld2(body.ptr)) 139 if (!BulletSimAPI.IsInWorld2(body.ptr))
133 { 140 {
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 141 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); 142 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
136 } 143 }
137 }); 144 });
138 } 145 }
@@ -149,7 +156,7 @@ public sealed class BSShapeCollection : IDisposable
149 { 156 {
150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() 157 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
151 { 158 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", 159 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
153 body.ID, body, inTaintTime); 160 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up. 161 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body); 162 if (bodyCallback != null) bodyCallback(body);
@@ -157,7 +164,7 @@ public sealed class BSShapeCollection : IDisposable
157 if (BulletSimAPI.IsInWorld2(body.ptr)) 164 if (BulletSimAPI.IsInWorld2(body.ptr))
158 { 165 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 166 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); 167 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 } 168 }
162 169
163 // Zero any reference to the shape so it is not freed when the body is deleted. 170 // Zero any reference to the shape so it is not freed when the body is deleted.
@@ -184,7 +191,7 @@ public sealed class BSShapeCollection : IDisposable
184 { 191 {
185 // There is an existing instance of this mesh. 192 // There is an existing instance of this mesh.
186 meshDesc.referenceCount++; 193 meshDesc.referenceCount++;
187 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", 194 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
188 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 195 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
189 } 196 }
190 else 197 else
@@ -194,7 +201,7 @@ public sealed class BSShapeCollection : IDisposable
194 meshDesc.shapeKey = shape.shapeKey; 201 meshDesc.shapeKey = shape.shapeKey;
195 // We keep a reference to the underlying IMesh data so a hull can be built 202 // We keep a reference to the underlying IMesh data so a hull can be built
196 meshDesc.referenceCount = 1; 203 meshDesc.referenceCount = 1;
197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 204 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
198 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 205 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
199 ret = true; 206 ret = true;
200 } 207 }
@@ -207,7 +214,7 @@ public sealed class BSShapeCollection : IDisposable
207 { 214 {
208 // There is an existing instance of this hull. 215 // There is an existing instance of this hull.
209 hullDesc.referenceCount++; 216 hullDesc.referenceCount++;
210 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", 217 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 218 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
212 } 219 }
213 else 220 else
@@ -216,7 +223,7 @@ public sealed class BSShapeCollection : IDisposable
216 hullDesc.ptr = shape.ptr; 223 hullDesc.ptr = shape.ptr;
217 hullDesc.shapeKey = shape.shapeKey; 224 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 225 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 226 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 227 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true; 228 ret = true;
222 229
@@ -246,7 +253,7 @@ public sealed class BSShapeCollection : IDisposable
246 if (shape.isNativeShape) 253 if (shape.isNativeShape)
247 { 254 {
248 // Native shapes are not tracked and are released immediately 255 // Native shapes are not tracked and are released immediately
249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 256 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 257 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape); 258 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 259 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
@@ -286,7 +293,7 @@ public sealed class BSShapeCollection : IDisposable
286 if (shapeCallback != null) shapeCallback(shape); 293 if (shapeCallback != null) shapeCallback(shape);
287 meshDesc.lastReferenced = System.DateTime.Now; 294 meshDesc.lastReferenced = System.DateTime.Now;
288 Meshes[shape.shapeKey] = meshDesc; 295 Meshes[shape.shapeKey] = meshDesc;
289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", 296 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
290 BSScene.DetailLogZero, shape, meshDesc.referenceCount); 297 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
291 298
292 } 299 }
@@ -307,7 +314,7 @@ public sealed class BSShapeCollection : IDisposable
307 314
308 hullDesc.lastReferenced = System.DateTime.Now; 315 hullDesc.lastReferenced = System.DateTime.Now;
309 Hulls[shape.shapeKey] = hullDesc; 316 Hulls[shape.shapeKey] = hullDesc;
310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", 317 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
311 BSScene.DetailLogZero, shape, hullDesc.referenceCount); 318 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 } 319 }
313 } 320 }
@@ -325,13 +332,13 @@ public sealed class BSShapeCollection : IDisposable
325 // Failed the sanity check!! 332 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", 333 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
327 LogHeader, shape.type, shape.ptr.ToString("X")); 334 LogHeader, shape.type, shape.ptr.ToString("X"));
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", 335 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); 336 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
330 return; 337 return;
331 } 338 }
332 339
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 340 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); 341 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335 342
336 for (int ii = numChildren - 1; ii >= 0; ii--) 343 for (int ii = numChildren - 1; ii >= 0; ii--)
337 { 344 {
@@ -379,7 +386,7 @@ public sealed class BSShapeCollection : IDisposable
379 } 386 }
380 } 387 }
381 388
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 389 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 390
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) 391 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 392 {
@@ -410,7 +417,7 @@ public sealed class BSShapeCollection : IDisposable
410 // an avatar capsule is close to a native shape (it is not shared) 417 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, 418 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
412 FixedShapeKey.KEY_CAPSULE, shapeCallback); 419 FixedShapeKey.KEY_CAPSULE, shapeCallback);
413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); 420 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true; 421 ret = true;
415 haveShape = true; 422 haveShape = true;
416 } 423 }
@@ -420,7 +427,7 @@ public sealed class BSShapeCollection : IDisposable
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) 427 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 428 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 429 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 430 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true; 431 haveShape = true;
425 } 432 }
426 433
@@ -465,7 +472,7 @@ public sealed class BSShapeCollection : IDisposable
465 { 472 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 473 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 474 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 475 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape); 476 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 477 }
471 } 478 }
@@ -479,7 +486,7 @@ public sealed class BSShapeCollection : IDisposable
479 { 486 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 487 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 488 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 489 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape); 490 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 491 }
485 } 492 }
@@ -504,13 +511,13 @@ public sealed class BSShapeCollection : IDisposable
504 { 511 {
505 // Update prim.BSShape to reference a hull of this shape. 512 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 513 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 514 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 515 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 516 }
510 else 517 else
511 { 518 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 519 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 520 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 521 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 522 }
516 return ret; 523 return ret;
@@ -528,7 +535,7 @@ public sealed class BSShapeCollection : IDisposable
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 535 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 536
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 537 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 538 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 539 prim.LocalID, newShape, prim.Scale);
533 540
534 prim.PhysShape = newShape; 541 prim.PhysShape = newShape;
@@ -554,7 +561,7 @@ public sealed class BSShapeCollection : IDisposable
554 newShape = new BulletShape( 561 newShape = new BulletShape(
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 562 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
556 , shapeType); 563 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 564 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 565 }
559 else 566 else
560 { 567 {
@@ -589,7 +596,7 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 596 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 597 return false;
591 598
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 599 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 600 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
594 601
595 // Since we're recreating new, get rid of the reference to the previous shape 602 // Since we're recreating new, get rid of the reference to the previous shape
@@ -620,8 +627,7 @@ public sealed class BSShapeCollection : IDisposable
620 } 627 }
621 else 628 else
622 { 629 {
623 // Pass false for physicalness as this creates some sort of bounding box which we don't need 630 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
625 631
626 if (meshData != null) 632 if (meshData != null)
627 { 633 {
@@ -663,7 +669,7 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 669 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 670 return false;
665 671
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 672 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 673 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 674
669 // Remove usage of the previous shape. 675 // Remove usage of the previous shape.
@@ -694,8 +700,8 @@ public sealed class BSShapeCollection : IDisposable
694 else 700 else
695 { 701 {
696 // Build a new hull in the physical world 702 // Build a new hull in the physical world
697 // Pass false for physicalness as this creates some sort of bounding box which we don't need 703 // Pass true for physicalness as this creates some sort of bounding box which we don't need
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 704 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
699 if (meshData != null) 705 if (meshData != null)
700 { 706 {
701 707
@@ -809,7 +815,7 @@ public sealed class BSShapeCollection : IDisposable
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 815 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 816 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 817 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 818 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 819 prim.LocalID, cShape, prim.PhysShape);
814 820
815 prim.PhysShape = cShape; 821 prim.PhysShape = cShape;
@@ -936,13 +942,13 @@ public sealed class BSShapeCollection : IDisposable
936 { 942 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 943 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 944 prim.LocalID, prim.RawPosition, prim.RawOrientation);
939 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 945 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
940 } 946 }
941 else 947 else
942 { 948 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 949 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 950 prim.LocalID, prim.RawPosition, prim.RawOrientation);
945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 951 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
946 } 952 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr); 953 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 954
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index 1450f66..83b9c37 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -121,8 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
121 // redo its bounding box now that it is in the world 121 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
123 123
124 BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, 124 BulletSimAPI.SetCollisionGroupMask2(m_mapInfo.terrainBody.ptr,
125 (uint)CollisionFilterGroups.TerrainFilter, 125 (uint)CollisionFilterGroups.TerrainGroup,
126 (uint)CollisionFilterGroups.TerrainMask); 126 (uint)CollisionFilterGroups.TerrainMask);
127 127
128 // Make it so the terrain will not move or be considered for movement. 128 // Make it so the terrain will not move or be considered for movement.
@@ -148,7 +148,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
148 } 148 }
149 149
150 // The passed position is relative to the base of the region. 150 // The passed position is relative to the base of the region.
151 public override float GetHeightAtXYZ(Vector3 pos) 151 public override float GetTerrainHeightAtXYZ(Vector3 pos)
152 { 152 {
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154 154
@@ -166,5 +166,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
166 } 166 }
167 return ret; 167 return ret;
168 } 168 }
169
170 // The passed position is relative to the base of the region.
171 public override float GetWaterLevelAtXYZ(Vector3 pos)
172 {
173 return PhysicsScene.SimpleWaterLevel;
174 }
169} 175}
170} 176}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index cd623f1..83df360 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable
62 ID = id; 62 ID = id;
63 } 63 }
64 public abstract void Dispose(); 64 public abstract void Dispose();
65 public abstract float GetHeightAtXYZ(Vector3 pos); 65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
66} 67}
67 68
68// ========================================================================================== 69// ==========================================================================================
@@ -75,6 +76,7 @@ public sealed class BSTerrainManager
75 public const float HEIGHT_INITIALIZATION = 24.987f; 76 public const float HEIGHT_INITIALIZATION = 24.987f;
76 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; 77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
77 public const float HEIGHT_GETHEIGHT_RET = 24.765f; 78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
78 80
79 // If the min and max height are equal, we reduce the min by this 81 // If the min and max height are equal, we reduce the min by this
80 // amount to make sure that a bounding box is built for the terrain. 82 // amount to make sure that a bounding box is built for the terrain.
@@ -138,8 +140,8 @@ public sealed class BSTerrainManager
138 // Ground plane does not move 140 // Ground plane does not move
139 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 141 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
140 // Everything collides with the ground plane. 142 // Everything collides with the ground plane.
141 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 143 BulletSimAPI.SetCollisionGroupMask2(m_groundPlane.ptr,
142 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 144 (uint)CollisionFilterGroups.GroundPlaneGroup, (uint)CollisionFilterGroups.GroundPlaneMask);
143 145
144 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 146 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
145 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 147 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
@@ -358,7 +360,7 @@ public sealed class BSTerrainManager
358 BSTerrainPhys physTerrain; 360 BSTerrainPhys physTerrain;
359 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) 361 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
360 { 362 {
361 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 363 ret = physTerrain.GetTerrainHeightAtXYZ(loc - terrainBaseXYZ);
362 } 364 }
363 else 365 else
364 { 366 {
@@ -370,6 +372,33 @@ public sealed class BSTerrainManager
370 return ret; 372 return ret;
371 } 373 }
372 374
375 public float GetWaterLevelAtXYZ(Vector3 pos)
376 {
377 float ret = WATER_HEIGHT_GETHEIGHT_RET;
378
379 float tX = pos.X;
380 float tY = pos.Y;
381
382 Vector3 terrainBaseXYZ = Vector3.Zero;
383 terrainBaseXYZ.X = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
384 terrainBaseXYZ.Y = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
385
386 lock (m_terrains)
387 {
388 BSTerrainPhys physTerrain;
389 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
390 {
391 ret = physTerrain.GetWaterLevelAtXYZ(pos);
392 }
393 else
394 {
395 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
396 LogHeader, PhysicsScene.RegionName, tX, tY);
397 }
398 }
399 return ret;
400 }
401
373 // Although no one seems to check this, I do support combining. 402 // Although no one seems to check this, I do support combining.
374 public bool SupportsCombining() 403 public bool SupportsCombining()
375 { 404 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index d7afdeb..6ce767d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 // Something is very messed up and a crash is in our future. 88 // Something is very messed up and a crash is in our future.
89 return; 89 return;
90 } 90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
91 93
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
93 indicesCount, indices, verticesCount, vertices), 95 indicesCount, indices, verticesCount, vertices),
94 BSPhysicsShapeType.SHAPE_MESH); 96 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero) 97 if (m_terrainShape.ptr == IntPtr.Zero)
96 { 98 {
@@ -122,14 +124,14 @@ public sealed class BSTerrainMesh : BSTerrainPhys
122 // Static objects are not very massive. 124 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 125 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
124 126
125 // Return the new terrain to the world of physical objects 127 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 128 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
127 129
128 // redo its bounding box now that it is in the world 130 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
130 132
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 133 BulletSimAPI.SetCollisionGroupMask2(m_terrainBody.ptr,
132 (uint)CollisionFilterGroups.TerrainFilter, 134 (uint)CollisionFilterGroups.TerrainGroup,
133 (uint)CollisionFilterGroups.TerrainMask); 135 (uint)CollisionFilterGroups.TerrainMask);
134 136
135 // Make it so the terrain will not move or be considered for movement. 137 // Make it so the terrain will not move or be considered for movement.
@@ -146,7 +148,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
146 } 148 }
147 } 149 }
148 150
149 public override float GetHeightAtXYZ(Vector3 pos) 151 public override float GetTerrainHeightAtXYZ(Vector3 pos)
150 { 152 {
151 // For the moment use the saved heightmap to get the terrain height. 153 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position. 154 // TODO: raycast downward to find the true terrain below the position.
@@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
167 return ret; 169 return ret;
168 } 170 }
169 171
172 // The passed position is relative to the base of the region.
173 public override float GetWaterLevelAtXYZ(Vector3 pos)
174 {
175 return PhysicsScene.SimpleWaterLevel;
176 }
177
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 178 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created. 179 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh( 180 public static bool ConvertHeightmapToMesh(
@@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
188 // Simple mesh creation which assumes magnification == 1. 196 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result. 197 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190 198
199 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
200 // from zero to <= sizeX). The triangle indices are then generated as two triangles
201 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
202 // column of vertices are used to complete the triangles of the last row and column
203 // of the heightmap.
191 try 204 try
192 { 205 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge. 206 // One vertice per heightmap value plus the vertices off the top and bottom edge.
@@ -200,16 +213,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
200 float magY = (float)sizeY / extentY; 213 float magY = (float)sizeY / extentY;
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 214 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 215 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
216 float minHeight = float.MaxValue;
203 // Note that sizeX+1 vertices are created since there is land between this and the next region. 217 // Note that sizeX+1 vertices are created since there is land between this and the next region.
204 for (int yy = 0; yy <= sizeY; yy++) 218 for (int yy = 0; yy <= sizeY; yy++)
205 { 219 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times 220 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
207 { 221 {
208 int offset = yy * sizeX + xx; 222 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column 223 // Extend the height with the height from the last row or column
210 if (yy == sizeY) offset -= sizeX; 224 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1; 225 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset]; 226 float height = heightMap[offset];
227 minHeight = Math.Min(minHeight, height);
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 228 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 229 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z; 230 vertices[verticesCount + 2] = height + extentBase.Z;
@@ -222,7 +237,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
222 { 237 {
223 for (int xx = 0; xx < sizeX; xx++) 238 for (int xx = 0; xx < sizeX; xx++)
224 { 239 {
225 int offset = yy * sizeX + xx; 240 int offset = yy * (sizeX + 1) + xx;
226 // Each vertices is presumed to be the upper left corner of a box of two triangles 241 // Each vertices is presumed to be the upper left corner of a box of two triangles
227 indices[indicesCount + 0] = offset; 242 indices[indicesCount + 0] = offset;
228 indices[indicesCount + 1] = offset + 1; 243 indices[indicesCount + 1] = offset + 1;
@@ -233,6 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
233 indicesCount += 6; 248 indicesCount += 6;
234 } 249 }
235 } 250 }
251
236 ret = true; 252 ret = true;
237 } 253 }
238 catch (Exception e) 254 catch (Exception e)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 12baee9..2671995 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -57,12 +57,12 @@ public struct BulletBody
57 { 57 {
58 ID = id; 58 ID = id;
59 ptr = xx; 59 ptr = xx;
60 collisionFilter = 0; 60 collisionGroup = 0;
61 collisionMask = 0; 61 collisionMask = 0;
62 } 62 }
63 public IntPtr ptr; 63 public IntPtr ptr;
64 public uint ID; 64 public uint ID;
65 public CollisionFilterGroups collisionFilter; 65 public CollisionFilterGroups collisionGroup;
66 public CollisionFilterGroups collisionMask; 66 public CollisionFilterGroups collisionMask;
67 public override string ToString() 67 public override string ToString()
68 { 68 {
@@ -71,10 +71,10 @@ public struct BulletBody
71 buff.Append(ID.ToString()); 71 buff.Append(ID.ToString());
72 buff.Append(",p="); 72 buff.Append(",p=");
73 buff.Append(ptr.ToString("X")); 73 buff.Append(ptr.ToString("X"));
74 if (collisionFilter != 0 || collisionMask != 0) 74 if (collisionGroup != 0 || collisionMask != 0)
75 { 75 {
76 buff.Append(",f="); 76 buff.Append(",g=");
77 buff.Append(collisionFilter.ToString("X")); 77 buff.Append(collisionGroup.ToString("X"));
78 buff.Append(",m="); 78 buff.Append(",m=");
79 buff.Append(collisionMask.ToString("X")); 79 buff.Append(collisionMask.ToString("X"));
80 } 80 }
@@ -357,9 +357,10 @@ public enum CollisionFlags : uint
357 CF_CHARACTER_OBJECT = 1 << 4, 357 CF_CHARACTER_OBJECT = 1 << 4,
358 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, 358 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
359 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 359 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
360 // Following used by BulletSim to control collisions 360 // Following used by BulletSim to control collisions and updates
361 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 361 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
362 BS_FLOATS_ON_WATER = 1 << 11, 362 BS_FLOATS_ON_WATER = 1 << 11,
363 BS_VEHICLE_COLLISIONS = 1 << 12,
363 BS_NONE = 0, 364 BS_NONE = 0,
364 BS_ALL = 0xFFFFFFFF, 365 BS_ALL = 0xFFFFFFFF,
365 366
@@ -376,36 +377,36 @@ public enum CollisionFilterGroups : uint
376 // Don't use the bit definitions!! Define the use in a 377 // Don't use the bit definitions!! Define the use in a
377 // filter/mask definition below. This way collision interactions 378 // filter/mask definition below. This way collision interactions
378 // are more easily debugged. 379 // are more easily debugged.
379 BNoneFilter = 0, 380 BNoneGroup = 0,
380 BDefaultFilter = 1 << 0, 381 BDefaultGroup = 1 << 0,
381 BStaticFilter = 1 << 1, 382 BStaticGroup = 1 << 1,
382 BKinematicFilter = 1 << 2, 383 BKinematicGroup = 1 << 2,
383 BDebrisFilter = 1 << 3, 384 BDebrisGroup = 1 << 3,
384 BSensorTrigger = 1 << 4, 385 BSensorTrigger = 1 << 4,
385 BCharacterFilter = 1 << 5, 386 BCharacterGroup = 1 << 5,
386 BAllFilter = 0xFFFFFFFF, 387 BAllGroup = 0xFFFFFFFF,
387 // Filter groups defined by BulletSim 388 // Filter groups defined by BulletSim
388 BGroundPlaneFilter = 1 << 10, 389 BGroundPlaneGroup = 1 << 10,
389 BTerrainFilter = 1 << 11, 390 BTerrainGroup = 1 << 11,
390 BRaycastFilter = 1 << 12, 391 BRaycastGroup = 1 << 12,
391 BSolidFilter = 1 << 13, 392 BSolidGroup = 1 << 13,
392 BLinksetFilter = 1 << 14, 393 BLinksetGroup = 1 << 14,
393 394
394 // The collsion filters and masked are defined in one place -- don't want them scattered 395 // The collsion filters and masked are defined in one place -- don't want them scattered
395 AvatarFilter = BCharacterFilter, 396 AvatarGroup = BCharacterGroup,
396 AvatarMask = BAllFilter, 397 AvatarMask = BAllGroup,
397 ObjectFilter = BSolidFilter, 398 ObjectGroup = BSolidGroup,
398 ObjectMask = BAllFilter, 399 ObjectMask = BAllGroup,
399 StaticObjectFilter = BStaticFilter, 400 StaticObjectGroup = BStaticGroup,
400 StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other 401 StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
401 LinksetFilter = BLinksetFilter, 402 LinksetGroup = BLinksetGroup,
402 LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other 403 LinksetMask = BAllGroup & ~BLinksetGroup, // linkset objects don't collide with each other
403 VolumeDetectFilter = BSensorTrigger, 404 VolumeDetectGroup = BSensorTrigger,
404 VolumeDetectMask = ~BSensorTrigger, 405 VolumeDetectMask = ~BSensorTrigger,
405 TerrainFilter = BTerrainFilter, 406 TerrainGroup = BTerrainGroup,
406 TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide 407 TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
407 GroundPlaneFilter = BGroundPlaneFilter, 408 GroundPlaneGroup = BGroundPlaneGroup,
408 GroundPlaneMask = BAllFilter 409 GroundPlaneMask = BAllGroup
409 410
410}; 411};
411 412
@@ -945,7 +946,7 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
945public static extern int GetNumConstraintRefs2(IntPtr obj); 946public static extern int GetNumConstraintRefs2(IntPtr obj);
946 947
947[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 948[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
948public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); 949public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
949 950
950// ===================================================================================== 951// =====================================================================================
951// btCollisionShape entries 952// btCollisionShape entries
@@ -1007,13 +1008,16 @@ public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1007public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); 1008public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1008 1009
1009[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1010[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1011public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1012
1013[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1010public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); 1014public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1011 1015
1012[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1016[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1013public static extern void DumpAllInfo2(IntPtr sim); 1017public static extern void DumpActivationInfo2(IntPtr sim);
1014 1018
1015[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1019[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1016public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); 1020public static extern void DumpAllInfo2(IntPtr sim);
1017 1021
1018[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1022[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1019public static extern void DumpPhysicsStatistics2(IntPtr sim); 1023public static extern void DumpPhysicsStatistics2(IntPtr sim);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
new file mode 100755
index 0000000..d51003c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -0,0 +1,142 @@
1CRASHES
2=================================================
320121129.1411: editting/moving phys object across region boundries causes crash
4 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
520121128.1600: mesh object not rezzing (no physics mesh).
6 Causes many errors. Doesn't stop after first error with box shape.
7 Eventually crashes when deleting the object.
8
9VEHICLES TODO LIST:
10=================================================
11Neb car jiggling left and right
12 Happens on terrain and any other mesh object. Flat cubes are much smoother.
13Vehicles (Move smoothly)
14Add vehicle collisions so IsColliding is properly reported.
15 Needed for banking, limitMotorUp, movementLimiting, ...
16Some vehicles should not be able to turn if no speed or off ground.
17For limitMotorUp, use raycast down to find if vehicle is in the air.
18Implement function efficiency for lineaar and angular motion.
19Should vehicle angular/linear movement friction happen after all the components
20 or does it only apply to the basic movement?
21After getting off a vehicle, the root prim is phantom (can be walked through)
22 Need to force a position update for the root prim after compound shape destruction
23Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
24Implement referenceFrame for all the motion routines.
25Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
26
27BULLETSIM TODO LIST:
28=================================================
29Disable activity of passive linkset children.
30 Since the linkset is a compound object, the old prims are left lying
31 around and need to be phantomized so they don't collide, ...
32Scenes with hundred of thousands of static objects take a lot of physics CPU time.
33BSPrim.Force should set a continious force on the prim. The force should be
34 applied each tick. Some limits?
35Single prim vehicles don't seem to properly vehiclize.
36Gun sending shooter flying.
37Collision margin (gap between physical objects lying on each other)
38Boundry checking (crashes related to crossing boundry)
39 Add check for border edge position for avatars and objects.
40 Verify the events are created for border crossings.
41Avatar rotation (check out changes to ScenePresence for physical rotation)
42Avatar running (what does phys engine need to do?)
43Small physical objects do not interact correctly
44 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
45 The chain will fall apart and pairs will dance around on ground
46 Chains of 1x1x.2 will stay connected but will dance.
47 Chains above 2x2x.4 are move stable and get stablier as torui get larger.
48Add material type linkage and input all the material property definitions.
49 Skeleton classes and table are in the sources but are not filled or used.
50Add PID motor for avatar movement (slow to stop, ...)
51setForce should set a constant force. Different than AddImpulse.
52Implement raycast.
53Implement ShapeCollection.Dispose()
54Implement water as a plain so raycasting and collisions can happen with same.
55
56Find/remove avatar collision with ID=0.
57Test avatar walking up stairs. How does compare with SL.
58 Radius of the capsule affects ability to climb edges.
59Tune terrain/object friction to be closer to SL.
60Debounce avatar contact so legs don't keep folding up when standing.
61Implement LSL physics controls. Like STATUS_ROTATE_X.
62Add border extensions to terrain to help region crossings and objects leaving region.
63
64Speed up creation of large physical linksets
65 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
66Performance test with lots of avatars. Can BulletSim support a thousand?
67Optimize collisions in C++: only send up to the object subscribed to collisions.
68 Use collision subscription and remove the collsion(A,B) and collision(B,A)
69Check whether SimMotionState needs large if statement (see TODO).
70
71Implement 'top colliders' info.
72Avatar jump
73Performance measurement and changes to make quicker.
74Implement detailed physics stats (GetStats()).
75
76Eliminate collisions between objects in a linkset. (LinksetConstraint)
77 Have UserPointer point to struct with localID and linksetID?
78 Objects in original linkset still collide with each other?
79
80Measure performance improvement from hulls
81Test not using ghost objects for volume detect implementation.
82Performance of closures and delegates for taint processing
83 Are there faster ways?
84 Is any slowdown introduced by the existing implementation significant?
85Is there are more efficient method of implementing pre and post step actions?
86 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
87
88Physics Arena central pyramid: why is one side permiable?
89
90INTERNAL IMPROVEMENT/CLEANUP
91=================================================
92Remove unused fields from ShapeData (not used in API2)
93Breakout code for mesh/hull/compound/native into separate BSShape* classes
94 Standardize access to building and reference code.
95 The skeleton classes are in the sources but are not complete or linked in.
96Generalize Dynamics and PID with standardized motors.
97Generalize Linkset and vehicles into PropertyManagers
98 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
99 Possibly generalized a 'pre step action' registration.
100Complete implemention of preStepActions
101 Replace vehicle step call with prestep event.
102 Is there a need for postStepActions? postStepTaints?
103Implement linkset by setting position of children when root updated. (LinksetManual)
104 Linkset implementation using manual prim movement.
105LinkablePrim class? Would that simplify/centralize the linkset logic?
106BSScene.UpdateParameterSet() is broken. How to set params on objects?
107Remove HeightmapInfo from terrain specification.
108 Since C++ code does not need terrain height, this structure et al are not needed.
109Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
110 bob at the water level. BSPrim.PositionSanityCheck().
111
112THREADING
113=================================================
114Do taint action immediately if not actually executing Bullet.
115 Add lock around Bullet execution and just do taint actions if simulation is not happening.
116
117DONE DONE DONE DONE
118=================================================
119Cleanup code in BSDynamics by using motors. (Resolution: started)
120Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
121 Would have better and adjustable resolution.
122Build terrain mesh so heighmap is height of the center of the square meter.
123 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
124Terrain as mesh. (Resolution: done)
125How are static linksets seen by the physics engine?
126 Resolution: they are not linked in physics. When moved, all the children are repositioned.
127Convert BSCharacter to use all API2 (Resolution: done)
128Avatar pushing difficult (too heavy?)
129Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
130Remove old code in DLL (all non-API2 stuff). (Resolution: done)
131Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
132Debug Bullet internal stats output (why is timing all wrong?)
133 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
134Implement meshes or just verify that they work. (Resolution: they do!)
135Do prim hash codes work for sculpties and meshes? (Resolution: yes)
136Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
137 Compound shapes will need the LocalID in the shapes and collision
138 processing to get it from there.
139Light cycle falling over when driving (Resolution: implemented VerticalAttractor)
140Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
141Package Bullet source mods for Bullet internal stats output
142 (Resolution: move code into WorldData.h rather than relying on patches) \ No newline at end of file
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs
index 3a9ca1b..10c4bd3 100644
--- a/OpenSim/Region/Physics/Manager/IMesher.cs
+++ b/OpenSim/Region/Physics/Manager/IMesher.cs
@@ -36,6 +36,7 @@ namespace OpenSim.Region.Physics.Manager
36 { 36 {
37 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); 37 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); 38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache);
39 } 40 }
40 41
41 // Values for level of detail to be passed to the mesher. 42 // Values for level of detail to be passed to the mesher.
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
index ba19db6..270d2ec 100644
--- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs
+++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
@@ -64,11 +64,16 @@ namespace OpenSim.Region.Physics.Manager
64 { 64 {
65 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 65 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
66 { 66 {
67 return CreateMesh(primName, primShape, size, lod, false); 67 return CreateMesh(primName, primShape, size, lod, false, false);
68 } 68 }
69 69
70 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 70 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
71 { 71 {
72 return CreateMesh(primName, primShape, size, lod, false, false);
73 }
74
75 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
76 {
72 // Remove the reference to the encoded JPEG2000 data so it can be GCed 77 // Remove the reference to the encoded JPEG2000 data so it can be GCed
73 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; 78 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes;
74 79
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index 3bd15ce..8145d61 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -321,7 +321,10 @@ namespace OpenSim.Region.Physics.Meshing
321 321
322 if (primShape.SculptData.Length <= 0) 322 if (primShape.SculptData.Length <= 0)
323 { 323 {
324 m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); 324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
325 // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
326 // The first time will always call with unloaded SculptData if this needs to be uploaded.
327// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
325 return false; 328 return false;
326 } 329 }
327 330
@@ -699,11 +702,16 @@ namespace OpenSim.Region.Physics.Meshing
699 702
700 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
701 { 704 {
702 return CreateMesh(primName, primShape, size, lod, false); 705 return CreateMesh(primName, primShape, size, lod, false, true);
703 } 706 }
704 707
705 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) 708 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
706 { 709 {
710 return CreateMesh(primName, primShape, size, lod, isPhysical, true);
711 }
712
713 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
714 {
707#if SPAM 715#if SPAM
708 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); 716 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
709#endif 717#endif
@@ -713,9 +721,12 @@ namespace OpenSim.Region.Physics.Meshing
713 721
714 // If this mesh has been created already, return it instead of creating another copy 722 // If this mesh has been created already, return it instead of creating another copy
715 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory 723 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
716 key = primShape.GetMeshKey(size, lod); 724 if (shouldCache)
717 if (m_uniqueMeshes.TryGetValue(key, out mesh)) 725 {
718 return mesh; 726 key = primShape.GetMeshKey(size, lod);
727 if (m_uniqueMeshes.TryGetValue(key, out mesh))
728 return mesh;
729 }
719 730
720 if (size.X < 0.01f) size.X = 0.01f; 731 if (size.X < 0.01f) size.X = 0.01f;
721 if (size.Y < 0.01f) size.Y = 0.01f; 732 if (size.Y < 0.01f) size.Y = 0.01f;
@@ -738,7 +749,10 @@ namespace OpenSim.Region.Physics.Meshing
738 // trim the vertex and triangle lists to free up memory 749 // trim the vertex and triangle lists to free up memory
739 mesh.TrimExcess(); 750 mesh.TrimExcess();
740 751
741 m_uniqueMeshes.Add(key, mesh); 752 if (shouldCache)
753 {
754 m_uniqueMeshes.Add(key, mesh);
755 }
742 } 756 }
743 757
744 return mesh; 758 return mesh;
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index 5a0b8d1..0d66496 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -3361,6 +3361,11 @@ Console.WriteLine(" JointCreateFixed");
3361 _pbs.SculptData = new byte[asset.Data.Length]; 3361 _pbs.SculptData = new byte[asset.Data.Length];
3362 asset.Data.CopyTo(_pbs.SculptData, 0); 3362 asset.Data.CopyTo(_pbs.SculptData, 0);
3363// m_assetFailed = false; 3363// m_assetFailed = false;
3364
3365// m_log.DebugFormat(
3366// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
3367// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
3368
3364 m_taintshape = true; 3369 m_taintshape = true;
3365 _parent_scene.AddPhysicsActorTaint(this); 3370 _parent_scene.AddPhysicsActorTaint(this);
3366 } 3371 }
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index b04f6b6..0cef550 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -114,6 +114,16 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
114 UUID AssetID { get; } 114 UUID AssetID { get; }
115 Queue EventQueue { get; } 115 Queue EventQueue { get; }
116 116
117 /// <summary>
118 /// Number of events queued for processing.
119 /// </summary>
120 long EventsQueued { get; }
121
122 /// <summary>
123 /// Number of events processed by this script instance.
124 /// </summary>
125 long EventsProcessed { get; }
126
117 void ClearQueue(); 127 void ClearQueue();
118 int StartParam { get; set; } 128 int StartParam { get; set; }
119 129
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index acf4d8c..4108588 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -6856,6 +6856,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6856 public void llCloseRemoteDataChannel(string channel) 6856 public void llCloseRemoteDataChannel(string channel)
6857 { 6857 {
6858 m_host.AddScriptLPS(1); 6858 m_host.AddScriptLPS(1);
6859
6860 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
6861 if (xmlRpcRouter != null)
6862 {
6863 xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID);
6864 }
6865
6859 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 6866 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6860 xmlrpcMod.CloseXMLRPCChannel((UUID)channel); 6867 xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
6861 ScriptSleep(1000); 6868 ScriptSleep(1000);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 5793cc9..5ad6eeb 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -173,6 +173,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
173 173
174 public Queue EventQueue { get; private set; } 174 public Queue EventQueue { get; private set; }
175 175
176 public long EventsQueued
177 {
178 get
179 {
180 lock (EventQueue)
181 return EventQueue.Count;
182 }
183 }
184
185 public long EventsProcessed { get; private set; }
186
176 public int StartParam { get; set; } 187 public int StartParam { get; set; }
177 188
178 public TaskInventoryItem ScriptTask { get; private set; } 189 public TaskInventoryItem ScriptTask { get; private set; }
@@ -774,6 +785,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
774 ChatTypeEnum.DebugChannel, 2147483647, 785 ChatTypeEnum.DebugChannel, 2147483647,
775 part.AbsolutePosition, 786 part.AbsolutePosition,
776 part.Name, part.UUID, false); 787 part.Name, part.UUID, false);
788
789
790 m_log.DebugFormat(
791 "[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}",
792 ScriptName,
793 PrimName,
794 part.UUID,
795 part.AbsolutePosition,
796 part.ParentGroup.Scene.Name,
797 text.Replace("\n", "\\n"),
798 e.InnerException);
777 } 799 }
778 catch (Exception) 800 catch (Exception)
779 { 801 {
@@ -808,6 +830,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
808 // script engine to run the next event. 830 // script engine to run the next event.
809 lock (EventQueue) 831 lock (EventQueue)
810 { 832 {
833 EventsProcessed++;
834
811 if (EventQueue.Count > 0 && Running && !ShuttingDown) 835 if (EventQueue.Count > 0 && Running && !ShuttingDown)
812 { 836 {
813 m_CurrentWorkItem = Engine.QueueEventHandler(this); 837 m_CurrentWorkItem = Engine.QueueEventHandler(this);
@@ -1013,7 +1037,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
1013 "({0}): {1}", scriptLine - 1, 1037 "({0}): {1}", scriptLine - 1,
1014 e.InnerException.Message); 1038 e.InnerException.Message);
1015 1039
1016 System.Console.WriteLine(e.ToString()+"\n");
1017 return message; 1040 return message;
1018 } 1041 }
1019 } 1042 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
index 2c9d9e8..cb7291a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs
@@ -57,8 +57,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
57 protected XEngine.XEngine m_engine; 57 protected XEngine.XEngine m_engine;
58 58
59 [SetUp] 59 [SetUp]
60 public void SetUp() 60 public override void SetUp()
61 { 61 {
62 base.SetUp();
63
62 IConfigSource initConfigSource = new IniConfigSource(); 64 IConfigSource initConfigSource = new IniConfigSource();
63 IConfig config = initConfigSource.AddConfig("XEngine"); 65 IConfig config = initConfigSource.AddConfig("XEngine");
64 config.Set("Enabled", "true"); 66 config.Set("Enabled", "true");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
index 57f19b9..d9b17d7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs
@@ -62,8 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
62 protected XEngine.XEngine m_engine; 62 protected XEngine.XEngine m_engine;
63 63
64 [SetUp] 64 [SetUp]
65 public void SetUp() 65 public override void SetUp()
66 { 66 {
67 base.SetUp();
68
67 IConfigSource initConfigSource = new IniConfigSource(); 69 IConfigSource initConfigSource = new IniConfigSource();
68 IConfig config = initConfigSource.AddConfig("XEngine"); 70 IConfig config = initConfigSource.AddConfig("XEngine");
69 config.Set("Enabled", "true"); 71 config.Set("Enabled", "true");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
index 182b07b..98017d8 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiListTests.cs
@@ -51,8 +51,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
51 private LSL_Api m_lslApi; 51 private LSL_Api m_lslApi;
52 52
53 [SetUp] 53 [SetUp]
54 public void SetUp() 54 public override void SetUp()
55 { 55 {
56 base.SetUp();
57
56 IConfigSource initConfigSource = new IniConfigSource(); 58 IConfigSource initConfigSource = new IniConfigSource();
57 IConfig config = initConfigSource.AddConfig("XEngine"); 59 IConfig config = initConfigSource.AddConfig("XEngine");
58 config.Set("Enabled", "true"); 60 config.Set("Enabled", "true");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
index 213f33f..1381d2b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
@@ -57,8 +57,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
57 protected XEngine.XEngine m_engine; 57 protected XEngine.XEngine m_engine;
58 58
59 [SetUp] 59 [SetUp]
60 public void SetUp() 60 public override void SetUp()
61 { 61 {
62 base.SetUp();
63
62 IConfigSource initConfigSource = new IniConfigSource(); 64 IConfigSource initConfigSource = new IniConfigSource();
63 IConfig config = initConfigSource.AddConfig("XEngine"); 65 IConfig config = initConfigSource.AddConfig("XEngine");
64 config.Set("Enabled", "true"); 66 config.Set("Enabled", "true");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
index b49bcc2..d6c82f1 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
@@ -127,12 +127,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
127 OSSL_Api osslApi = new OSSL_Api(); 127 OSSL_Api osslApi = new OSSL_Api();
128 osslApi.Initialize(m_engine, so.RootPart, null); 128 osslApi.Initialize(m_engine, so.RootPart, null);
129 129
130 string npcRaw;
131 bool gotExpectedException = false; 130 bool gotExpectedException = false;
132 try 131 try
133 { 132 {
134 npcRaw 133 osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
135 = osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
136 } 134 }
137 catch (ScriptException) 135 catch (ScriptException)
138 { 136 {
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 0460f22..965101a 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -30,6 +30,7 @@ using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Globalization; 31using System.Globalization;
32using System.IO; 32using System.IO;
33using System.Linq;
33using System.Reflection; 34using System.Reflection;
34using System.Security; 35using System.Security;
35using System.Security.Policy; 36using System.Security.Policy;
@@ -377,9 +378,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine
377 /// </summary> 378 /// </summary>
378 /// <param name="cmdparams"></param> 379 /// <param name="cmdparams"></param>
379 /// <param name="instance"></param> 380 /// <param name="instance"></param>
380 /// <returns>true if we're okay to proceed, false if not.</returns> 381 /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param>
381 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action) 382 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
382 { 383 {
384 HandleScriptsAction<object>(cmdparams, action, null);
385 }
386
387 /// <summary>
388 /// Parse the raw item id into a script instance from the command params if it's present.
389 /// </summary>
390 /// <param name="cmdparams"></param>
391 /// <param name="instance"></param>
392 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
393 private void HandleScriptsAction<TKey>(
394 string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector)
395 {
383 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) 396 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
384 return; 397 return;
385 398
@@ -390,7 +403,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
390 403
391 if (cmdparams.Length == 2) 404 if (cmdparams.Length == 2)
392 { 405 {
393 foreach (IScriptInstance instance in m_Scripts.Values) 406 IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
407
408 if (keySelector != null)
409 scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
410
411 foreach (IScriptInstance instance in scripts)
394 action(instance); 412 action(instance);
395 413
396 return; 414 return;
@@ -437,9 +455,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
437 StringBuilder sb = new StringBuilder(); 455 StringBuilder sb = new StringBuilder();
438 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName); 456 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
439 457
458 long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
459
440 lock (m_Scripts) 460 lock (m_Scripts)
441 sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count); 461 {
462 scriptsLoaded = m_Scripts.Count;
442 463
464 foreach (IScriptInstance si in m_Scripts.Values)
465 {
466 eventsQueued += si.EventsQueued;
467 eventsProcessed += si.EventsProcessed;
468 }
469 }
470
471 sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
443 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count); 472 sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
444 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count); 473 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
445 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads); 474 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
@@ -448,6 +477,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
448 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads); 477 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
449 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks); 478 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
450// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count); 479// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
480 sb.AppendFormat("Events queued : {0}\n", eventsQueued);
481 sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
451 482
452 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this); 483 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
453 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0); 484 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
@@ -478,7 +509,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
478 } 509 }
479 } 510 }
480 511
481 HandleScriptsAction(cmdparams, HandleShowScript); 512 HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
482 } 513 }
483 514
484 private void HandleShowScript(IScriptInstance instance) 515 private void HandleShowScript(IScriptInstance instance)
@@ -508,10 +539,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
508 539
509 sb.AppendFormat("Script name : {0}\n", instance.ScriptName); 540 sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
510 sb.AppendFormat("Status : {0}\n", status); 541 sb.AppendFormat("Status : {0}\n", status);
511 542 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
512 lock (eq) 543 sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
513 sb.AppendFormat("Queued events : {0}\n", eq.Count);
514
515 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID); 544 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
516 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName); 545 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
517 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); 546 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
@@ -1018,8 +1047,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1018 1047
1019 string assembly = ""; 1048 string assembly = "";
1020 1049
1021 CultureInfo USCulture = new CultureInfo("en-US"); 1050 Culture.SetCurrentCulture();
1022 Thread.CurrentThread.CurrentCulture = USCulture;
1023 1051
1024 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap; 1052 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
1025 1053
@@ -1415,8 +1443,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1415 /// <returns></returns> 1443 /// <returns></returns>
1416 private object ProcessEventHandler(object parms) 1444 private object ProcessEventHandler(object parms)
1417 { 1445 {
1418 CultureInfo USCulture = new CultureInfo("en-US"); 1446 Culture.SetCurrentCulture();
1419 Thread.CurrentThread.CurrentCulture = USCulture;
1420 1447
1421 IScriptInstance instance = (ScriptInstance) parms; 1448 IScriptInstance instance = (ScriptInstance) parms;
1422 1449
diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
index 95c4f87..57f2ffa 100644
--- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
+++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs
@@ -314,7 +314,7 @@ namespace OpenSim.Services.Connectors.Simulation
314 314
315 try 315 try
316 { 316 {
317 OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 10000, false); 317 OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 30000, false);
318 bool success = result["success"].AsBoolean(); 318 bool success = result["success"].AsBoolean();
319 if (result.ContainsKey("_Result")) 319 if (result.ContainsKey("_Result"))
320 { 320 {
diff --git a/OpenSim/Services/HypergridService/HGInstantMessageService.cs b/OpenSim/Services/HypergridService/HGInstantMessageService.cs
index 0c9cfd3..e8d7cca 100644
--- a/OpenSim/Services/HypergridService/HGInstantMessageService.cs
+++ b/OpenSim/Services/HypergridService/HGInstantMessageService.cs
@@ -61,13 +61,13 @@ namespace OpenSim.Services.HypergridService
61 protected static IGridService m_GridService; 61 protected static IGridService m_GridService;
62 protected static IPresenceService m_PresenceService; 62 protected static IPresenceService m_PresenceService;
63 protected static IUserAgentService m_UserAgentService; 63 protected static IUserAgentService m_UserAgentService;
64 protected static IOfflineIMService m_OfflineIMService;
64 65
65 protected static IInstantMessageSimConnector m_IMSimConnector; 66 protected static IInstantMessageSimConnector m_IMSimConnector;
66 67
67 protected static Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>(); 68 protected static Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>();
68 private static ExpiringCache<UUID, GridRegion> m_RegionCache; 69 private static ExpiringCache<UUID, GridRegion> m_RegionCache;
69 70
70 private static string m_RestURL;
71 private static bool m_ForwardOfflineGroupMessages; 71 private static bool m_ForwardOfflineGroupMessages;
72 private static bool m_InGatekeeper; 72 private static bool m_InGatekeeper;
73 73
@@ -111,9 +111,14 @@ namespace OpenSim.Services.HypergridService
111 return; 111 return;
112 } 112 }
113 113
114 m_RestURL = cnf.GetString("OfflineMessageURL", string.Empty);
115 m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", false); 114 m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", false);
116 115
116 if (m_InGatekeeper)
117 {
118 string offlineIMService = cnf.GetString("OfflineIMService", string.Empty);
119 if (offlineIMService != string.Empty)
120 m_OfflineIMService = ServerUtils.LoadPlugin<IOfflineIMService>(offlineIMService, args);
121 }
117 } 122 }
118 } 123 }
119 124
@@ -329,18 +334,28 @@ namespace OpenSim.Services.HypergridService
329 334
330 private bool UndeliveredMessage(GridInstantMessage im) 335 private bool UndeliveredMessage(GridInstantMessage im)
331 { 336 {
332 if (m_RestURL != string.Empty && (im.offline != 0) 337 if (m_OfflineIMService == null)
333 && (!im.fromGroup || (im.fromGroup && m_ForwardOfflineGroupMessages))) 338 return false;
334 {
335// m_log.DebugFormat("[HG IM SERVICE]: Message saved");
336 339
337 return SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( 340 if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
338 "POST", m_RestURL + "/SaveMessage/", im); 341 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
339 } 342 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
340 else 343 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
344 im.dialog != (byte)InstantMessageDialog.InventoryOffered)
341 { 345 {
342 return false; 346 return false;
343 } 347 }
348
349 if (!m_ForwardOfflineGroupMessages)
350 {
351 if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
352 im.dialog == (byte)InstantMessageDialog.GroupInvitation)
353 return false;
354 }
355
356// m_log.DebugFormat("[HG IM SERVICE]: Message saved");
357 string reason = string.Empty;
358 return m_OfflineIMService.StoreMessage(im, out reason);
344 } 359 }
345 } 360 }
346} \ No newline at end of file 361} \ No newline at end of file
diff --git a/OpenSim/Services/Interfaces/IOfflineIMService.cs b/OpenSim/Services/Interfaces/IOfflineIMService.cs
new file mode 100644
index 0000000..2848967
--- /dev/null
+++ b/OpenSim/Services/Interfaces/IOfflineIMService.cs
@@ -0,0 +1,115 @@
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 */
27using System;
28using System.Collections.Generic;
29
30using OpenSim.Framework;
31using OpenMetaverse;
32
33namespace OpenSim.Services.Interfaces
34{
35 public interface IOfflineIMService
36 {
37 List<GridInstantMessage> GetMessages(UUID principalID);
38 bool StoreMessage(GridInstantMessage im, out string reason);
39 }
40
41 public class OfflineIMDataUtils
42 {
43 public static GridInstantMessage GridInstantMessage(Dictionary<string, object> dict)
44 {
45 GridInstantMessage im = new GridInstantMessage();
46
47 if (dict.ContainsKey("BinaryBucket") && dict["BinaryBucket"] != null)
48 im.binaryBucket = OpenMetaverse.Utils.HexStringToBytes(dict["BinaryBucket"].ToString(), true);
49
50 if (dict.ContainsKey("Dialog") && dict["Dialog"] != null)
51 im.dialog = byte.Parse(dict["Dialog"].ToString());
52
53 if (dict.ContainsKey("FromAgentID") && dict["FromAgentID"] != null)
54 im.fromAgentID = new Guid(dict["FromAgentID"].ToString());
55
56 if (dict.ContainsKey("FromAgentName") && dict["FromAgentName"] != null)
57 im.fromAgentName = dict["FromAgentName"].ToString();
58 else
59 im.fromAgentName = string.Empty;
60
61 if (dict.ContainsKey("FromGroup") && dict["FromGroup"] != null)
62 im.fromGroup = bool.Parse(dict["FromGroup"].ToString());
63
64 if (dict.ContainsKey("SessionID") && dict["SessionID"] != null)
65 im.imSessionID = new Guid(dict["SessionID"].ToString());
66
67 if (dict.ContainsKey("Message") && dict["Message"] != null)
68 im.message = dict["Message"].ToString();
69 else
70 im.message = string.Empty;
71
72 if (dict.ContainsKey("Offline") && dict["Offline"] != null)
73 im.offline = byte.Parse(dict["Offline"].ToString());
74
75 if (dict.ContainsKey("EstateID") && dict["EstateID"] != null)
76 im.ParentEstateID = UInt32.Parse(dict["EstateID"].ToString());
77
78 if (dict.ContainsKey("Position") && dict["Position"] != null)
79 im.Position = Vector3.Parse(dict["Position"].ToString());
80
81 if (dict.ContainsKey("RegionID") && dict["RegionID"] != null)
82 im.RegionID = new Guid(dict["RegionID"].ToString());
83
84 if (dict.ContainsKey("Timestamp") && dict["Timestamp"] != null)
85 im.timestamp = UInt32.Parse(dict["Timestamp"].ToString());
86
87 if (dict.ContainsKey("ToAgentID") && dict["ToAgentID"] != null)
88 im.toAgentID = new Guid(dict["ToAgentID"].ToString());
89
90 return im;
91 }
92
93 public static Dictionary<string, object> GridInstantMessage(GridInstantMessage im)
94 {
95 Dictionary<string, object> dict = new Dictionary<string, object>();
96
97 dict["BinaryBucket"] = OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, im.binaryBucket.Length, null);
98 dict["Dialog"] = im.dialog.ToString();
99 dict["FromAgentID"] = im.fromAgentID.ToString();
100 dict["FromAgentName"] = im.fromAgentName == null ? string.Empty : im.fromAgentName;
101 dict["FromGroup"] = im.fromGroup.ToString();
102 dict["SessionID"] = im.imSessionID.ToString();
103 dict["Message"] = im.message == null ? string.Empty : im.message;
104 dict["Offline"] = im.offline.ToString();
105 dict["EstateID"] = im.ParentEstateID.ToString();
106 dict["Position"] = im.Position.ToString();
107 dict["RegionID"] = im.RegionID.ToString();
108 dict["Timestamp"] = im.timestamp.ToString();
109 dict["ToAgentID"] = im.toAgentID.ToString();
110
111 return dict;
112 }
113
114 }
115}
diff --git a/bin/OpenMetaverse.dll.config b/bin/OpenMetaverse.dll.config
index b67da5f..f5423b2 100644
--- a/bin/OpenMetaverse.dll.config
+++ b/bin/OpenMetaverse.dll.config
@@ -1,5 +1,5 @@
1<configuration> 1<configuration>
2 <dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet-2.1.5.0-dotnet-1.dylib" /> 2 <dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet.dylib" />
3 <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" /> 3 <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" />
4 <dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" /> 4 <dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" />
5</configuration> 5</configuration>
diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll
index 38b11cd..9834faa 100755
--- a/bin/lib32/BulletSim.dll
+++ b/bin/lib32/BulletSim.dll
Binary files differ
diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so
index f59ec97..3c8e034 100755
--- a/bin/lib32/libBulletSim.so
+++ b/bin/lib32/libBulletSim.so
Binary files differ
diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll
index 1861d6d..75999f0 100755
--- a/bin/lib64/BulletSim.dll
+++ b/bin/lib64/BulletSim.dll
Binary files differ
diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so
index e9b8845..a8a4720 100755
--- a/bin/lib64/libBulletSim.so
+++ b/bin/lib64/libBulletSim.so
Binary files differ
diff --git a/prebuild.xml b/prebuild.xml
index fffeab1..99ba2a9 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -2052,7 +2052,7 @@
2052 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 2052 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
2053 <Reference name="OpenMetaverse" path="../../../bin/"/> 2053 <Reference name="OpenMetaverse" path="../../../bin/"/>
2054 <Reference name="Nini" path="../../../bin/"/> 2054 <Reference name="Nini" path="../../../bin/"/>
2055 <Reference name="Mono.Addins"/> 2055 <Reference name="Mono.Addins" path="../../../bin/"/>
2056 <Reference name="log4net" path="../../../bin/"/> 2056 <Reference name="log4net" path="../../../bin/"/>
2057 <Files> 2057 <Files>
2058 <Match pattern="*.cs" recurse="true"/> 2058 <Match pattern="*.cs" recurse="true"/>
@@ -2460,7 +2460,7 @@
2460 <Reference name="OpenSim.Framework.Servers.HttpServer"/> 2460 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
2461 <Reference name="OpenSim.Region.Physics.Manager"/> 2461 <Reference name="OpenSim.Region.Physics.Manager"/>
2462 <Reference name="Mono.Data.SqliteClient" path="../../../bin/"/> 2462 <Reference name="Mono.Data.SqliteClient" path="../../../bin/"/>
2463 <Reference name="Mono.Addins"/> 2463 <Reference name="Mono.Addins" path="../../../bin/"/>
2464 2464
2465 <!-- For scripting in funny languages by default --> 2465 <!-- For scripting in funny languages by default -->
2466 <Reference name="XMLRPC" path="../../../bin/"/> 2466 <Reference name="XMLRPC" path="../../../bin/"/>