Merge branch 'master' into careminster
Conflicts: OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs OpenSim/Region/Framework/Scenes/Scene.csavinationmerge
commit
2cb824d3fc
|
@ -225,6 +225,11 @@ namespace OpenSim.Capabilities.Handlers
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Handle the case where no second range value was given. This is equivalent to requesting
|
||||||
|
// the rest of the entity.
|
||||||
|
if (end == -1)
|
||||||
|
end = int.MaxValue;
|
||||||
|
|
||||||
end = Utils.Clamp(end, 0, texture.Data.Length - 1);
|
end = Utils.Clamp(end, 0, texture.Data.Length - 1);
|
||||||
start = Utils.Clamp(start, 0, end);
|
start = Utils.Clamp(start, 0, end);
|
||||||
int len = end - start + 1;
|
int len = end - start + 1;
|
||||||
|
@ -283,15 +288,43 @@ namespace OpenSim.Capabilities.Handlers
|
||||||
// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
|
// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parse a range header.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
|
||||||
|
/// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
|
||||||
|
/// Where there is no value, -1 is returned.
|
||||||
|
/// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
|
||||||
|
/// for start.</remarks>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <param name='header'></param>
|
||||||
|
/// <param name='start'>Start of the range. Undefined if this was not a number.</param>
|
||||||
|
/// <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>
|
||||||
private bool TryParseRange(string header, out int start, out int end)
|
private bool TryParseRange(string header, out int start, out int end)
|
||||||
{
|
{
|
||||||
|
start = end = 0;
|
||||||
|
|
||||||
if (header.StartsWith("bytes="))
|
if (header.StartsWith("bytes="))
|
||||||
{
|
{
|
||||||
string[] rangeValues = header.Substring(6).Split('-');
|
string[] rangeValues = header.Substring(6).Split('-');
|
||||||
|
|
||||||
if (rangeValues.Length == 2)
|
if (rangeValues.Length == 2)
|
||||||
{
|
{
|
||||||
if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
|
if (!Int32.TryParse(rangeValues[0], out start))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string rawEnd = rangeValues[1];
|
||||||
|
|
||||||
|
if (rawEnd == "")
|
||||||
|
{
|
||||||
|
end = -1;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
else if (Int32.TryParse(rawEnd, out end))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,508 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2008, openmetaverse.org, http://opensimulator.org/
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* - Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* - Neither the name of the openmetaverse.org nor the names
|
||||||
|
* of its contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace OpenSim.Framework
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A double dictionary that is thread abort safe.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This adapts OpenMetaverse.DoubleDictionary to be thread-abort safe by acquiring ReaderWriterLockSlim within
|
||||||
|
/// a finally section (which can't be interrupted by Thread.Abort()).
|
||||||
|
/// </remarks>
|
||||||
|
public class DoubleDictionaryThreadAbortSafe<TKey1, TKey2, TValue>
|
||||||
|
{
|
||||||
|
Dictionary<TKey1, TValue> Dictionary1;
|
||||||
|
Dictionary<TKey2, TValue> Dictionary2;
|
||||||
|
ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
|
||||||
|
|
||||||
|
public DoubleDictionaryThreadAbortSafe()
|
||||||
|
{
|
||||||
|
Dictionary1 = new Dictionary<TKey1,TValue>();
|
||||||
|
Dictionary2 = new Dictionary<TKey2,TValue>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleDictionaryThreadAbortSafe(int capacity)
|
||||||
|
{
|
||||||
|
Dictionary1 = new Dictionary<TKey1, TValue>(capacity);
|
||||||
|
Dictionary2 = new Dictionary<TKey2, TValue>(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(TKey1 key1, TKey2 key2, TValue value)
|
||||||
|
{
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterWriteLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Dictionary1.ContainsKey(key1))
|
||||||
|
{
|
||||||
|
if (!Dictionary2.ContainsKey(key2))
|
||||||
|
throw new ArgumentException("key1 exists in the dictionary but not key2");
|
||||||
|
}
|
||||||
|
else if (Dictionary2.ContainsKey(key2))
|
||||||
|
{
|
||||||
|
if (!Dictionary1.ContainsKey(key1))
|
||||||
|
throw new ArgumentException("key2 exists in the dictionary but not key1");
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary1[key1] = value;
|
||||||
|
Dictionary2[key2] = value;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TKey1 key1, TKey2 key2)
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterWriteLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary1.Remove(key1);
|
||||||
|
success = Dictionary2.Remove(key2);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TKey1 key1)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterWriteLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an O(n) operation!
|
||||||
|
TValue value;
|
||||||
|
if (Dictionary1.TryGetValue(key1, out value))
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
|
||||||
|
{
|
||||||
|
if (kvp.Value.Equals(value))
|
||||||
|
{
|
||||||
|
Dictionary1.Remove(key1);
|
||||||
|
Dictionary2.Remove(kvp.Key);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TKey2 key2)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterWriteLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an O(n) operation!
|
||||||
|
TValue value;
|
||||||
|
if (Dictionary2.TryGetValue(key2, out value))
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
|
||||||
|
{
|
||||||
|
if (kvp.Value.Equals(value))
|
||||||
|
{
|
||||||
|
Dictionary2.Remove(key2);
|
||||||
|
Dictionary1.Remove(kvp.Key);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterWriteLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary1.Clear();
|
||||||
|
Dictionary2.Clear();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get { return Dictionary1.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(TKey1 key)
|
||||||
|
{
|
||||||
|
return Dictionary1.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(TKey2 key)
|
||||||
|
{
|
||||||
|
return Dictionary2.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(TKey1 key, out TValue value)
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterReadLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
success = Dictionary1.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(TKey2 key, out TValue value)
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterReadLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
success = Dictionary2.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForEach(Action<TValue> action)
|
||||||
|
{
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterReadLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (TValue value in Dictionary1.Values)
|
||||||
|
action(value);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForEach(Action<KeyValuePair<TKey1, TValue>> action)
|
||||||
|
{
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterReadLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<TKey1, TValue> entry in Dictionary1)
|
||||||
|
action(entry);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForEach(Action<KeyValuePair<TKey2, TValue>> action)
|
||||||
|
{
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterReadLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<TKey2, TValue> entry in Dictionary2)
|
||||||
|
action(entry);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue FindValue(Predicate<TValue> predicate)
|
||||||
|
{
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterReadLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (TValue value in Dictionary1.Values)
|
||||||
|
{
|
||||||
|
if (predicate(value))
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return default(TValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<TValue> FindAll(Predicate<TValue> predicate)
|
||||||
|
{
|
||||||
|
IList<TValue> list = new List<TValue>();
|
||||||
|
bool gotLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterReadLock();
|
||||||
|
gotLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (TValue value in Dictionary1.Values)
|
||||||
|
{
|
||||||
|
if (predicate(value))
|
||||||
|
list.Add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotLock)
|
||||||
|
rwLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int RemoveAll(Predicate<TValue> predicate)
|
||||||
|
{
|
||||||
|
IList<TKey1> list = new List<TKey1>();
|
||||||
|
bool gotUpgradeableLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
|
||||||
|
// the acquision inside the main try. The inner finally block is needed because thread aborts cannot
|
||||||
|
// interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterUpgradeableReadLock();
|
||||||
|
gotUpgradeableLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
|
||||||
|
{
|
||||||
|
if (predicate(kvp.Value))
|
||||||
|
list.Add(kvp.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
IList<TKey2> list2 = new List<TKey2>(list.Count);
|
||||||
|
foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
|
||||||
|
{
|
||||||
|
if (predicate(kvp.Value))
|
||||||
|
list2.Add(kvp.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gotWriteLock = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try {}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
rwLock.EnterUpgradeableReadLock();
|
||||||
|
gotWriteLock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < list.Count; i++)
|
||||||
|
Dictionary1.Remove(list[i]);
|
||||||
|
|
||||||
|
for (int i = 0; i < list2.Count; i++)
|
||||||
|
Dictionary2.Remove(list2[i]);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotWriteLock)
|
||||||
|
rwLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (gotUpgradeableLock)
|
||||||
|
rwLock.ExitUpgradeableReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -192,18 +192,7 @@ namespace OpenSim.Framework
|
||||||
|
|
||||||
public PrimitiveBaseShape()
|
public PrimitiveBaseShape()
|
||||||
{
|
{
|
||||||
PCode = (byte) PCodeEnum.Primitive;
|
|
||||||
ExtraParams = new byte[1];
|
|
||||||
m_textureEntry = DEFAULT_TEXTURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PrimitiveBaseShape(bool noShape)
|
|
||||||
{
|
|
||||||
if (noShape)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PCode = (byte)PCodeEnum.Primitive;
|
PCode = (byte)PCodeEnum.Primitive;
|
||||||
ExtraParams = new byte[1];
|
|
||||||
m_textureEntry = DEFAULT_TEXTURE;
|
m_textureEntry = DEFAULT_TEXTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +205,6 @@ namespace OpenSim.Framework
|
||||||
// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID);
|
// m_log.DebugFormat("[PRIMITIVE BASE SHAPE]: Creating from {0}", prim.ID);
|
||||||
|
|
||||||
PCode = (byte)prim.PrimData.PCode;
|
PCode = (byte)prim.PrimData.PCode;
|
||||||
ExtraParams = new byte[1];
|
|
||||||
|
|
||||||
State = prim.PrimData.State;
|
State = prim.PrimData.State;
|
||||||
PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
|
PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
|
||||||
|
@ -248,7 +236,10 @@ namespace OpenSim.Framework
|
||||||
SculptTexture = prim.Sculpt.SculptTexture;
|
SculptTexture = prim.Sculpt.SculptTexture;
|
||||||
SculptType = (byte)prim.Sculpt.Type;
|
SculptType = (byte)prim.Sculpt.Type;
|
||||||
}
|
}
|
||||||
else SculptType = (byte)OpenMetaverse.SculptType.None;
|
else
|
||||||
|
{
|
||||||
|
SculptType = (byte)OpenMetaverse.SculptType.None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[XmlIgnore]
|
[XmlIgnore]
|
||||||
|
@ -340,9 +331,9 @@ namespace OpenSim.Framework
|
||||||
_scale = new Vector3(side, side, side);
|
_scale = new Vector3(side, side, side);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetHeigth(float heigth)
|
public void SetHeigth(float height)
|
||||||
{
|
{
|
||||||
_scale.Z = heigth;
|
_scale.Z = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRadius(float radius)
|
public void SetRadius(float radius)
|
||||||
|
|
|
@ -437,7 +437,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
|
// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
|
||||||
//m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
|
//m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
|
||||||
|
|
||||||
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
|
Culture.SetCurrentCulture();
|
||||||
|
|
||||||
// // This is the REST agent interface. We require an agent to properly identify
|
// // This is the REST agent interface. We require an agent to properly identify
|
||||||
// // itself. If the REST handler recognizes the prefix it will attempt to
|
// // itself. If the REST handler recognizes the prefix it will attempt to
|
||||||
|
|
|
@ -303,10 +303,6 @@ namespace OpenSim.Framework.Tests
|
||||||
Culture.SetCurrentCulture();
|
Culture.SetCurrentCulture();
|
||||||
Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US");
|
Assert.That(Thread.CurrentThread.CurrentCulture.Name == ci.Name, "SetCurrentCulture failed to set thread culture to en-US");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,10 @@ namespace OpenSim.Region.CoreModules.Asset.Tests
|
||||||
protected FlotsamAssetCache m_cache;
|
protected FlotsamAssetCache m_cache;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
IConfigSource config = new IniConfigSource();
|
IConfigSource config = new IniConfigSource();
|
||||||
|
|
||||||
config.AddConfig("Modules");
|
config.AddConfig("Modules");
|
||||||
|
|
|
@ -153,7 +153,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
|
||||||
if (sp != null && !sp.IsChildAgent)
|
if (sp != null && !sp.IsChildAgent)
|
||||||
{
|
{
|
||||||
// Local message
|
// Local message
|
||||||
m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID);
|
// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID);
|
||||||
|
|
||||||
sp.ControllingClient.SendInstantMessage(im);
|
sp.ControllingClient.SendInstantMessage(im);
|
||||||
|
|
||||||
|
@ -166,14 +166,14 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
|
||||||
// try child avatar second
|
// try child avatar second
|
||||||
foreach (Scene scene in m_Scenes)
|
foreach (Scene scene in m_Scenes)
|
||||||
{
|
{
|
||||||
//m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
|
// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
ScenePresence sp = scene.GetScenePresence(toAgentID);
|
ScenePresence sp = scene.GetScenePresence(toAgentID);
|
||||||
if (sp != null)
|
if (sp != null)
|
||||||
{
|
{
|
||||||
// Local message
|
// Local message
|
||||||
m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID);
|
// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID);
|
||||||
|
|
||||||
sp.ControllingClient.SendInstantMessage(im);
|
sp.ControllingClient.SendInstantMessage(im);
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
|
// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
|
||||||
|
|
||||||
SendGridInstantMessageViaXMLRPC(im, result);
|
SendGridInstantMessageViaXMLRPC(im, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
|
||||||
protected TestClient m_tc;
|
protected TestClient m_tc;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
m_iam = new BasicInventoryAccessModule();
|
m_iam = new BasicInventoryAccessModule();
|
||||||
|
|
||||||
IConfigSource config = new IniConfigSource();
|
IConfigSource config = new IniConfigSource();
|
||||||
|
|
|
@ -46,8 +46,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests
|
||||||
public class PresenceConnectorsTests : OpenSimTestCase
|
public class PresenceConnectorsTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
LocalPresenceServicesConnector m_LocalConnector;
|
LocalPresenceServicesConnector m_LocalConnector;
|
||||||
private void SetUp()
|
|
||||||
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
IConfigSource config = new IniConfigSource();
|
IConfigSource config = new IniConfigSource();
|
||||||
config.AddConfig("Modules");
|
config.AddConfig("Modules");
|
||||||
config.AddConfig("PresenceService");
|
config.AddConfig("PresenceService");
|
||||||
|
|
|
@ -60,8 +60,10 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests
|
||||||
protected ILandObject m_lo2;
|
protected ILandObject m_lo2;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
m_pcm = new PrimCountModule();
|
m_pcm = new PrimCountModule();
|
||||||
LandManagementModule lmm = new LandManagementModule();
|
LandManagementModule lmm = new LandManagementModule();
|
||||||
m_scene = new SceneHelpers().SetupScene();
|
m_scene = new SceneHelpers().SetupScene();
|
||||||
|
|
|
@ -50,8 +50,10 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests
|
||||||
protected MoapModule m_module;
|
protected MoapModule m_module;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
m_module = new MoapModule();
|
m_module = new MoapModule();
|
||||||
m_scene = new SceneHelpers().SetupScene();
|
m_scene = new SceneHelpers().SetupScene();
|
||||||
SceneHelpers.SetupSceneModules(m_scene, m_module);
|
SceneHelpers.SetupSceneModules(m_scene, m_module);
|
||||||
|
|
|
@ -31,6 +31,7 @@ using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
|
||||||
namespace OpenSim.Region.Framework.Scenes
|
namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
|
@ -38,7 +39,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private readonly DoubleDictionary<UUID, uint, EntityBase> m_entities = new DoubleDictionary<UUID, uint, EntityBase>();
|
private readonly DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase> m_entities
|
||||||
|
= new DoubleDictionaryThreadAbortSafe<UUID, uint, EntityBase>();
|
||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
|
|
|
@ -6041,10 +6041,17 @@ Environment.Exit(1);
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrappers to get physics modules retrieve assets. Has to be done this way
|
/// <summary>
|
||||||
// because we can't assign the asset service to physics directly - at the
|
/// Wrappers to get physics modules retrieve assets.
|
||||||
// time physics are instantiated it's not registered but it will be by
|
/// </summary>
|
||||||
// the time the first prim exists.
|
/// <remarks>
|
||||||
|
/// Has to be done this way
|
||||||
|
/// because we can't assign the asset service to physics directly - at the
|
||||||
|
/// time physics are instantiated it's not registered but it will be by
|
||||||
|
/// the time the first prim exists.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="assetID"></param>
|
||||||
|
/// <param name="callback"></param>
|
||||||
public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
|
public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
|
||||||
{
|
{
|
||||||
AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
|
AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
|
||||||
|
|
|
@ -24,21 +24,10 @@
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
|
* The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
|
||||||
/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
|
* are Copyright (c) 2009 Linden Research, Inc and are used under their license
|
||||||
* call the BulletSim system.
|
* of Creative Commons Attribution-Share Alike 3.0
|
||||||
*/
|
* (http://creativecommons.org/licenses/by-sa/3.0/).
|
||||||
/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
|
|
||||||
* ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
|
|
||||||
* ODEPrim.cs contains methods dealing with Prim editing, Prim
|
|
||||||
* characteristics and Kinetic motion.
|
|
||||||
* ODEDynamics.cs contains methods dealing with Prim Physical motion
|
|
||||||
* (dynamics) and the associated settings. Old Linear and angular
|
|
||||||
* motors for dynamic motion have been replace with MoveLinear()
|
|
||||||
* and MoveAngular(); 'Physical' is used only to switch ODE dynamic
|
|
||||||
* simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
|
|
||||||
* switch between 'VEHICLE' parameter use and general dynamics
|
|
||||||
* settings use.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
@ -111,7 +100,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
private float m_bankingEfficiency = 0;
|
private float m_bankingEfficiency = 0;
|
||||||
private float m_bankingMix = 0;
|
private float m_bankingMix = 0;
|
||||||
private float m_bankingTimescale = 0;
|
private float m_bankingTimescale = 0;
|
||||||
private Vector3 m_lastBanking = Vector3.Zero;
|
|
||||||
|
|
||||||
//Hover and Buoyancy properties
|
//Hover and Buoyancy properties
|
||||||
private float m_VhoverHeight = 0f;
|
private float m_VhoverHeight = 0f;
|
||||||
|
@ -125,8 +113,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
//Attractor properties
|
//Attractor properties
|
||||||
private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
|
private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
|
||||||
private float m_verticalAttractionEfficiency = 1.0f; // damped
|
private float m_verticalAttractionEfficiency = 1.0f; // damped
|
||||||
private float m_verticalAttractionTimescale = 600f; // Timescale > 500 means no vert attractor.
|
private float m_verticalAttractionCutoff = 500f; // per the documentation
|
||||||
|
// Timescale > cutoff means no vert attractor.
|
||||||
|
private float m_verticalAttractionTimescale = 510f;
|
||||||
|
|
||||||
public BSDynamics(BSScene myScene, BSPrim myPrim)
|
public BSDynamics(BSScene myScene, BSPrim myPrim)
|
||||||
{
|
{
|
||||||
|
@ -329,7 +319,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_bankingEfficiency = 0;
|
m_bankingEfficiency = 0;
|
||||||
m_bankingTimescale = 1000;
|
m_bankingTimescale = 1000;
|
||||||
m_bankingMix = 1;
|
m_bankingMix = 1;
|
||||||
m_lastBanking = Vector3.Zero;
|
|
||||||
|
|
||||||
m_referenceFrame = Quaternion.Identity;
|
m_referenceFrame = Quaternion.Identity;
|
||||||
m_flags = (VehicleFlag)0;
|
m_flags = (VehicleFlag)0;
|
||||||
|
@ -364,7 +353,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_bankingEfficiency = 0;
|
m_bankingEfficiency = 0;
|
||||||
m_bankingTimescale = 10;
|
m_bankingTimescale = 10;
|
||||||
m_bankingMix = 1;
|
m_bankingMix = 1;
|
||||||
m_lastBanking = Vector3.Zero;
|
|
||||||
|
|
||||||
m_referenceFrame = Quaternion.Identity;
|
m_referenceFrame = Quaternion.Identity;
|
||||||
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
|
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
|
||||||
|
@ -374,6 +362,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_flags |= (VehicleFlag.NO_DEFLECTION_UP
|
m_flags |= (VehicleFlag.NO_DEFLECTION_UP
|
||||||
| VehicleFlag.LIMIT_ROLL_ONLY
|
| VehicleFlag.LIMIT_ROLL_ONLY
|
||||||
| VehicleFlag.LIMIT_MOTOR_UP);
|
| VehicleFlag.LIMIT_MOTOR_UP);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Vehicle.TYPE_CAR:
|
case Vehicle.TYPE_CAR:
|
||||||
m_linearMotorDirection = Vector3.Zero;
|
m_linearMotorDirection = Vector3.Zero;
|
||||||
|
@ -403,7 +392,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_bankingEfficiency = -0.2f;
|
m_bankingEfficiency = -0.2f;
|
||||||
m_bankingMix = 1;
|
m_bankingMix = 1;
|
||||||
m_bankingTimescale = 1;
|
m_bankingTimescale = 1;
|
||||||
m_lastBanking = Vector3.Zero;
|
|
||||||
|
|
||||||
m_referenceFrame = Quaternion.Identity;
|
m_referenceFrame = Quaternion.Identity;
|
||||||
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
|
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
|
||||||
|
@ -442,7 +430,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_bankingEfficiency = -0.3f;
|
m_bankingEfficiency = -0.3f;
|
||||||
m_bankingMix = 0.8f;
|
m_bankingMix = 0.8f;
|
||||||
m_bankingTimescale = 1;
|
m_bankingTimescale = 1;
|
||||||
m_lastBanking = Vector3.Zero;
|
|
||||||
|
|
||||||
m_referenceFrame = Quaternion.Identity;
|
m_referenceFrame = Quaternion.Identity;
|
||||||
m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
|
m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
|
||||||
|
@ -481,7 +468,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_bankingEfficiency = 1;
|
m_bankingEfficiency = 1;
|
||||||
m_bankingMix = 0.7f;
|
m_bankingMix = 0.7f;
|
||||||
m_bankingTimescale = 2;
|
m_bankingTimescale = 2;
|
||||||
m_lastBanking = Vector3.Zero;
|
|
||||||
|
|
||||||
m_referenceFrame = Quaternion.Identity;
|
m_referenceFrame = Quaternion.Identity;
|
||||||
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
|
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
|
||||||
|
@ -520,7 +506,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_bankingEfficiency = 0;
|
m_bankingEfficiency = 0;
|
||||||
m_bankingMix = 0.7f;
|
m_bankingMix = 0.7f;
|
||||||
m_bankingTimescale = 5;
|
m_bankingTimescale = 5;
|
||||||
m_lastBanking = Vector3.Zero;
|
|
||||||
|
|
||||||
m_referenceFrame = Quaternion.Identity;
|
m_referenceFrame = Quaternion.Identity;
|
||||||
|
|
||||||
|
@ -554,8 +539,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// Z goes away and we keep X and Y
|
// Z goes away and we keep X and Y
|
||||||
m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
|
m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
|
||||||
m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
|
m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
|
||||||
|
|
||||||
// m_bankingMotor = new BSVMotor("BankingMotor", ...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some of the properties of this prim may have changed.
|
// Some of the properties of this prim may have changed.
|
||||||
|
@ -577,15 +560,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
|
float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
|
||||||
BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
|
BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
|
||||||
|
|
||||||
|
// Vehicles report collision events so we know when it's on the ground
|
||||||
|
BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
|
||||||
|
|
||||||
// DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
|
// DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
|
||||||
// Vector3 localInertia = new Vector3(1f, 1f, 1f);
|
// Vector3 localInertia = new Vector3(1f, 1f, 1f);
|
||||||
Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
|
// Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
|
||||||
|
Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass);
|
||||||
BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
|
BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
|
||||||
BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
|
BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
|
||||||
|
|
||||||
VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
|
VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
|
||||||
Prim.LocalID, friction, localInertia, angularDamping);
|
Prim.LocalID, friction, localInertia, angularDamping);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RemoveBodyDependencies(BSPhysObject prim)
|
public bool RemoveBodyDependencies(BSPhysObject prim)
|
||||||
|
@ -618,13 +609,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
private float? m_knownWaterLevel;
|
private float? m_knownWaterLevel;
|
||||||
private Vector3? m_knownPosition;
|
private Vector3? m_knownPosition;
|
||||||
private Vector3? m_knownVelocity;
|
private Vector3? m_knownVelocity;
|
||||||
|
private Vector3 m_knownForce;
|
||||||
private Quaternion? m_knownOrientation;
|
private Quaternion? m_knownOrientation;
|
||||||
private Vector3? m_knownRotationalVelocity;
|
private Vector3? m_knownRotationalVelocity;
|
||||||
|
private Vector3 m_knownRotationalForce;
|
||||||
|
private float? m_knownForwardSpeed;
|
||||||
|
|
||||||
private const int m_knownChangedPosition = 1 << 0;
|
private const int m_knownChangedPosition = 1 << 0;
|
||||||
private const int m_knownChangedVelocity = 1 << 1;
|
private const int m_knownChangedVelocity = 1 << 1;
|
||||||
private const int m_knownChangedOrientation = 1 << 2;
|
private const int m_knownChangedForce = 1 << 2;
|
||||||
private const int m_knownChangedRotationalVelocity = 1 << 3;
|
private const int m_knownChangedOrientation = 1 << 3;
|
||||||
|
private const int m_knownChangedRotationalVelocity = 1 << 4;
|
||||||
|
private const int m_knownChangedRotationalForce = 1 << 5;
|
||||||
|
|
||||||
private void ForgetKnownVehicleProperties()
|
private void ForgetKnownVehicleProperties()
|
||||||
{
|
{
|
||||||
|
@ -632,8 +628,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_knownWaterLevel = null;
|
m_knownWaterLevel = null;
|
||||||
m_knownPosition = null;
|
m_knownPosition = null;
|
||||||
m_knownVelocity = null;
|
m_knownVelocity = null;
|
||||||
|
m_knownForce = Vector3.Zero;
|
||||||
m_knownOrientation = null;
|
m_knownOrientation = null;
|
||||||
m_knownRotationalVelocity = null;
|
m_knownRotationalVelocity = null;
|
||||||
|
m_knownRotationalForce = Vector3.Zero;
|
||||||
|
m_knownForwardSpeed = null;
|
||||||
m_knownChanged = 0;
|
m_knownChanged = 0;
|
||||||
}
|
}
|
||||||
private void PushKnownChanged()
|
private void PushKnownChanged()
|
||||||
|
@ -645,12 +644,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
if ((m_knownChanged & m_knownChangedOrientation) != 0)
|
if ((m_knownChanged & m_knownChangedOrientation) != 0)
|
||||||
Prim.ForceOrientation = VehicleOrientation;
|
Prim.ForceOrientation = VehicleOrientation;
|
||||||
if ((m_knownChanged & m_knownChangedVelocity) != 0)
|
if ((m_knownChanged & m_knownChangedVelocity) != 0)
|
||||||
|
{
|
||||||
Prim.ForceVelocity = VehicleVelocity;
|
Prim.ForceVelocity = VehicleVelocity;
|
||||||
|
BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity);
|
||||||
|
}
|
||||||
|
if ((m_knownChanged & m_knownChangedForce) != 0)
|
||||||
|
Prim.AddForce((Vector3)m_knownForce, false, true);
|
||||||
|
|
||||||
if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
|
if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
|
||||||
{
|
{
|
||||||
Prim.ForceRotationalVelocity = VehicleRotationalVelocity;
|
Prim.ForceRotationalVelocity = VehicleRotationalVelocity;
|
||||||
|
// Fake out Bullet by making it think the velocity is the same as last time.
|
||||||
BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity);
|
BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity);
|
||||||
}
|
}
|
||||||
|
if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
|
||||||
|
Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true);
|
||||||
|
|
||||||
// If we set one of the values (ie, the physics engine didn't do it) we must force
|
// If we set one of the values (ie, the physics engine didn't do it) we must force
|
||||||
// an UpdateProperties event to send the changes up to the simulator.
|
// an UpdateProperties event to send the changes up to the simulator.
|
||||||
BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr);
|
BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr);
|
||||||
|
@ -720,6 +729,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void VehicleAddForce(Vector3 aForce)
|
||||||
|
{
|
||||||
|
m_knownForce += aForce;
|
||||||
|
m_knownChanged |= m_knownChangedForce;
|
||||||
|
}
|
||||||
|
|
||||||
private Vector3 VehicleRotationalVelocity
|
private Vector3 VehicleRotationalVelocity
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -734,6 +749,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_knownChanged |= m_knownChangedRotationalVelocity;
|
m_knownChanged |= m_knownChangedRotationalVelocity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void VehicleAddAngularForce(Vector3 aForce)
|
||||||
|
{
|
||||||
|
m_knownRotationalForce += aForce;
|
||||||
|
m_knownChanged |= m_knownChangedRotationalForce;
|
||||||
|
}
|
||||||
|
private float VehicleForwardSpeed
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (m_knownForwardSpeed == null)
|
||||||
|
m_knownForwardSpeed = (VehicleVelocity * Quaternion.Inverse(VehicleOrientation)).X;
|
||||||
|
return (float)m_knownForwardSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion // Known vehicle value functions
|
#endregion // Known vehicle value functions
|
||||||
|
|
||||||
// One step of the vehicle properties for the next 'pTimestep' seconds.
|
// One step of the vehicle properties for the next 'pTimestep' seconds.
|
||||||
|
@ -769,10 +799,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
linearMotorContribution *= VehicleOrientation;
|
linearMotorContribution *= VehicleOrientation;
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// Gravity and Buoyancy
|
// Buoyancy: force to overcome gravity.
|
||||||
// There is some gravity, make a gravity force vector that is applied after object velocity.
|
|
||||||
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
|
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
|
||||||
Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
|
// So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
|
||||||
|
Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
|
||||||
|
|
||||||
Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
|
Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
|
||||||
|
|
||||||
|
@ -797,14 +827,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
newVelocity.Z = 0;
|
newVelocity.Z = 0;
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// Clamp REALLY high or low velocities
|
// Clamp high or low velocities
|
||||||
float newVelocityLengthSq = newVelocity.LengthSquared();
|
float newVelocityLengthSq = newVelocity.LengthSquared();
|
||||||
if (newVelocityLengthSq > 1e6f)
|
// if (newVelocityLengthSq > 1e6f)
|
||||||
|
if (newVelocityLengthSq > 1000f)
|
||||||
{
|
{
|
||||||
newVelocity /= newVelocity.Length();
|
newVelocity /= newVelocity.Length();
|
||||||
newVelocity *= 1000f;
|
newVelocity *= 1000f;
|
||||||
}
|
}
|
||||||
else if (newVelocityLengthSq < 1e-6f)
|
// else if (newVelocityLengthSq < 1e-6f)
|
||||||
|
else if (newVelocityLengthSq < 0.001f)
|
||||||
newVelocity = Vector3.Zero;
|
newVelocity = Vector3.Zero;
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
|
@ -813,15 +845,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
VehicleVelocity = newVelocity;
|
VehicleVelocity = newVelocity;
|
||||||
|
|
||||||
// Other linear forces are applied as forces.
|
// Other linear forces are applied as forces.
|
||||||
Vector3 totalDownForce = grav * m_vehicleMass * pTimestep;
|
Vector3 totalDownForce = buoyancyContribution * m_vehicleMass;
|
||||||
if (totalDownForce != Vector3.Zero)
|
if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
|
||||||
{
|
{
|
||||||
Prim.AddForce(totalDownForce, false);
|
VehicleAddForce(totalDownForce);
|
||||||
}
|
}
|
||||||
|
|
||||||
VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},linContrib={3},terrContrib={4},hoverContrib={5},limitContrib={6}",
|
VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}",
|
||||||
Prim.LocalID, newVelocity, totalDownForce,
|
Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding);
|
||||||
linearMotorContribution, terrainHeightContribution, hoverContribution, limitMotorUpContribution
|
VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
|
||||||
|
Prim.LocalID,
|
||||||
|
linearMotorContribution, terrainHeightContribution, hoverContribution,
|
||||||
|
limitMotorUpContribution, buoyancyContribution
|
||||||
);
|
);
|
||||||
|
|
||||||
} // end MoveLinear()
|
} // end MoveLinear()
|
||||||
|
@ -942,21 +977,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
// From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
|
// From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
|
||||||
// Prevent ground vehicles from motoring into the sky.This flag has a subtle effect when
|
// Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
|
||||||
// used with conjunction with banking: the strength of the banking will decay when the
|
// used with conjunction with banking: the strength of the banking will decay when the
|
||||||
// vehicle no longer experiences collisions. The decay timescale is the same as
|
// vehicle no longer experiences collisions. The decay timescale is the same as
|
||||||
// VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
|
// VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
|
||||||
// when they are in mid jump.
|
// when they are in mid jump.
|
||||||
// TODO: this code is wrong. Also, what should it do for boats?
|
// TODO: this code is wrong. Also, what should it do for boats (height from water)?
|
||||||
|
// This is just using the ground and a general collision check. Should really be using
|
||||||
|
// a downward raycast to find what is below.
|
||||||
public Vector3 ComputeLinearMotorUp(float pTimestep)
|
public Vector3 ComputeLinearMotorUp(float pTimestep)
|
||||||
{
|
{
|
||||||
Vector3 ret = Vector3.Zero;
|
Vector3 ret = Vector3.Zero;
|
||||||
|
|
||||||
if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
|
if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
|
||||||
{
|
{
|
||||||
// If the vehicle is motoring into the sky, get it going back down.
|
// If the vehicle is motoring into the sky, get it going back down.
|
||||||
// float distanceAboveGround = pos.Z - Math.Max(GetTerrainHeight(pos), GetWaterLevel(pos));
|
|
||||||
float distanceAboveGround = VehiclePosition.Z - GetTerrainHeight(VehiclePosition);
|
float distanceAboveGround = VehiclePosition.Z - GetTerrainHeight(VehiclePosition);
|
||||||
if (distanceAboveGround > 1f)
|
// Not colliding if the vehicle is off the ground
|
||||||
|
if (!Prim.IsColliding)
|
||||||
{
|
{
|
||||||
// downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
|
// downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
|
||||||
// downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
|
// downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
|
||||||
|
@ -977,8 +1015,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// Apply the effect of the angular motor.
|
// Apply the effect of the angular motor.
|
||||||
// The 'contribution' is how much angular correction velocity each function wants.
|
// The 'contribution' is how much angular correction velocity each function wants.
|
||||||
// All the contributions are added together and the orientation of the vehicle
|
// All the contributions are added together and the resulting velocity is
|
||||||
// is changed by all the contributed corrections.
|
// set directly on the vehicle.
|
||||||
private void MoveAngular(float pTimestep)
|
private void MoveAngular(float pTimestep)
|
||||||
{
|
{
|
||||||
// The user wants how many radians per second angular change?
|
// The user wants how many radians per second angular change?
|
||||||
|
@ -1001,7 +1039,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
Vector3 deflectionContribution = ComputeAngularDeflection();
|
Vector3 deflectionContribution = ComputeAngularDeflection();
|
||||||
|
|
||||||
Vector3 bankingContribution = ComputeAngularBanking(angularMotorContribution.Z);
|
Vector3 bankingContribution = ComputeAngularBanking();
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
m_lastVertAttractor = verticalAttractionContribution;
|
m_lastVertAttractor = verticalAttractionContribution;
|
||||||
|
@ -1013,11 +1051,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
+ bankingContribution;
|
+ bankingContribution;
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// The correction is applied to the current orientation.
|
// Apply the correction velocity.
|
||||||
|
// TODO: Should this be applied as an angular force (torque)?
|
||||||
if (!m_lastAngularCorrection.ApproxEquals(Vector3.Zero, 0.01f))
|
if (!m_lastAngularCorrection.ApproxEquals(Vector3.Zero, 0.01f))
|
||||||
{
|
{
|
||||||
Vector3 scaledCorrection = m_lastAngularCorrection * pTimestep;
|
Vector3 scaledCorrection = m_lastAngularCorrection * pTimestep;
|
||||||
|
|
||||||
VehicleRotationalVelocity = scaledCorrection;
|
VehicleRotationalVelocity = scaledCorrection;
|
||||||
|
|
||||||
VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5},scaledCorr={6}",
|
VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5},scaledCorr={6}",
|
||||||
|
@ -1029,7 +1067,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The vehicle is not adding anything velocity wise.
|
// The vehicle is not adding anything angular wise.
|
||||||
VehicleRotationalVelocity = Vector3.Zero;
|
VehicleRotationalVelocity = Vector3.Zero;
|
||||||
VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
|
VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
|
||||||
}
|
}
|
||||||
|
@ -1060,19 +1098,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
torqueFromOffset.Y = 0;
|
torqueFromOffset.Y = 0;
|
||||||
if (float.IsNaN(torqueFromOffset.Z))
|
if (float.IsNaN(torqueFromOffset.Z))
|
||||||
torqueFromOffset.Z = 0;
|
torqueFromOffset.Z = 0;
|
||||||
torqueFromOffset *= m_vehicleMass;
|
|
||||||
Prim.ApplyTorqueImpulse(torqueFromOffset, true);
|
VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
|
||||||
VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
|
VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
|
||||||
|
// Some vehicles, like boats, should always keep their up-side up. This can be done by
|
||||||
|
// enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
|
||||||
|
// the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
|
||||||
|
// VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
|
||||||
|
// and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
|
||||||
|
// efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
|
||||||
|
// efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
|
||||||
public Vector3 ComputeAngularVerticalAttraction()
|
public Vector3 ComputeAngularVerticalAttraction()
|
||||||
{
|
{
|
||||||
Vector3 ret = Vector3.Zero;
|
Vector3 ret = Vector3.Zero;
|
||||||
|
|
||||||
// If vertical attaction timescale is reasonable and we applied an angular force last time...
|
// If vertical attaction timescale is reasonable and we applied an angular force last time...
|
||||||
if (m_verticalAttractionTimescale < 500)
|
if (m_verticalAttractionTimescale < m_verticalAttractionCutoff)
|
||||||
{
|
{
|
||||||
// Take a vector pointing up and convert it from world to vehicle relative coords.
|
// Take a vector pointing up and convert it from world to vehicle relative coords.
|
||||||
Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
|
Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
|
||||||
|
@ -1097,91 +1142,121 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
ret.Y = - verticalError.X;
|
ret.Y = - verticalError.X;
|
||||||
ret.Z = 0f;
|
ret.Z = 0f;
|
||||||
|
|
||||||
// scale by the time scale and timestep
|
// Scale the correction force by how far we're off from vertical.
|
||||||
|
// Z error of one says little error. As Z gets smaller, the vehicle is leaning farther over.
|
||||||
|
float clampedSqrZError = ClampInRange(0.01f, verticalError.Z * verticalError.Z, 1f);
|
||||||
|
float vertForce = 1f / clampedSqrZError;
|
||||||
|
|
||||||
|
ret *= vertForce;
|
||||||
|
|
||||||
|
// Correction happens over a number of seconds.
|
||||||
Vector3 unscaledContrib = ret;
|
Vector3 unscaledContrib = ret;
|
||||||
ret /= m_verticalAttractionTimescale;
|
ret /= m_verticalAttractionTimescale;
|
||||||
// This returns the angular correction desired. Timestep is added later.
|
|
||||||
// ret *= pTimestep;
|
|
||||||
|
|
||||||
// apply efficiency
|
VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},vertForce={3},eff={4},vertAttr={5}",
|
||||||
Vector3 preEfficiencyContrib = ret;
|
Prim.LocalID, verticalError, unscaledContrib, vertForce, m_verticalAttractionEfficiency, ret);
|
||||||
// TODO: implement efficiency.
|
|
||||||
// Effenciency squared seems to give a more realistic effect
|
|
||||||
float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
|
|
||||||
// ret *= efficencySquared;
|
|
||||||
|
|
||||||
VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}",
|
|
||||||
Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib,
|
|
||||||
m_verticalAttractionEfficiency, efficencySquared,
|
|
||||||
ret);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the angular correction to correct the direction the vehicle is pointing to be
|
// Return the angular correction to correct the direction the vehicle is pointing to be
|
||||||
// the direction is should want to be pointing.
|
// the direction is should want to be pointing.
|
||||||
|
// The vehicle is moving in some direction and correct its orientation to it is pointing
|
||||||
|
// in that direction.
|
||||||
|
// TODO: implement reference frame.
|
||||||
public Vector3 ComputeAngularDeflection()
|
public Vector3 ComputeAngularDeflection()
|
||||||
{
|
{
|
||||||
Vector3 ret = Vector3.Zero;
|
Vector3 ret = Vector3.Zero;
|
||||||
|
return ret; // DEBUG DEBUG DEBUG debug one force at a time
|
||||||
|
|
||||||
if (m_angularDeflectionEfficiency != 0)
|
if (m_angularDeflectionEfficiency != 0)
|
||||||
{
|
{
|
||||||
// Where the vehicle should want to point relative to the vehicle
|
// The direction the vehicle is moving
|
||||||
Vector3 preferredDirection = Vector3.UnitX * m_referenceFrame;
|
Vector3 movingDirection = VehicleVelocity;
|
||||||
|
movingDirection.Normalize();
|
||||||
|
|
||||||
// Where the vehicle is pointing relative to the vehicle.
|
// The direction the vehicle is pointing
|
||||||
Vector3 currentDirection = Vector3.UnitX * Quaternion.Add(VehicleOrientation, m_referenceFrame);
|
Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
|
||||||
|
pointingDirection.Normalize();
|
||||||
|
|
||||||
// Difference between where vehicle is pointing and where it should wish to point
|
// The difference between what is and what should be
|
||||||
Vector3 directionCorrection = preferredDirection - currentDirection;
|
Vector3 deflectionError = movingDirection - pointingDirection;
|
||||||
|
|
||||||
// Scale the correction by recovery timescale and efficiency
|
// Scale the correction by recovery timescale and efficiency
|
||||||
ret = directionCorrection * m_angularDeflectionEfficiency / m_angularDeflectionTimescale;
|
ret = (-deflectionError * VehicleForwardSpeed) * m_angularDeflectionEfficiency;
|
||||||
|
ret /= m_angularDeflectionTimescale;
|
||||||
|
|
||||||
VDetailLog("{0}, MoveAngular,Deflection,perfDir={1},currentDir={2},dirCorrection={3},ret={4}",
|
VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
|
||||||
Prim.LocalID, preferredDirection, currentDirection, directionCorrection, ret);
|
Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return an angular change to tip the vehicle (around X axis) when turning (turned around Z).
|
// Return an angular change to rotate the vehicle around the Z axis when the vehicle
|
||||||
// Remembers the last banking value calculated and returns the difference needed this tick.
|
// is tipped around the X axis.
|
||||||
// TurningFactor is rate going left or right (pos=left, neg=right, scale=0..1).
|
// From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
|
||||||
public Vector3 ComputeAngularBanking(float turningFactor)
|
// The vertical attractor feature must be enabled in order for the banking behavior to
|
||||||
|
// function. The way banking works is this: a rotation around the vehicle's roll-axis will
|
||||||
|
// produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
|
||||||
|
// of the yaw effect will be proportional to the
|
||||||
|
// VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
|
||||||
|
// velocity along its preferred axis of motion.
|
||||||
|
// The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
|
||||||
|
// positive rotation (by the right-hand rule) about the roll-axis will effect a
|
||||||
|
// (negative) torque around the yaw-axis, making it turn to the right--that is the
|
||||||
|
// vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
|
||||||
|
// Negating the banking coefficient will make it so that the vehicle leans to the
|
||||||
|
// outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
|
||||||
|
// The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
|
||||||
|
// banking vehicles do what you want rather than what the laws of physics allow.
|
||||||
|
// For example, consider a real motorcycle...it must be moving forward in order for
|
||||||
|
// it to turn while banking, however video-game motorcycles are often configured
|
||||||
|
// to turn in place when at a dead stop--because they are often easier to control
|
||||||
|
// that way using the limited interface of the keyboard or game controller. The
|
||||||
|
// VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
|
||||||
|
// banking by functioning as a slider between a banking that is correspondingly
|
||||||
|
// totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
|
||||||
|
// banking effect depends only on the vehicle's rotation about its roll-axis compared
|
||||||
|
// to "dynamic" where the banking is also proportional to its velocity along its
|
||||||
|
// roll-axis. Finding the best value of the "mixture" will probably require trial and error.
|
||||||
|
// The time it takes for the banking behavior to defeat a preexisting angular velocity about the
|
||||||
|
// world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
|
||||||
|
// bank quickly then give it a banking timescale of about a second or less, otherwise you can
|
||||||
|
// make a sluggish vehicle by giving it a timescale of several seconds.
|
||||||
|
public Vector3 ComputeAngularBanking()
|
||||||
{
|
{
|
||||||
Vector3 ret = Vector3.Zero;
|
Vector3 ret = Vector3.Zero;
|
||||||
Vector3 computedBanking = Vector3.Zero;
|
|
||||||
|
|
||||||
if (m_bankingEfficiency != 0)
|
if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
|
||||||
{
|
{
|
||||||
Vector3 currentDirection = Vector3.UnitX * VehicleOrientation;
|
// This works by rotating a unit vector to the orientation of the vehicle. The
|
||||||
|
// roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
|
||||||
|
// up to one for full over).
|
||||||
|
Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
|
||||||
|
|
||||||
float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1);
|
// Figure out the yaw value for this much roll.
|
||||||
|
float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency;
|
||||||
|
// Keep the sign
|
||||||
|
if (rollComponents.Y < 0f)
|
||||||
|
turnComponent = -turnComponent;
|
||||||
|
|
||||||
//Use the square of the efficiency, as it looks much more how SL banking works
|
// TODO: there must be a better computation of the banking force.
|
||||||
float effSquared = (m_bankingEfficiency * m_bankingEfficiency);
|
float bankingTurnForce = turnComponent;
|
||||||
if (m_bankingEfficiency < 0)
|
|
||||||
effSquared *= -1; //Keep the negative!
|
|
||||||
|
|
||||||
float mix = Math.Abs(m_bankingMix);
|
// actual error = static turn error + dynamic turn error
|
||||||
// TODO: Must include reference frame.
|
float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed;
|
||||||
float forwardSpeed = VehicleVelocity.X;
|
// TODO: the banking effect should not go to infinity but what to limit it to?
|
||||||
|
mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f);
|
||||||
|
|
||||||
if (!Prim.IsColliding && forwardSpeed > mix)
|
// Build the force vector to change rotation from what it is to what it should be
|
||||||
{
|
ret.Z = -mixedBankingError;
|
||||||
computedBanking.X = ClampInRange(-3f, turningFactor * (effSquared * mult), 3f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'computedBanking' is now how much banking that should be happening.
|
// Don't do it all at once.
|
||||||
ret = computedBanking - m_lastBanking;
|
ret /= m_bankingTimescale;
|
||||||
|
|
||||||
// Scale the correction by timescale and efficiency
|
VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}",
|
||||||
ret /= m_bankingTimescale * m_bankingEfficiency;
|
Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret);
|
||||||
|
|
||||||
VDetailLog("{0}, MoveAngular,Banking,computedB={1},lastB={2},bEff={3},effSq={4},mult={5},mix={6},banking={7}",
|
|
||||||
Prim.LocalID, computedBanking, m_lastBanking, m_bankingEfficiency, effSquared, mult, mix, ret);
|
|
||||||
}
|
}
|
||||||
m_lastBanking = computedBanking;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,191 +1,185 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* * Redistributions in binary form must reproduce the above copyrightD
|
* * Redistributions in binary form must reproduce the above copyrightD
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
|
|
||||||
public struct MaterialAttributes
|
public struct MaterialAttributes
|
||||||
{
|
{
|
||||||
// Material type values that correspond with definitions for LSL
|
// Material type values that correspond with definitions for LSL
|
||||||
public enum Material : int
|
public enum Material : int
|
||||||
{
|
{
|
||||||
Stone = 0,
|
Stone = 0,
|
||||||
Metal,
|
Metal,
|
||||||
Glass,
|
Glass,
|
||||||
Wood,
|
Wood,
|
||||||
Flesh,
|
Flesh,
|
||||||
Plastic,
|
Plastic,
|
||||||
Rubber,
|
Rubber,
|
||||||
Light,
|
Light,
|
||||||
// Hereafter are BulletSim additions
|
// Hereafter are BulletSim additions
|
||||||
Avatar,
|
Avatar,
|
||||||
NumberOfTypes // the count of types in the enum.
|
NumberOfTypes // the count of types in the enum.
|
||||||
}
|
}
|
||||||
// Names must be in the order of the above enum.
|
// Names must be in the order of the above enum.
|
||||||
public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
|
public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
|
||||||
"Flesh", "Plastic", "Rubber", "Light", "Avatar" };
|
"Flesh", "Plastic", "Rubber", "Light", "Avatar" };
|
||||||
public static string[] MaterialAttribs = { "Density", "Friction", "Restitution",
|
public static string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
|
||||||
"ccdMotionThreshold", "ccdSweptSphereRadius" };
|
|
||||||
|
public MaterialAttributes(string t, float d, float f, float r)
|
||||||
public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS)
|
{
|
||||||
{
|
type = t;
|
||||||
type = t;
|
density = d;
|
||||||
density = d;
|
friction = f;
|
||||||
friction = f;
|
restitution = r;
|
||||||
restitution = r;
|
}
|
||||||
ccdMotionThreshold = ccdM;
|
public string type;
|
||||||
ccdSweptSphereRadius = ccdS;
|
public float density;
|
||||||
}
|
public float friction;
|
||||||
public string type;
|
public float restitution;
|
||||||
public float density;
|
}
|
||||||
public float friction;
|
|
||||||
public float restitution;
|
public static class BSMaterials
|
||||||
public float ccdMotionThreshold;
|
{
|
||||||
public float ccdSweptSphereRadius;
|
public static MaterialAttributes[] Attributes;
|
||||||
}
|
|
||||||
|
static BSMaterials()
|
||||||
public static class BSMaterials
|
{
|
||||||
{
|
// Attribute sets for both the non-physical and physical instances of materials.
|
||||||
public static MaterialAttributes[] Attributes;
|
Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
|
||||||
|
}
|
||||||
static BSMaterials()
|
|
||||||
{
|
// This is where all the default material attributes are defined.
|
||||||
// Attribute sets for both the non-physical and physical instances of materials.
|
public static void InitializeFromDefaults(ConfigurationParameters parms)
|
||||||
Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
|
{
|
||||||
}
|
// Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
|
||||||
|
// public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
|
||||||
// This is where all the default material attributes are defined.
|
// "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
|
||||||
public static void InitializeFromDefaults(ConfigurationParameters parms)
|
float dFriction = parms.defaultFriction;
|
||||||
{
|
float dRestitution = parms.defaultRestitution;
|
||||||
// public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
|
float dDensity = parms.defaultDensity;
|
||||||
// "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
|
Attributes[(int)MaterialAttributes.Material.Stone] =
|
||||||
float dFriction = parms.defaultFriction;
|
new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
|
||||||
float dRestitution = parms.defaultRestitution;
|
Attributes[(int)MaterialAttributes.Material.Metal] =
|
||||||
float dDensity = parms.defaultDensity;
|
new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
|
||||||
float dCcdM = parms.ccdMotionThreshold;
|
Attributes[(int)MaterialAttributes.Material.Glass] =
|
||||||
float dCcdS = parms.ccdSweptSphereRadius;
|
new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Stone] =
|
Attributes[(int)MaterialAttributes.Material.Wood] =
|
||||||
new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Metal] =
|
Attributes[(int)MaterialAttributes.Material.Flesh] =
|
||||||
new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Glass] =
|
Attributes[(int)MaterialAttributes.Material.Plastic] =
|
||||||
new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Wood] =
|
Attributes[(int)MaterialAttributes.Material.Rubber] =
|
||||||
new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Flesh] =
|
Attributes[(int)MaterialAttributes.Material.Light] =
|
||||||
new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("light",dDensity, dFriction, dRestitution);
|
||||||
Attributes[(int)MaterialAttributes.Material.Plastic] =
|
Attributes[(int)MaterialAttributes.Material.Avatar] =
|
||||||
new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("avatar",60f, 0.2f, 0f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Rubber] =
|
|
||||||
new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
Attributes[(int)MaterialAttributes.Material.Light] =
|
new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
|
||||||
new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
Attributes[(int)MaterialAttributes.Material.Avatar] =
|
new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f);
|
||||||
new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
|
new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
|
Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
|
Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
|
Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
|
Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
|
Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
|
||||||
Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
|
Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f);
|
||||||
Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
|
}
|
||||||
new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
|
||||||
Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
|
// Under the [BulletSim] section, one can change the individual material
|
||||||
new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
// attribute values. The format of the configuration parameter is:
|
||||||
Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
|
// <materialName><Attribute>["Physical"] = floatValue
|
||||||
new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
// For instance:
|
||||||
}
|
// [BulletSim]
|
||||||
|
// StoneFriction = 0.2
|
||||||
// Under the [BulletSim] section, one can change the individual material
|
// FleshRestitutionPhysical = 0.8
|
||||||
// attribute values. The format of the configuration parameter is:
|
// Materials can have different parameters for their static and
|
||||||
// <materialName><Attribute>["Physical"] = floatValue
|
// physical instantiations. When setting the non-physical value,
|
||||||
// For instance:
|
// both values are changed. Setting the physical value only changes
|
||||||
// [BulletSim]
|
// the physical value.
|
||||||
// StoneFriction = 0.2
|
public static void InitializefromParameters(IConfig pConfig)
|
||||||
// FleshRestitutionPhysical = 0.8
|
{
|
||||||
// Materials can have different parameters for their static and
|
int matType = 0;
|
||||||
// physical instantiations. When setting the non-physical value,
|
foreach (string matName in MaterialAttributes.MaterialNames)
|
||||||
// both values are changed. Setting the physical value only changes
|
{
|
||||||
// the physical value.
|
foreach (string attribName in MaterialAttributes.MaterialAttribs)
|
||||||
public static void InitializefromParameters(IConfig pConfig)
|
{
|
||||||
{
|
string paramName = matName + attribName;
|
||||||
int matType = 0;
|
if (pConfig.Contains(paramName))
|
||||||
foreach (string matName in MaterialAttributes.MaterialNames)
|
{
|
||||||
{
|
float paramValue = pConfig.GetFloat(paramName);
|
||||||
foreach (string attribName in MaterialAttributes.MaterialAttribs)
|
SetAttributeValue(matType, attribName, paramValue);
|
||||||
{
|
// set the physical value also
|
||||||
string paramName = matName + attribName;
|
SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
|
||||||
if (pConfig.Contains(paramName))
|
}
|
||||||
{
|
paramName += "Physical";
|
||||||
float paramValue = pConfig.GetFloat(paramName);
|
if (pConfig.Contains(paramName))
|
||||||
SetAttributeValue(matType, attribName, paramValue);
|
{
|
||||||
// set the physical value also
|
float paramValue = pConfig.GetFloat(paramName);
|
||||||
SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
|
SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
|
||||||
}
|
}
|
||||||
paramName += "Physical";
|
}
|
||||||
if (pConfig.Contains(paramName))
|
matType++;
|
||||||
{
|
}
|
||||||
float paramValue = pConfig.GetFloat(paramName);
|
}
|
||||||
SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
|
|
||||||
}
|
private static void SetAttributeValue(int matType, string attribName, float val)
|
||||||
}
|
{
|
||||||
matType++;
|
MaterialAttributes thisAttrib = Attributes[matType];
|
||||||
}
|
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
|
||||||
}
|
if (fieldInfo != null)
|
||||||
|
{
|
||||||
private static void SetAttributeValue(int matType, string attribName, float val)
|
fieldInfo.SetValue(thisAttrib, val);
|
||||||
{
|
Attributes[matType] = thisAttrib;
|
||||||
MaterialAttributes thisAttrib = Attributes[matType];
|
}
|
||||||
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
|
}
|
||||||
if (fieldInfo != null)
|
|
||||||
{
|
public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
|
||||||
fieldInfo.SetValue(thisAttrib, val);
|
{
|
||||||
Attributes[matType] = thisAttrib;
|
int ind = (int)type;
|
||||||
}
|
if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
|
||||||
}
|
return Attributes[ind];
|
||||||
|
}
|
||||||
public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
|
|
||||||
{
|
}
|
||||||
int ind = (int)type;
|
}
|
||||||
if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
|
|
||||||
return Attributes[ind];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1010,6 +1010,9 @@ public sealed class BSPrim : BSPhysObject
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// A torque impulse.
|
// A torque impulse.
|
||||||
|
// ApplyTorqueImpulse adds torque directly to the angularVelocity.
|
||||||
|
// AddAngularForce accumulates the force and applied it to the angular velocity all at once.
|
||||||
|
// Computed as: angularVelocity += impulse * inertia;
|
||||||
public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
|
public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
|
||||||
{
|
{
|
||||||
OMV.Vector3 applyImpulse = impulse;
|
OMV.Vector3 applyImpulse = impulse;
|
||||||
|
@ -1396,7 +1399,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
_rotationalVelocity = entprop.RotationalVelocity;
|
_rotationalVelocity = entprop.RotationalVelocity;
|
||||||
|
|
||||||
// The sanity check can change the velocity and/or position.
|
// The sanity check can change the velocity and/or position.
|
||||||
if (PositionSanityCheck(true))
|
if (IsPhysical && PositionSanityCheck(true))
|
||||||
{
|
{
|
||||||
entprop.Position = _position;
|
entprop.Position = _position;
|
||||||
entprop.Velocity = _velocity;
|
entprop.Velocity = _velocity;
|
||||||
|
@ -1410,8 +1413,6 @@ public sealed class BSPrim : BSPhysObject
|
||||||
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
|
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
|
||||||
LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
|
LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
|
||||||
|
|
||||||
// BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
|
|
||||||
|
|
||||||
base.RequestPhysicsterseUpdate();
|
base.RequestPhysicsterseUpdate();
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
|
private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
|
||||||
private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
|
private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
|
||||||
|
|
||||||
|
private bool DDetail = false;
|
||||||
|
|
||||||
public BSShapeCollection(BSScene physScene)
|
public BSShapeCollection(BSScene physScene)
|
||||||
{
|
{
|
||||||
PhysicsScene = physScene;
|
PhysicsScene = physScene;
|
||||||
|
// Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
|
||||||
|
// While detailed debugging is still active, this is better than commenting out all the
|
||||||
|
// DetailLog statements. When debugging slows down, this and the protected logging
|
||||||
|
// statements can be commented/removed.
|
||||||
|
DDetail = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -126,13 +133,13 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
lock (m_collectionActivityLock)
|
lock (m_collectionActivityLock)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
|
if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
|
||||||
{
|
{
|
||||||
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
||||||
{
|
{
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
|
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
|
if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -149,7 +156,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
|
PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
|
||||||
body.ID, body, inTaintTime);
|
body.ID, body, inTaintTime);
|
||||||
// If the caller needs to know the old body is going away, pass the event up.
|
// If the caller needs to know the old body is going away, pass the event up.
|
||||||
if (bodyCallback != null) bodyCallback(body);
|
if (bodyCallback != null) bodyCallback(body);
|
||||||
|
@ -157,7 +164,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
if (BulletSimAPI.IsInWorld2(body.ptr))
|
if (BulletSimAPI.IsInWorld2(body.ptr))
|
||||||
{
|
{
|
||||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
|
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
|
if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero any reference to the shape so it is not freed when the body is deleted.
|
// 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
|
||||||
{
|
{
|
||||||
// There is an existing instance of this mesh.
|
// There is an existing instance of this mesh.
|
||||||
meshDesc.referenceCount++;
|
meshDesc.referenceCount++;
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -194,7 +201,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
meshDesc.shapeKey = shape.shapeKey;
|
meshDesc.shapeKey = shape.shapeKey;
|
||||||
// We keep a reference to the underlying IMesh data so a hull can be built
|
// We keep a reference to the underlying IMesh data so a hull can be built
|
||||||
meshDesc.referenceCount = 1;
|
meshDesc.referenceCount = 1;
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
@ -207,7 +214,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
// There is an existing instance of this hull.
|
// There is an existing instance of this hull.
|
||||||
hullDesc.referenceCount++;
|
hullDesc.referenceCount++;
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -216,7 +223,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
hullDesc.ptr = shape.ptr;
|
hullDesc.ptr = shape.ptr;
|
||||||
hullDesc.shapeKey = shape.shapeKey;
|
hullDesc.shapeKey = shape.shapeKey;
|
||||||
hullDesc.referenceCount = 1;
|
hullDesc.referenceCount = 1;
|
||||||
DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
|
||||||
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
|
@ -246,7 +253,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
if (shape.isNativeShape)
|
if (shape.isNativeShape)
|
||||||
{
|
{
|
||||||
// Native shapes are not tracked and are released immediately
|
// Native shapes are not tracked and are released immediately
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
||||||
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
||||||
if (shapeCallback != null) shapeCallback(shape);
|
if (shapeCallback != null) shapeCallback(shape);
|
||||||
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
||||||
|
@ -286,7 +293,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
if (shapeCallback != null) shapeCallback(shape);
|
if (shapeCallback != null) shapeCallback(shape);
|
||||||
meshDesc.lastReferenced = System.DateTime.Now;
|
meshDesc.lastReferenced = System.DateTime.Now;
|
||||||
Meshes[shape.shapeKey] = meshDesc;
|
Meshes[shape.shapeKey] = meshDesc;
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
|
||||||
BSScene.DetailLogZero, shape, meshDesc.referenceCount);
|
BSScene.DetailLogZero, shape, meshDesc.referenceCount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -307,7 +314,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
hullDesc.lastReferenced = System.DateTime.Now;
|
hullDesc.lastReferenced = System.DateTime.Now;
|
||||||
Hulls[shape.shapeKey] = hullDesc;
|
Hulls[shape.shapeKey] = hullDesc;
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
|
||||||
BSScene.DetailLogZero, shape, hullDesc.referenceCount);
|
BSScene.DetailLogZero, shape, hullDesc.referenceCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,13 +332,13 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
// Failed the sanity check!!
|
// Failed the sanity check!!
|
||||||
PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
|
PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
|
||||||
LogHeader, shape.type, shape.ptr.ToString("X"));
|
LogHeader, shape.type, shape.ptr.ToString("X"));
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
|
||||||
BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
|
BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
|
int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
|
if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
|
||||||
|
|
||||||
for (int ii = numChildren - 1; ii >= 0; ii--)
|
for (int ii = numChildren - 1; ii >= 0; ii--)
|
||||||
{
|
{
|
||||||
|
@ -379,7 +386,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
|
if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
|
||||||
|
|
||||||
if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
|
if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
|
||||||
{
|
{
|
||||||
|
@ -410,7 +417,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
// an avatar capsule is close to a native shape (it is not shared)
|
// an avatar capsule is close to a native shape (it is not shared)
|
||||||
ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
|
ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
|
||||||
FixedShapeKey.KEY_CAPSULE, shapeCallback);
|
FixedShapeKey.KEY_CAPSULE, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
|
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
|
||||||
ret = true;
|
ret = true;
|
||||||
haveShape = true;
|
haveShape = true;
|
||||||
}
|
}
|
||||||
|
@ -420,7 +427,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
|
if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
|
||||||
{
|
{
|
||||||
ret = GetReferenceToCompoundShape(prim, shapeCallback);
|
ret = GetReferenceToCompoundShape(prim, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
|
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
|
||||||
haveShape = true;
|
haveShape = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,7 +472,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
|
ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
|
||||||
FixedShapeKey.KEY_SPHERE, shapeCallback);
|
FixedShapeKey.KEY_SPHERE, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
|
||||||
prim.LocalID, forceRebuild, prim.PhysShape);
|
prim.LocalID, forceRebuild, prim.PhysShape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,7 +486,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
|
ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
|
||||||
FixedShapeKey.KEY_BOX, shapeCallback);
|
FixedShapeKey.KEY_BOX, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
|
||||||
prim.LocalID, forceRebuild, prim.PhysShape);
|
prim.LocalID, forceRebuild, prim.PhysShape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,13 +511,13 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
// Update prim.BSShape to reference a hull of this shape.
|
// Update prim.BSShape to reference a hull of this shape.
|
||||||
ret = GetReferenceToHull(prim,shapeCallback);
|
ret = GetReferenceToHull(prim,shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
|
||||||
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = GetReferenceToMesh(prim, shapeCallback);
|
ret = GetReferenceToMesh(prim, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
|
||||||
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -528,7 +535,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
|
BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
|
||||||
|
|
||||||
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
||||||
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
|
||||||
prim.LocalID, newShape, prim.Scale);
|
prim.LocalID, newShape, prim.Scale);
|
||||||
|
|
||||||
prim.PhysShape = newShape;
|
prim.PhysShape = newShape;
|
||||||
|
@ -554,7 +561,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
newShape = new BulletShape(
|
newShape = new BulletShape(
|
||||||
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
|
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
|
||||||
, shapeType);
|
, shapeType);
|
||||||
DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
|
if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -589,7 +596,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
|
if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
|
||||||
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
|
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
|
||||||
|
|
||||||
// Since we're recreating new, get rid of the reference to the previous shape
|
// Since we're recreating new, get rid of the reference to the previous shape
|
||||||
|
@ -662,7 +669,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
|
if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
|
||||||
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
|
prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
|
||||||
|
|
||||||
// Remove usage of the previous shape.
|
// Remove usage of the previous shape.
|
||||||
|
@ -808,7 +815,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
// Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
|
// Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
|
||||||
CreateGeomMeshOrHull(prim, shapeCallback);
|
CreateGeomMeshOrHull(prim, shapeCallback);
|
||||||
BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
|
BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
|
||||||
DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
|
if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
|
||||||
prim.LocalID, cShape, prim.PhysShape);
|
prim.LocalID, cShape, prim.PhysShape);
|
||||||
|
|
||||||
prim.PhysShape = cShape;
|
prim.PhysShape = cShape;
|
||||||
|
@ -935,13 +942,13 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
|
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
|
||||||
prim.LocalID, prim.RawPosition, prim.RawOrientation);
|
prim.LocalID, prim.RawPosition, prim.RawOrientation);
|
||||||
DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
|
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
|
||||||
prim.LocalID, prim.RawPosition, prim.RawOrientation);
|
prim.LocalID, prim.RawPosition, prim.RawOrientation);
|
||||||
DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
||||||
}
|
}
|
||||||
aBody = new BulletBody(prim.LocalID, bodyPtr);
|
aBody = new BulletBody(prim.LocalID, bodyPtr);
|
||||||
|
|
||||||
|
|
|
@ -360,6 +360,7 @@ public enum CollisionFlags : uint
|
||||||
// Following used by BulletSim to control collisions and updates
|
// Following used by BulletSim to control collisions and updates
|
||||||
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
|
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
|
||||||
BS_FLOATS_ON_WATER = 1 << 11,
|
BS_FLOATS_ON_WATER = 1 << 11,
|
||||||
|
BS_VEHICLE_COLLISIONS = 1 << 12,
|
||||||
BS_NONE = 0,
|
BS_NONE = 0,
|
||||||
BS_ALL = 0xFFFFFFFF,
|
BS_ALL = 0xFFFFFFFF,
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,34 @@ CRASHES
|
||||||
Causes many errors. Doesn't stop after first error with box shape.
|
Causes many errors. Doesn't stop after first error with box shape.
|
||||||
Eventually crashes when deleting the object.
|
Eventually crashes when deleting the object.
|
||||||
|
|
||||||
BULLETSIM TODO LIST:
|
VEHICLES TODO LIST:
|
||||||
=================================================
|
=================================================
|
||||||
Neb car jiggling left and right
|
Neb car jiggling left and right
|
||||||
|
Happens on terrain and any other mesh object. Flat cubes are much smoother.
|
||||||
Vehicles (Move smoothly)
|
Vehicles (Move smoothly)
|
||||||
Light cycle falling over when driving
|
Add vehicle collisions so IsColliding is properly reported.
|
||||||
Light cycle not banking
|
Needed for banking, limitMotorUp, movementLimiting, ...
|
||||||
Do single prim vehicles don't seem to properly vehiclize.
|
Some vehicles should not be able to turn if no speed or off ground.
|
||||||
Gun sending shooter flying
|
For limitMotorUp, use raycast down to find if vehicle is in the air.
|
||||||
|
Implement function efficiency for lineaar and angular motion.
|
||||||
|
Should vehicle angular/linear movement friction happen after all the components
|
||||||
|
or does it only apply to the basic movement?
|
||||||
|
After getting off a vehicle, the root prim is phantom (can be walked through)
|
||||||
|
Need to force a position update for the root prim after compound shape destruction
|
||||||
|
Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
|
||||||
|
Implement referenceFrame for all the motion routines.
|
||||||
|
Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
|
||||||
|
|
||||||
|
BULLETSIM TODO LIST:
|
||||||
|
=================================================
|
||||||
|
Disable activity of passive linkset children.
|
||||||
|
Since the linkset is a compound object, the old prims are left lying
|
||||||
|
around and need to be phantomized so they don't collide, ...
|
||||||
|
Scenes with hundred of thousands of static objects take a lot of physics CPU time.
|
||||||
|
BSPrim.Force should set a continious force on the prim. The force should be
|
||||||
|
applied each tick. Some limits?
|
||||||
|
Single prim vehicles don't seem to properly vehiclize.
|
||||||
|
Gun sending shooter flying.
|
||||||
Collision margin (gap between physical objects lying on each other)
|
Collision margin (gap between physical objects lying on each other)
|
||||||
Boundry checking (crashes related to crossing boundry)
|
Boundry checking (crashes related to crossing boundry)
|
||||||
Add check for border edge position for avatars and objects.
|
Add check for border edge position for avatars and objects.
|
||||||
|
@ -28,10 +48,11 @@ Small physical objects do not interact correctly
|
||||||
Add material type linkage and input all the material property definitions.
|
Add material type linkage and input all the material property definitions.
|
||||||
Skeleton classes and table are in the sources but are not filled or used.
|
Skeleton classes and table are in the sources but are not filled or used.
|
||||||
Add PID motor for avatar movement (slow to stop, ...)
|
Add PID motor for avatar movement (slow to stop, ...)
|
||||||
Implement function efficiency for lineaar and angular motion.
|
setForce should set a constant force. Different than AddImpulse.
|
||||||
|
Implement raycast.
|
||||||
|
Implement ShapeCollection.Dispose()
|
||||||
|
Implement water as a plain so raycasting and collisions can happen with same.
|
||||||
|
|
||||||
After getting off a vehicle, the root prim is phantom (can be walked through)
|
|
||||||
Need to force a position update for the root prim after compound shape destruction
|
|
||||||
Find/remove avatar collision with ID=0.
|
Find/remove avatar collision with ID=0.
|
||||||
Test avatar walking up stairs. How does compare with SL.
|
Test avatar walking up stairs. How does compare with SL.
|
||||||
Radius of the capsule affects ability to climb edges.
|
Radius of the capsule affects ability to climb edges.
|
||||||
|
@ -39,19 +60,16 @@ Tune terrain/object friction to be closer to SL.
|
||||||
Debounce avatar contact so legs don't keep folding up when standing.
|
Debounce avatar contact so legs don't keep folding up when standing.
|
||||||
Implement LSL physics controls. Like STATUS_ROTATE_X.
|
Implement LSL physics controls. Like STATUS_ROTATE_X.
|
||||||
Add border extensions to terrain to help region crossings and objects leaving region.
|
Add border extensions to terrain to help region crossings and objects leaving region.
|
||||||
Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
|
|
||||||
|
|
||||||
Speed up creation of large physical linksets
|
Speed up creation of large physical linksets
|
||||||
For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
|
For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
|
||||||
Performance test with lots of avatars. Can BulletSim support a thousand?
|
Performance test with lots of avatars. Can BulletSim support a thousand?
|
||||||
Optimize collisions in C++: only send up to the object subscribed to collisions.
|
Optimize collisions in C++: only send up to the object subscribed to collisions.
|
||||||
Use collision subscription and remove the collsion(A,B) and collision(B,A)
|
Use collision subscription and remove the collsion(A,B) and collision(B,A)
|
||||||
Check wheter SimMotionState needs large if statement (see TODO).
|
Check whether SimMotionState needs large if statement (see TODO).
|
||||||
|
|
||||||
Implement 'top colliders' info.
|
Implement 'top colliders' info.
|
||||||
Avatar jump
|
Avatar jump
|
||||||
Implement meshes or just verify that they work.
|
|
||||||
Do prim hash codes work for sculpties and meshes?
|
|
||||||
Performance measurement and changes to make quicker.
|
Performance measurement and changes to make quicker.
|
||||||
Implement detailed physics stats (GetStats()).
|
Implement detailed physics stats (GetStats()).
|
||||||
|
|
||||||
|
@ -67,8 +85,6 @@ Performance of closures and delegates for taint processing
|
||||||
Is there are more efficient method of implementing pre and post step actions?
|
Is there are more efficient method of implementing pre and post step actions?
|
||||||
See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
|
See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
|
||||||
|
|
||||||
Package Bullet source mods for Bullet internal stats output
|
|
||||||
|
|
||||||
Physics Arena central pyramid: why is one side permiable?
|
Physics Arena central pyramid: why is one side permiable?
|
||||||
|
|
||||||
INTERNAL IMPROVEMENT/CLEANUP
|
INTERNAL IMPROVEMENT/CLEANUP
|
||||||
|
@ -85,33 +101,42 @@ Complete implemention of preStepActions
|
||||||
Replace vehicle step call with prestep event.
|
Replace vehicle step call with prestep event.
|
||||||
Is there a need for postStepActions? postStepTaints?
|
Is there a need for postStepActions? postStepTaints?
|
||||||
Implement linkset by setting position of children when root updated. (LinksetManual)
|
Implement linkset by setting position of children when root updated. (LinksetManual)
|
||||||
|
Linkset implementation using manual prim movement.
|
||||||
LinkablePrim class? Would that simplify/centralize the linkset logic?
|
LinkablePrim class? Would that simplify/centralize the linkset logic?
|
||||||
Linkset implementation using manual prim movement.
|
|
||||||
Linkset implementation using compound shapes.
|
|
||||||
Compound shapes will need the LocalID in the shapes and collision
|
|
||||||
processing to get it from there.
|
|
||||||
BSScene.UpdateParameterSet() is broken. How to set params on objects?
|
BSScene.UpdateParameterSet() is broken. How to set params on objects?
|
||||||
Remove HeightmapInfo from terrain specification.
|
Remove HeightmapInfo from terrain specification.
|
||||||
Since C++ code does not need terrain height, this structure et al are not needed.
|
Since C++ code does not need terrain height, this structure et al are not needed.
|
||||||
Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
|
Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
|
||||||
bob at the water level. BSPrim.PositionSanityCheck().
|
bob at the water level. BSPrim.PositionSanityCheck().
|
||||||
|
|
||||||
|
THREADING
|
||||||
|
=================================================
|
||||||
|
Do taint action immediately if not actually executing Bullet.
|
||||||
|
Add lock around Bullet execution and just do taint actions if simulation is not happening.
|
||||||
|
|
||||||
DONE DONE DONE DONE
|
DONE DONE DONE DONE
|
||||||
=================================================
|
=================================================
|
||||||
Cleanup code in BSDynamics by using motors.
|
Cleanup code in BSDynamics by using motors. (Resolution: started)
|
||||||
Consider implementing terrain with a mesh rather than heightmap.
|
Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
|
||||||
Would have better and adjustable resolution.
|
Would have better and adjustable resolution.
|
||||||
NOTDONE: Build terrain mesh so heighmap is height of the center of the square meter.
|
Build terrain mesh so heighmap is height of the center of the square meter.
|
||||||
SL and ODE define meter square as being at one corner with one diagional.
|
Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
|
||||||
Terrain as mesh.
|
Terrain as mesh. (Resolution: done)
|
||||||
How are static linksets seen by the physics engine?
|
How are static linksets seen by the physics engine?
|
||||||
A: they are not linked in physics. When moved, all the children are repositioned.
|
Resolution: they are not linked in physics. When moved, all the children are repositioned.
|
||||||
Remember to remove BSScene.DetailLog Refresh call.
|
Convert BSCharacter to use all API2 (Resolution: done)
|
||||||
Convert BSCharacter to use all API2
|
|
||||||
Avatar pushing difficult (too heavy?)
|
Avatar pushing difficult (too heavy?)
|
||||||
Use asset service passed to BulletSim to get sculptie bodies, etc.
|
Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
|
||||||
Vehicles (fix bouncing on terrain)
|
Remove old code in DLL (all non-API2 stuff). (Resolution: done)
|
||||||
Remove old code in DLL (all non-API2 stuff).
|
Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
|
||||||
Measurements of mega-physical prim performance (with graph)
|
|
||||||
Debug Bullet internal stats output (why is timing all wrong?)
|
Debug Bullet internal stats output (why is timing all wrong?)
|
||||||
Bullet stats logging only works with a single instance of Bullet (one region).
|
Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
|
||||||
|
Implement meshes or just verify that they work. (Resolution: they do!)
|
||||||
|
Do prim hash codes work for sculpties and meshes? (Resolution: yes)
|
||||||
|
Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
|
||||||
|
Compound shapes will need the LocalID in the shapes and collision
|
||||||
|
processing to get it from there.
|
||||||
|
Light cycle falling over when driving (Resolution: implemented VerticalAttractor)
|
||||||
|
Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
|
||||||
|
Package Bullet source mods for Bullet internal stats output
|
||||||
|
(Resolution: move code into WorldData.h rather than relying on patches)
|
|
@ -114,6 +114,16 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
|
||||||
UUID AssetID { get; }
|
UUID AssetID { get; }
|
||||||
Queue EventQueue { get; }
|
Queue EventQueue { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of events queued for processing.
|
||||||
|
/// </summary>
|
||||||
|
long EventsQueued { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of events processed by this script instance.
|
||||||
|
/// </summary>
|
||||||
|
long EventsProcessed { get; }
|
||||||
|
|
||||||
void ClearQueue();
|
void ClearQueue();
|
||||||
int StartParam { get; set; }
|
int StartParam { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
|
|
||||||
public Queue EventQueue { get; private set; }
|
public Queue EventQueue { get; private set; }
|
||||||
|
|
||||||
|
public long EventsQueued
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (EventQueue)
|
||||||
|
return EventQueue.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long EventsProcessed { get; private set; }
|
||||||
|
|
||||||
public int StartParam { get; set; }
|
public int StartParam { get; set; }
|
||||||
|
|
||||||
public TaskInventoryItem ScriptTask { get; private set; }
|
public TaskInventoryItem ScriptTask { get; private set; }
|
||||||
|
@ -776,6 +787,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
ChatTypeEnum.DebugChannel, 2147483647,
|
ChatTypeEnum.DebugChannel, 2147483647,
|
||||||
part.AbsolutePosition,
|
part.AbsolutePosition,
|
||||||
part.Name, part.UUID, false);
|
part.Name, part.UUID, false);
|
||||||
|
|
||||||
|
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[SCRIPT INSTANCE]: Runtime error in script {0}, part {1} {2} at {3} in {4}, displayed error {5}, actual exception {6}",
|
||||||
|
ScriptName,
|
||||||
|
PrimName,
|
||||||
|
part.UUID,
|
||||||
|
part.AbsolutePosition,
|
||||||
|
part.ParentGroup.Scene.Name,
|
||||||
|
text.Replace("\n", "\\n"),
|
||||||
|
e.InnerException);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
@ -810,6 +832,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
// script engine to run the next event.
|
// script engine to run the next event.
|
||||||
lock (EventQueue)
|
lock (EventQueue)
|
||||||
{
|
{
|
||||||
|
EventsProcessed++;
|
||||||
|
|
||||||
if (EventQueue.Count > 0 && Running && !ShuttingDown)
|
if (EventQueue.Count > 0 && Running && !ShuttingDown)
|
||||||
{
|
{
|
||||||
m_CurrentWorkItem = Engine.QueueEventHandler(this);
|
m_CurrentWorkItem = Engine.QueueEventHandler(this);
|
||||||
|
@ -1015,7 +1039,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
"({0}): {1}", scriptLine - 1,
|
"({0}): {1}", scriptLine - 1,
|
||||||
e.InnerException.Message);
|
e.InnerException.Message);
|
||||||
|
|
||||||
System.Console.WriteLine(e.ToString()+"\n");
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
protected XEngine.XEngine m_engine;
|
protected XEngine.XEngine m_engine;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
IConfigSource initConfigSource = new IniConfigSource();
|
IConfigSource initConfigSource = new IniConfigSource();
|
||||||
IConfig config = initConfigSource.AddConfig("XEngine");
|
IConfig config = initConfigSource.AddConfig("XEngine");
|
||||||
config.Set("Enabled", "true");
|
config.Set("Enabled", "true");
|
||||||
|
|
|
@ -62,8 +62,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
protected XEngine.XEngine m_engine;
|
protected XEngine.XEngine m_engine;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
IConfigSource initConfigSource = new IniConfigSource();
|
IConfigSource initConfigSource = new IniConfigSource();
|
||||||
IConfig config = initConfigSource.AddConfig("XEngine");
|
IConfig config = initConfigSource.AddConfig("XEngine");
|
||||||
config.Set("Enabled", "true");
|
config.Set("Enabled", "true");
|
||||||
|
|
|
@ -51,8 +51,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
private LSL_Api m_lslApi;
|
private LSL_Api m_lslApi;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
IConfigSource initConfigSource = new IniConfigSource();
|
IConfigSource initConfigSource = new IniConfigSource();
|
||||||
IConfig config = initConfigSource.AddConfig("XEngine");
|
IConfig config = initConfigSource.AddConfig("XEngine");
|
||||||
config.Set("Enabled", "true");
|
config.Set("Enabled", "true");
|
||||||
|
|
|
@ -57,8 +57,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
protected XEngine.XEngine m_engine;
|
protected XEngine.XEngine m_engine;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
IConfigSource initConfigSource = new IniConfigSource();
|
IConfigSource initConfigSource = new IniConfigSource();
|
||||||
IConfig config = initConfigSource.AddConfig("XEngine");
|
IConfig config = initConfigSource.AddConfig("XEngine");
|
||||||
config.Set("Enabled", "true");
|
config.Set("Enabled", "true");
|
||||||
|
|
|
@ -127,12 +127,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
OSSL_Api osslApi = new OSSL_Api();
|
OSSL_Api osslApi = new OSSL_Api();
|
||||||
osslApi.Initialize(m_engine, so.RootPart, null);
|
osslApi.Initialize(m_engine, so.RootPart, null);
|
||||||
|
|
||||||
string npcRaw;
|
|
||||||
bool gotExpectedException = false;
|
bool gotExpectedException = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
npcRaw
|
osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
|
||||||
= osslApi.osNpcCreate("Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), "not existing notecard name");
|
|
||||||
}
|
}
|
||||||
catch (ScriptException)
|
catch (ScriptException)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics; //for [DebuggerNonUserCode]
|
using System.Diagnostics; //for [DebuggerNonUserCode]
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using System.Security.Policy;
|
using System.Security.Policy;
|
||||||
|
@ -445,8 +446,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cmdparams"></param>
|
/// <param name="cmdparams"></param>
|
||||||
/// <param name="instance"></param>
|
/// <param name="instance"></param>
|
||||||
/// <returns>true if we're okay to proceed, false if not.</returns>
|
/// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param>
|
||||||
private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
|
private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
|
||||||
|
{
|
||||||
|
HandleScriptsAction<object>(cmdparams, action, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parse the raw item id into a script instance from the command params if it's present.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdparams"></param>
|
||||||
|
/// <param name="instance"></param>
|
||||||
|
/// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
|
||||||
|
private void HandleScriptsAction<TKey>(
|
||||||
|
string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector)
|
||||||
{
|
{
|
||||||
if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
|
if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
|
||||||
return;
|
return;
|
||||||
|
@ -458,7 +471,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
|
|
||||||
if (cmdparams.Length == 2)
|
if (cmdparams.Length == 2)
|
||||||
{
|
{
|
||||||
foreach (IScriptInstance instance in m_Scripts.Values)
|
IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
|
||||||
|
|
||||||
|
if (keySelector != null)
|
||||||
|
scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
|
||||||
|
|
||||||
|
foreach (IScriptInstance instance in scripts)
|
||||||
action(instance);
|
action(instance);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -505,9 +523,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
|
sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
lock (m_Scripts)
|
long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
|
||||||
sb.AppendFormat("Scripts loaded : {0}\n", m_Scripts.Count);
|
|
||||||
|
|
||||||
|
lock (m_Scripts)
|
||||||
|
{
|
||||||
|
scriptsLoaded = m_Scripts.Count;
|
||||||
|
|
||||||
|
foreach (IScriptInstance si in m_Scripts.Values)
|
||||||
|
{
|
||||||
|
eventsQueued += si.EventsQueued;
|
||||||
|
eventsProcessed += si.EventsProcessed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
|
||||||
sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
|
sb.AppendFormat("Unique scripts : {0}\n", m_uniqueScripts.Count);
|
||||||
sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
|
sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
|
||||||
sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
|
sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
|
||||||
|
@ -516,6 +545,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
|
sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
|
||||||
sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
|
sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
|
||||||
// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
|
// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
|
||||||
|
sb.AppendFormat("Events queued : {0}\n", eventsQueued);
|
||||||
|
sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
|
||||||
|
|
||||||
SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
|
SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
|
||||||
sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
|
sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
|
||||||
|
@ -546,7 +577,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleScriptsAction(cmdparams, HandleShowScript);
|
HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleShowScript(IScriptInstance instance)
|
private void HandleShowScript(IScriptInstance instance)
|
||||||
|
@ -576,10 +607,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
|
|
||||||
sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
|
sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
|
||||||
sb.AppendFormat("Status : {0}\n", status);
|
sb.AppendFormat("Status : {0}\n", status);
|
||||||
|
sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
|
||||||
lock (eq)
|
sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
|
||||||
sb.AppendFormat("Queued events : {0}\n", eq.Count);
|
|
||||||
|
|
||||||
sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
|
sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
|
||||||
sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
|
sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
|
||||||
sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
|
sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
|
||||||
|
@ -1089,8 +1118,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
|
|
||||||
string assembly = "";
|
string assembly = "";
|
||||||
|
|
||||||
CultureInfo USCulture = new CultureInfo("en-US");
|
Culture.SetCurrentCulture();
|
||||||
Thread.CurrentThread.CurrentCulture = USCulture;
|
|
||||||
|
|
||||||
Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
|
Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
|
||||||
|
|
||||||
|
@ -1504,8 +1532,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private object ProcessEventHandler(object parms)
|
private object ProcessEventHandler(object parms)
|
||||||
{
|
{
|
||||||
CultureInfo USCulture = new CultureInfo("en-US");
|
Culture.SetCurrentCulture();
|
||||||
Thread.CurrentThread.CurrentCulture = USCulture;
|
|
||||||
|
|
||||||
IScriptInstance instance = (ScriptInstance) parms;
|
IScriptInstance instance = (ScriptInstance) parms;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet-2.1.5.0-dotnet-1.dylib" />
|
<dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet.dylib" />
|
||||||
<dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" />
|
<dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" />
|
||||||
<dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" />
|
<dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" />
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2168,7 +2168,7 @@
|
||||||
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
|
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
|
||||||
<Reference name="OpenMetaverse" path="../../../bin/"/>
|
<Reference name="OpenMetaverse" path="../../../bin/"/>
|
||||||
<Reference name="Nini" path="../../../bin/"/>
|
<Reference name="Nini" path="../../../bin/"/>
|
||||||
<Reference name="Mono.Addins"/>
|
<Reference name="Mono.Addins" path="../../../bin/"/>
|
||||||
<Reference name="log4net" path="../../../bin/"/>
|
<Reference name="log4net" path="../../../bin/"/>
|
||||||
<Files>
|
<Files>
|
||||||
<Match pattern="*.cs" recurse="true"/>
|
<Match pattern="*.cs" recurse="true"/>
|
||||||
|
@ -2577,7 +2577,7 @@
|
||||||
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
|
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
|
||||||
<Reference name="OpenSim.Region.Physics.Manager"/>
|
<Reference name="OpenSim.Region.Physics.Manager"/>
|
||||||
<Reference name="Mono.Data.SqliteClient" path="../../../bin/"/>
|
<Reference name="Mono.Data.SqliteClient" path="../../../bin/"/>
|
||||||
<Reference name="Mono.Addins"/>
|
<Reference name="Mono.Addins" path="../../../bin/"/>
|
||||||
|
|
||||||
<!-- For scripting in funny languages by default -->
|
<!-- For scripting in funny languages by default -->
|
||||||
<Reference name="XMLRPC" path="../../../bin/"/>
|
<Reference name="XMLRPC" path="../../../bin/"/>
|
||||||
|
|
Loading…
Reference in New Issue