Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
commit
a82f699f43
|
@ -132,6 +132,11 @@
|
||||||
</exec>
|
</exec>
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" />
|
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" />
|
||||||
|
|
||||||
|
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.server.handlers.tests">
|
||||||
|
<arg value="./bin/OpenSim.Server.Handlers.Tests.dll" />
|
||||||
|
</exec>
|
||||||
|
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.server.handlers.tests)==0}" />
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.services.inventoryservice.tests">
|
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.services.inventoryservice.tests">
|
||||||
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" />
|
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" />
|
||||||
</exec>
|
</exec>
|
||||||
|
@ -240,6 +245,11 @@
|
||||||
<arg value="-xml=test-results/OpenSim.Capabilities.Handlers.Tests.dll-Results.xml" />
|
<arg value="-xml=test-results/OpenSim.Capabilities.Handlers.Tests.dll-Results.xml" />
|
||||||
</exec>
|
</exec>
|
||||||
|
|
||||||
|
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.server.handlers.tests">
|
||||||
|
<arg value="./bin/OpenSim.Server.Handlers.Tests.dll" />
|
||||||
|
<arg value="-xml=test-results/OpenSim.Server.Handlers.Tests.dll-Results.xml" />
|
||||||
|
</exec>
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.services.inventoryservice.tests">
|
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.services.inventoryservice.tests">
|
||||||
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" />
|
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" />
|
||||||
<arg value="-xml=test-results/OpenSim.Services.InventoryService.Tests.dll-Results.xml" />
|
<arg value="-xml=test-results/OpenSim.Services.InventoryService.Tests.dll-Results.xml" />
|
||||||
|
|
|
@ -93,6 +93,7 @@ what it is today.
|
||||||
* Garmin Kawaguichi
|
* Garmin Kawaguichi
|
||||||
* Gryc Ueusp
|
* Gryc Ueusp
|
||||||
* Hiro Lecker
|
* Hiro Lecker
|
||||||
|
* Iain Oliver
|
||||||
* Imaze Rhiano
|
* Imaze Rhiano
|
||||||
* Intimidated
|
* Intimidated
|
||||||
* Jeremy Bongio (IBM)
|
* Jeremy Bongio (IBM)
|
||||||
|
|
|
@ -42,7 +42,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
|
namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class GetTextureHandlerTests
|
public class GetTextureHandlerTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestTextureNotFound()
|
public void TestTextureNotFound()
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
|
||||||
|
namespace OpenSim.Data
|
||||||
|
{
|
||||||
|
public class XGroup
|
||||||
|
{
|
||||||
|
public UUID groupID;
|
||||||
|
public UUID ownerRoleID;
|
||||||
|
public string name;
|
||||||
|
public string charter;
|
||||||
|
public bool showInList;
|
||||||
|
public UUID insigniaID;
|
||||||
|
public int membershipFee;
|
||||||
|
public bool openEnrollment;
|
||||||
|
public bool allowPublish;
|
||||||
|
public bool maturePublish;
|
||||||
|
public UUID founderID;
|
||||||
|
public ulong everyonePowers;
|
||||||
|
public ulong ownersPowers;
|
||||||
|
|
||||||
|
public XGroup Clone()
|
||||||
|
{
|
||||||
|
return (XGroup)MemberwiseClone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Early stub interface for groups data, not final.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Currently in-use only for regression test purposes. Needs to be filled out over time.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IXGroupData
|
||||||
|
{
|
||||||
|
bool StoreGroup(XGroup group);
|
||||||
|
XGroup[] GetGroups(string field, string val);
|
||||||
|
XGroup[] GetGroups(string[] fields, string[] vals);
|
||||||
|
bool DeleteGroups(string field, string val);
|
||||||
|
bool DeleteGroups(string[] fields, string[] vals);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using log4net;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Data;
|
||||||
|
|
||||||
|
namespace OpenSim.Data.Null
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Not a proper generic data handler yet - probably needs to actually store the data as well instead of relying
|
||||||
|
/// on descendent classes
|
||||||
|
/// </summary>
|
||||||
|
public class NullGenericDataHandler
|
||||||
|
{
|
||||||
|
protected List<T> Get<T>(string[] fields, string[] vals, List<T> inputEntities)
|
||||||
|
{
|
||||||
|
List<T> entities = inputEntities;
|
||||||
|
|
||||||
|
for (int i = 0; i < fields.Length; i++)
|
||||||
|
{
|
||||||
|
entities
|
||||||
|
= entities.Where(
|
||||||
|
e =>
|
||||||
|
{
|
||||||
|
FieldInfo fi = typeof(T).GetField(fields[i]);
|
||||||
|
if (fi == null)
|
||||||
|
throw new NotImplementedException(string.Format("No field {0} for val {1}", fields[i], vals[i]));
|
||||||
|
|
||||||
|
return fi.GetValue(e).ToString() == vals[i];
|
||||||
|
}
|
||||||
|
).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using log4net;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Data;
|
||||||
|
|
||||||
|
namespace OpenSim.Data.Null
|
||||||
|
{
|
||||||
|
public class NullXGroupData : NullGenericDataHandler, IXGroupData
|
||||||
|
{
|
||||||
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
private Dictionary<UUID, XGroup> m_groups = new Dictionary<UUID, XGroup>();
|
||||||
|
|
||||||
|
public NullXGroupData(string connectionString, string realm) {}
|
||||||
|
|
||||||
|
public bool StoreGroup(XGroup group)
|
||||||
|
{
|
||||||
|
lock (m_groups)
|
||||||
|
{
|
||||||
|
m_groups[group.groupID] = group.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XGroup[] GetGroups(string field, string val)
|
||||||
|
{
|
||||||
|
return GetGroups(new string[] { field }, new string[] { val });
|
||||||
|
}
|
||||||
|
|
||||||
|
public XGroup[] GetGroups(string[] fields, string[] vals)
|
||||||
|
{
|
||||||
|
lock (m_groups)
|
||||||
|
{
|
||||||
|
List<XGroup> origGroups = Get<XGroup>(fields, vals, m_groups.Values.ToList());
|
||||||
|
|
||||||
|
return origGroups.Select(g => g.Clone()).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DeleteGroups(string field, string val)
|
||||||
|
{
|
||||||
|
return DeleteGroups(new string[] { field }, new string[] { val });
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DeleteGroups(string[] fields, string[] vals)
|
||||||
|
{
|
||||||
|
lock (m_groups)
|
||||||
|
{
|
||||||
|
XGroup[] groupsToDelete = GetGroups(fields, vals);
|
||||||
|
Array.ForEach(groupsToDelete, g => m_groups.Remove(g.groupID));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,7 +49,7 @@ using OpenSim.Data.SQLite;
|
||||||
namespace OpenSim.Data.Tests
|
namespace OpenSim.Data.Tests
|
||||||
{
|
{
|
||||||
[TestFixture(Description = "Asset store tests (SQLite)")]
|
[TestFixture(Description = "Asset store tests (SQLite)")]
|
||||||
public class SQLiteAssetTests : AssetTests<SqliteConnection, SQLiteAssetData>
|
public class SQLiteAssetTests : AssetTests<SqliteConnection, SQLiteAssetData>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ using NUnit.Framework;
|
||||||
using NUnit.Framework.Constraints;
|
using NUnit.Framework.Constraints;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
using log4net;
|
using log4net;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
@ -43,6 +44,12 @@ namespace OpenSim.Data.Tests
|
||||||
/// <summary>This is a base class for testing any Data service for any DBMS.
|
/// <summary>This is a base class for testing any Data service for any DBMS.
|
||||||
/// Requires NUnit 2.5 or better (to support the generics).
|
/// Requires NUnit 2.5 or better (to support the generics).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with
|
||||||
|
/// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
|
||||||
|
/// and similar on EstateTests, InventoryTests and RegionTests.
|
||||||
|
/// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts.
|
||||||
|
/// </remarks>
|
||||||
/// <typeparam name="TConn"></typeparam>
|
/// <typeparam name="TConn"></typeparam>
|
||||||
/// <typeparam name="TService"></typeparam>
|
/// <typeparam name="TService"></typeparam>
|
||||||
public class BasicDataServiceTest<TConn, TService>
|
public class BasicDataServiceTest<TConn, TService>
|
||||||
|
|
|
@ -36,6 +36,7 @@ using NUnit.Framework;
|
||||||
using NUnit.Framework.Constraints;
|
using NUnit.Framework.Constraints;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Data.Tests
|
namespace OpenSim.Data.Tests
|
||||||
{
|
{
|
||||||
|
@ -254,7 +255,7 @@ namespace OpenSim.Data.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PropertyCompareConstraintTest
|
public class PropertyCompareConstraintTest : OpenSimTestCase
|
||||||
{
|
{
|
||||||
public class HasInt
|
public class HasInt
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,6 +34,7 @@ using System.Text;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Data.Tests
|
namespace OpenSim.Data.Tests
|
||||||
{
|
{
|
||||||
|
@ -158,7 +159,7 @@ namespace OpenSim.Data.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PropertyScramblerTests
|
public class PropertyScramblerTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestScramble()
|
public void TestScramble()
|
||||||
|
|
|
@ -83,7 +83,8 @@ namespace OpenSim.Framework.Console
|
||||||
= "To enter an argument that contains spaces, surround the argument with double quotes.\nFor example, show object name \"My long object name\"\n";
|
= "To enter an argument that contains spaces, surround the argument with double quotes.\nFor example, show object name \"My long object name\"\n";
|
||||||
|
|
||||||
public const string ItemHelpText
|
public const string ItemHelpText
|
||||||
= "For more information, type 'help <item>' where <item> is one of the following:";
|
= @"For more information, type 'help all' to get a list of all commands,
|
||||||
|
or type help <item>' where <item> is one of the following:";
|
||||||
|
|
||||||
/// <value>
|
/// <value>
|
||||||
/// Commands organized by keyword in a tree
|
/// Commands organized by keyword in a tree
|
||||||
|
@ -117,6 +118,10 @@ namespace OpenSim.Framework.Console
|
||||||
help.Add(ItemHelpText);
|
help.Add(ItemHelpText);
|
||||||
help.AddRange(CollectModulesHelp(tree));
|
help.AddRange(CollectModulesHelp(tree));
|
||||||
}
|
}
|
||||||
|
else if (helpParts.Count == 1 && helpParts[0] == "all")
|
||||||
|
{
|
||||||
|
help.AddRange(CollectAllCommandsHelp());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
help.AddRange(CollectHelp(helpParts));
|
help.AddRange(CollectHelp(helpParts));
|
||||||
|
@ -124,6 +129,28 @@ namespace OpenSim.Framework.Console
|
||||||
|
|
||||||
return help;
|
return help;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collects the help from all commands and return in alphabetical order.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private List<string> CollectAllCommandsHelp()
|
||||||
|
{
|
||||||
|
List<string> help = new List<string>();
|
||||||
|
|
||||||
|
lock (m_modulesCommands)
|
||||||
|
{
|
||||||
|
foreach (List<CommandInfo> commands in m_modulesCommands.Values)
|
||||||
|
{
|
||||||
|
var ourHelpText = commands.ConvertAll(c => string.Format("{0} - {1}", c.help_text, c.long_help));
|
||||||
|
help.AddRange(ourHelpText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
help.Sort();
|
||||||
|
|
||||||
|
return help;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// See if we can find the requested command in order to display longer help
|
/// See if we can find the requested command in order to display longer help
|
||||||
|
@ -711,7 +738,7 @@ namespace OpenSim.Framework.Console
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Prompt()
|
public void Prompt()
|
||||||
{
|
{
|
||||||
string line = ReadLine(m_defaultPrompt + "# ", true, true);
|
string line = ReadLine(DefaultPrompt + "# ", true, true);
|
||||||
|
|
||||||
if (line != String.Empty)
|
if (line != String.Empty)
|
||||||
Output("Invalid command");
|
Output("Invalid command");
|
||||||
|
|
|
@ -43,15 +43,7 @@ namespace OpenSim.Framework.Console
|
||||||
|
|
||||||
public object ConsoleScene { get; set; }
|
public object ConsoleScene { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
public string DefaultPrompt { get; set; }
|
||||||
/// The default prompt text.
|
|
||||||
/// </summary>
|
|
||||||
public string DefaultPrompt
|
|
||||||
{
|
|
||||||
set { m_defaultPrompt = value; }
|
|
||||||
get { return m_defaultPrompt; }
|
|
||||||
}
|
|
||||||
protected string m_defaultPrompt;
|
|
||||||
|
|
||||||
public ConsoleBase(string defaultPrompt)
|
public ConsoleBase(string defaultPrompt)
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,13 +46,18 @@ namespace OpenSim.Framework.Console
|
||||||
|
|
||||||
public ICommands Commands { get { return m_commands; } }
|
public ICommands Commands { get { return m_commands; } }
|
||||||
|
|
||||||
|
public string DefaultPrompt { get; set; }
|
||||||
|
|
||||||
public void Prompt() {}
|
public void Prompt() {}
|
||||||
|
|
||||||
public void RunCommand(string cmd) {}
|
public void RunCommand(string cmd) {}
|
||||||
|
|
||||||
public string ReadLine(string p, bool isCommand, bool e) { return ""; }
|
public string ReadLine(string p, bool isCommand, bool e) { return ""; }
|
||||||
|
|
||||||
public object ConsoleScene { get { return null; } }
|
public object ConsoleScene {
|
||||||
|
get { return null; }
|
||||||
|
set {}
|
||||||
|
}
|
||||||
|
|
||||||
public void Output(string text, string level) {}
|
public void Output(string text, string level) {}
|
||||||
public void Output(string text) {}
|
public void Output(string text) {}
|
||||||
|
|
|
@ -82,6 +82,11 @@ namespace OpenSim.Framework
|
||||||
|
|
||||||
ICommands Commands { get; }
|
ICommands Commands { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default prompt text.
|
||||||
|
/// </summary>
|
||||||
|
string DefaultPrompt { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Display a command prompt on the console and wait for user input
|
/// Display a command prompt on the console and wait for user input
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
public interface IConsole
|
public interface IConsole
|
||||||
{
|
{
|
||||||
object ConsoleScene { get; }
|
object ConsoleScene { get; set; }
|
||||||
|
|
||||||
void Output(string text, string level);
|
void Output(string text, string level);
|
||||||
void Output(string text);
|
void Output(string text);
|
||||||
|
|
|
@ -154,6 +154,11 @@ namespace OpenSim.Framework.Serialization
|
||||||
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder;
|
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string CreateOarLandDataPath(LandData ld)
|
||||||
|
{
|
||||||
|
return string.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH, ld.GlobalID);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create the filename used to store an object in an OpenSim Archive.
|
/// Create the filename used to store an object in an OpenSim Archive.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
|
||||||
namespace OpenSim.Framework.Serialization.Tests
|
namespace OpenSim.Framework.Serialization.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class LandDataSerializerTest
|
public class LandDataSerializerTest : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private LandData land;
|
private LandData land;
|
||||||
private LandData landWithParcelAccessList;
|
private LandData landWithParcelAccessList;
|
||||||
|
|
|
@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
|
||||||
namespace OpenSim.Framework.Serialization.Tests
|
namespace OpenSim.Framework.Serialization.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class RegionSettingsSerializerTests
|
public class RegionSettingsSerializerTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private string m_serializedRs = @"<?xml version=""1.0"" encoding=""utf-16""?>
|
private string m_serializedRs = @"<?xml version=""1.0"" encoding=""utf-16""?>
|
||||||
<RegionSettings>
|
<RegionSettings>
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -38,6 +37,8 @@ using log4net;
|
||||||
using log4net.Appender;
|
using log4net.Appender;
|
||||||
using log4net.Core;
|
using log4net.Core;
|
||||||
using log4net.Repository;
|
using log4net.Repository;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Framework.Console;
|
using OpenSim.Framework.Console;
|
||||||
using OpenSim.Framework.Monitoring;
|
using OpenSim.Framework.Monitoring;
|
||||||
|
@ -45,16 +46,12 @@ using OpenSim.Framework.Servers;
|
||||||
using OpenSim.Framework.Servers.HttpServer;
|
using OpenSim.Framework.Servers.HttpServer;
|
||||||
using Timer=System.Timers.Timer;
|
using Timer=System.Timers.Timer;
|
||||||
|
|
||||||
using OpenMetaverse;
|
|
||||||
using OpenMetaverse.StructuredData;
|
|
||||||
|
|
||||||
|
|
||||||
namespace OpenSim.Framework.Servers
|
namespace OpenSim.Framework.Servers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Common base for the main OpenSimServers (user, grid, inventory, region, etc)
|
/// Common base for the main OpenSimServers (user, grid, inventory, region, etc)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseOpenSimServer
|
public abstract class BaseOpenSimServer : ServerBase
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
@ -63,27 +60,6 @@ namespace OpenSim.Framework.Servers
|
||||||
/// server.
|
/// server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000);
|
private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000);
|
||||||
|
|
||||||
protected CommandConsole m_console;
|
|
||||||
protected OpenSimAppender m_consoleAppender;
|
|
||||||
protected IAppender m_logFileAppender = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Time at which this server was started
|
|
||||||
/// </summary>
|
|
||||||
protected DateTime m_startuptime;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Record the initial startup directory for info purposes
|
|
||||||
/// </summary>
|
|
||||||
protected string m_startupDirectory = Environment.CurrentDirectory;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Server version information. Usually VersionInfo + information about git commit, operating system, etc.
|
|
||||||
/// </summary>
|
|
||||||
protected string m_version;
|
|
||||||
|
|
||||||
protected string m_pidFile = String.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Random uuid for private data
|
/// Random uuid for private data
|
||||||
|
@ -96,30 +72,13 @@ namespace OpenSim.Framework.Servers
|
||||||
get { return m_httpServer; }
|
get { return m_httpServer; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseOpenSimServer()
|
public BaseOpenSimServer() : base()
|
||||||
{
|
{
|
||||||
m_startuptime = DateTime.Now;
|
|
||||||
m_version = VersionInfo.Version;
|
|
||||||
|
|
||||||
// Random uuid for private data
|
// Random uuid for private data
|
||||||
m_osSecret = UUID.Random().ToString();
|
m_osSecret = UUID.Random().ToString();
|
||||||
|
|
||||||
m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics);
|
m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics);
|
||||||
m_periodicDiagnosticsTimer.Enabled = true;
|
m_periodicDiagnosticsTimer.Enabled = true;
|
||||||
|
|
||||||
// This thread will go on to become the console listening thread
|
|
||||||
Thread.CurrentThread.Name = "ConsoleThread";
|
|
||||||
|
|
||||||
ILoggerRepository repository = LogManager.GetRepository();
|
|
||||||
IAppender[] appenders = repository.GetAppenders();
|
|
||||||
|
|
||||||
foreach (IAppender appender in appenders)
|
|
||||||
{
|
|
||||||
if (appender.Name == "LogFileAppender")
|
|
||||||
{
|
|
||||||
m_logFileAppender = appender;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -127,83 +86,18 @@ namespace OpenSim.Framework.Servers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void StartupSpecific()
|
protected virtual void StartupSpecific()
|
||||||
{
|
{
|
||||||
if (m_console != null)
|
if (m_console == null)
|
||||||
{
|
return;
|
||||||
ILoggerRepository repository = LogManager.GetRepository();
|
|
||||||
IAppender[] appenders = repository.GetAppenders();
|
|
||||||
|
|
||||||
foreach (IAppender appender in appenders)
|
RegisterCommonCommands();
|
||||||
{
|
|
||||||
if (appender.Name == "Console")
|
m_console.Commands.AddCommand("General", false, "quit",
|
||||||
{
|
"quit",
|
||||||
m_consoleAppender = (OpenSimAppender)appender;
|
"Quit the application", HandleQuit);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == m_consoleAppender)
|
m_console.Commands.AddCommand("General", false, "shutdown",
|
||||||
{
|
"shutdown",
|
||||||
Notice("No appender named Console found (see the log4net config file for this executable)!");
|
"Quit the application", HandleQuit);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_consoleAppender.Console = m_console;
|
|
||||||
|
|
||||||
// If there is no threshold set then the threshold is effectively everything.
|
|
||||||
if (null == m_consoleAppender.Threshold)
|
|
||||||
m_consoleAppender.Threshold = Level.All;
|
|
||||||
|
|
||||||
Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "quit",
|
|
||||||
"quit",
|
|
||||||
"Quit the application", HandleQuit);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "shutdown",
|
|
||||||
"shutdown",
|
|
||||||
"Quit the application", HandleQuit);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "set log level",
|
|
||||||
"set log level <level>",
|
|
||||||
"Set the console logging level", HandleLogLevel);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "show info",
|
|
||||||
"show info",
|
|
||||||
"Show general information about the server", HandleShow);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "show threads",
|
|
||||||
"show threads",
|
|
||||||
"Show thread status", HandleShow);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "show uptime",
|
|
||||||
"show uptime",
|
|
||||||
"Show server uptime", HandleShow);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "show version",
|
|
||||||
"show version",
|
|
||||||
"Show server version", HandleShow);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "threads abort",
|
|
||||||
"threads abort <thread-id>",
|
|
||||||
"Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "threads show",
|
|
||||||
"threads show",
|
|
||||||
"Show thread status. Synonym for \"show threads\"",
|
|
||||||
(string module, string[] args) => Notice(GetThreadsReport()));
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "force gc",
|
|
||||||
"force gc",
|
|
||||||
"Manually invoke runtime garbage collection. For debugging purposes",
|
|
||||||
HandleForceGc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleForceGc(string module, string[] args)
|
|
||||||
{
|
|
||||||
MainConsole.Instance.Output("Manually invoking runtime garbage collection");
|
|
||||||
GC.Collect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -235,75 +129,12 @@ namespace OpenSim.Framework.Servers
|
||||||
m_log.Debug(sb);
|
m_log.Debug(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a report about the registered threads in this server.
|
|
||||||
/// </summary>
|
|
||||||
protected string GetThreadsReport()
|
|
||||||
{
|
|
||||||
// This should be a constant field.
|
|
||||||
string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
|
|
||||||
|
|
||||||
sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
|
|
||||||
|
|
||||||
int timeNow = Environment.TickCount & Int32.MaxValue;
|
|
||||||
|
|
||||||
sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
|
|
||||||
sb.Append(Environment.NewLine);
|
|
||||||
|
|
||||||
foreach (Watchdog.ThreadWatchdogInfo twi in threads)
|
|
||||||
{
|
|
||||||
Thread t = twi.Thread;
|
|
||||||
|
|
||||||
sb.AppendFormat(
|
|
||||||
reportFormat,
|
|
||||||
t.ManagedThreadId,
|
|
||||||
t.Name,
|
|
||||||
timeNow - twi.LastTick,
|
|
||||||
timeNow - twi.FirstTick,
|
|
||||||
t.Priority,
|
|
||||||
t.ThreadState);
|
|
||||||
|
|
||||||
sb.Append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.Append("\n");
|
|
||||||
|
|
||||||
// For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
|
|
||||||
// zero active threads.
|
|
||||||
int totalThreads = Process.GetCurrentProcess().Threads.Count;
|
|
||||||
if (totalThreads > 0)
|
|
||||||
sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
|
|
||||||
|
|
||||||
sb.Append("Main threadpool (excluding script engine pools)\n");
|
|
||||||
sb.Append(Util.GetThreadPoolReport());
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Return a report about the uptime of this server
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected string GetUptimeReport()
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now));
|
|
||||||
sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime));
|
|
||||||
sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime));
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs initialisation of the scene, such as loading configuration from disk.
|
/// Performs initialisation of the scene, such as loading configuration from disk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Startup()
|
public virtual void Startup()
|
||||||
{
|
{
|
||||||
m_log.Info("[STARTUP]: Beginning startup processing");
|
m_log.Info("[STARTUP]: Beginning startup processing");
|
||||||
|
|
||||||
EnhanceVersionInformation();
|
|
||||||
|
|
||||||
m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine);
|
m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine);
|
||||||
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
|
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
|
||||||
|
@ -338,257 +169,7 @@ namespace OpenSim.Framework.Servers
|
||||||
private void HandleQuit(string module, string[] args)
|
private void HandleQuit(string module, string[] args)
|
||||||
{
|
{
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleLogLevel(string module, string[] cmd)
|
|
||||||
{
|
|
||||||
if (null == m_consoleAppender)
|
|
||||||
{
|
|
||||||
Notice("No appender named Console found (see the log4net config file for this executable)!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd.Length > 3)
|
|
||||||
{
|
|
||||||
string rawLevel = cmd[3];
|
|
||||||
|
|
||||||
ILoggerRepository repository = LogManager.GetRepository();
|
|
||||||
Level consoleLevel = repository.LevelMap[rawLevel];
|
|
||||||
|
|
||||||
if (consoleLevel != null)
|
|
||||||
m_consoleAppender.Threshold = consoleLevel;
|
|
||||||
else
|
|
||||||
Notice(
|
|
||||||
String.Format(
|
|
||||||
"{0} is not a valid logging level. Valid logging levels are ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF",
|
|
||||||
rawLevel));
|
|
||||||
}
|
|
||||||
|
|
||||||
Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Show help information
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="helpArgs"></param>
|
|
||||||
protected virtual void ShowHelp(string[] helpArgs)
|
|
||||||
{
|
|
||||||
Notice("");
|
|
||||||
|
|
||||||
if (helpArgs.Length == 0)
|
|
||||||
{
|
|
||||||
Notice("set log level [level] - change the console logging level only. For example, off or debug.");
|
|
||||||
Notice("show info - show server information (e.g. startup path).");
|
|
||||||
Notice("show threads - list tracked threads");
|
|
||||||
Notice("show uptime - show server startup time and uptime.");
|
|
||||||
Notice("show version - show server version.");
|
|
||||||
Notice("");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void HandleShow(string module, string[] cmd)
|
|
||||||
{
|
|
||||||
List<string> args = new List<string>(cmd);
|
|
||||||
|
|
||||||
args.RemoveAt(0);
|
|
||||||
|
|
||||||
string[] showParams = args.ToArray();
|
|
||||||
|
|
||||||
switch (showParams[0])
|
|
||||||
{
|
|
||||||
case "info":
|
|
||||||
ShowInfo();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "threads":
|
|
||||||
Notice(GetThreadsReport());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "uptime":
|
|
||||||
Notice(GetUptimeReport());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "version":
|
|
||||||
Notice(GetVersionText());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void HandleThreadsAbort(string module, string[] cmd)
|
|
||||||
{
|
|
||||||
if (cmd.Length != 3)
|
|
||||||
{
|
|
||||||
MainConsole.Instance.Output("Usage: threads abort <thread-id>");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int threadId;
|
|
||||||
if (!int.TryParse(cmd[2], out threadId))
|
|
||||||
{
|
|
||||||
MainConsole.Instance.Output("ERROR: Thread id must be an integer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Watchdog.AbortThread(threadId))
|
|
||||||
MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
|
|
||||||
else
|
|
||||||
MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void ShowInfo()
|
|
||||||
{
|
|
||||||
Notice(GetVersionText());
|
|
||||||
Notice("Startup directory: " + m_startupDirectory);
|
|
||||||
if (null != m_consoleAppender)
|
|
||||||
Notice(String.Format("Console log level: {0}", m_consoleAppender.Threshold));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string GetVersionText()
|
|
||||||
{
|
|
||||||
return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Console output is only possible if a console has been established.
|
|
||||||
/// That is something that cannot be determined within this class. So
|
|
||||||
/// all attempts to use the console MUST be verified.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
protected void Notice(string msg)
|
|
||||||
{
|
|
||||||
if (m_console != null)
|
|
||||||
{
|
|
||||||
m_console.Output(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Console output is only possible if a console has been established.
|
|
||||||
/// That is something that cannot be determined within this class. So
|
|
||||||
/// all attempts to use the console MUST be verified.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format"></param>
|
|
||||||
/// <param name="components"></param>
|
|
||||||
protected void Notice(string format, params string[] components)
|
|
||||||
{
|
|
||||||
if (m_console != null)
|
|
||||||
m_console.OutputFormat(format, components);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enhance the version string with extra information if it's available.
|
|
||||||
/// </summary>
|
|
||||||
protected void EnhanceVersionInformation()
|
|
||||||
{
|
|
||||||
string buildVersion = string.Empty;
|
|
||||||
|
|
||||||
// The subversion information is deprecated and will be removed at a later date
|
|
||||||
// Add subversion revision information if available
|
|
||||||
// Try file "svn_revision" in the current directory first, then the .svn info.
|
|
||||||
// This allows to make the revision available in simulators not running from the source tree.
|
|
||||||
// FIXME: Making an assumption about the directory we're currently in - we do this all over the place
|
|
||||||
// elsewhere as well
|
|
||||||
string gitDir = "../.git/";
|
|
||||||
string gitRefPointerPath = gitDir + "HEAD";
|
|
||||||
|
|
||||||
string svnRevisionFileName = "svn_revision";
|
|
||||||
string svnFileName = ".svn/entries";
|
|
||||||
string manualVersionFileName = ".version";
|
|
||||||
string inputLine;
|
|
||||||
int strcmp;
|
|
||||||
|
|
||||||
if (File.Exists(manualVersionFileName))
|
|
||||||
{
|
|
||||||
using (StreamReader CommitFile = File.OpenText(manualVersionFileName))
|
|
||||||
buildVersion = CommitFile.ReadLine();
|
|
||||||
|
|
||||||
m_version += buildVersion ?? "";
|
|
||||||
}
|
|
||||||
else if (File.Exists(gitRefPointerPath))
|
|
||||||
{
|
|
||||||
// m_log.DebugFormat("[OPENSIM]: Found {0}", gitRefPointerPath);
|
|
||||||
|
|
||||||
string rawPointer = "";
|
|
||||||
|
|
||||||
using (StreamReader pointerFile = File.OpenText(gitRefPointerPath))
|
|
||||||
rawPointer = pointerFile.ReadLine();
|
|
||||||
|
|
||||||
// m_log.DebugFormat("[OPENSIM]: rawPointer [{0}]", rawPointer);
|
|
||||||
|
|
||||||
Match m = Regex.Match(rawPointer, "^ref: (.+)$");
|
|
||||||
|
|
||||||
if (m.Success)
|
|
||||||
{
|
|
||||||
// m_log.DebugFormat("[OPENSIM]: Matched [{0}]", m.Groups[1].Value);
|
|
||||||
|
|
||||||
string gitRef = m.Groups[1].Value;
|
|
||||||
string gitRefPath = gitDir + gitRef;
|
|
||||||
if (File.Exists(gitRefPath))
|
|
||||||
{
|
|
||||||
// m_log.DebugFormat("[OPENSIM]: Found gitRefPath [{0}]", gitRefPath);
|
|
||||||
|
|
||||||
using (StreamReader refFile = File.OpenText(gitRefPath))
|
|
||||||
{
|
|
||||||
string gitHash = refFile.ReadLine();
|
|
||||||
m_version += gitHash.Substring(0, 7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Remove the else logic when subversion mirror is no longer used
|
|
||||||
if (File.Exists(svnRevisionFileName))
|
|
||||||
{
|
|
||||||
StreamReader RevisionFile = File.OpenText(svnRevisionFileName);
|
|
||||||
buildVersion = RevisionFile.ReadLine();
|
|
||||||
buildVersion.Trim();
|
|
||||||
RevisionFile.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName))
|
|
||||||
{
|
|
||||||
StreamReader EntriesFile = File.OpenText(svnFileName);
|
|
||||||
inputLine = EntriesFile.ReadLine();
|
|
||||||
while (inputLine != null)
|
|
||||||
{
|
|
||||||
// using the dir svn revision at the top of entries file
|
|
||||||
strcmp = String.Compare(inputLine, "dir");
|
|
||||||
if (strcmp == 0)
|
|
||||||
{
|
|
||||||
buildVersion = EntriesFile.ReadLine();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
inputLine = EntriesFile.ReadLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EntriesFile.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_version += string.IsNullOrEmpty(buildVersion) ? " " : ("." + buildVersion + " ").Substring(0, 6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void CreatePIDFile(string path)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
|
|
||||||
FileStream fs = File.Create(path);
|
|
||||||
|
|
||||||
Byte[] buf = Encoding.ASCII.GetBytes(pidstring);
|
|
||||||
fs.Write(buf, 0, buf.Length);
|
|
||||||
fs.Close();
|
|
||||||
m_pidFile = path;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string osSecret {
|
public string osSecret {
|
||||||
// Secret uuid for the simulator
|
// Secret uuid for the simulator
|
||||||
|
@ -607,20 +188,5 @@ namespace OpenSim.Framework.Servers
|
||||||
return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
|
return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void RemovePIDFile()
|
|
||||||
{
|
|
||||||
if (m_pidFile != String.Empty)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(m_pidFile);
|
|
||||||
m_pidFile = String.Empty;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -719,8 +719,11 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
if (DebugLevel == 5)
|
if (DebugLevel == 5)
|
||||||
{
|
{
|
||||||
const int sampleLength = 80;
|
const int sampleLength = 80;
|
||||||
char[] sampleChars = new char[sampleLength];
|
char[] sampleChars = new char[sampleLength + 3];
|
||||||
reader.Read(sampleChars, 0, sampleLength);
|
reader.Read(sampleChars, 0, sampleLength);
|
||||||
|
sampleChars[80] = '.';
|
||||||
|
sampleChars[81] = '.';
|
||||||
|
sampleChars[82] = '.';
|
||||||
output = new string(sampleChars);
|
output = new string(sampleChars);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -728,7 +731,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
output = reader.ReadToEnd();
|
output = reader.ReadToEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.DebugFormat("[BASE HTTP SERVER]: {0}...", output.Replace("\n", @"\n"));
|
m_log.DebugFormat("[BASE HTTP SERVER]: {0}", output.Replace("\n", @"\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1279,59 +1282,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
map["login"] = OSD.FromString("false");
|
map["login"] = OSD.FromString("false");
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
/// A specific agent handler was provided. Such a handler is expecetd to have an
|
|
||||||
/// intimate, and highly specific relationship with the client. Consequently,
|
|
||||||
/// nothing is done here.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handler"></param>
|
|
||||||
/// <param name="request"></param>
|
|
||||||
/// <param name="response"></param>
|
|
||||||
|
|
||||||
private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response)
|
|
||||||
{
|
|
||||||
// In the case of REST, then handler is responsible for ALL aspects of
|
|
||||||
// the request/response handling. Nothing is done here, not even encoding.
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return handler.Handle(request, response);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
// If the handler did in fact close the stream, then this will blow
|
|
||||||
// chunks. So that that doesn't disturb anybody we throw away any
|
|
||||||
// and all exceptions raised. We've done our best to release the
|
|
||||||
// client.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_log.Warn("[HTTP-AGENT]: Error - " + e.Message);
|
|
||||||
response.SendChunked = false;
|
|
||||||
response.KeepAlive = true;
|
|
||||||
response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError;
|
|
||||||
//response.OutputStream.Close();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
response.Send();
|
|
||||||
//response.FreeContext();
|
|
||||||
}
|
|
||||||
catch (SocketException f)
|
|
||||||
{
|
|
||||||
// This has to be here to prevent a Linux/Mono crash
|
|
||||||
m_log.Warn(
|
|
||||||
String.Format("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux. ", f.Message), f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Indicate that the request has been "handled"
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
|
public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,677 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using log4net;
|
||||||
|
using log4net.Appender;
|
||||||
|
using log4net.Core;
|
||||||
|
using log4net.Repository;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenSim.Framework.Console;
|
||||||
|
using OpenSim.Framework.Monitoring;
|
||||||
|
|
||||||
|
namespace OpenSim.Framework.Servers
|
||||||
|
{
|
||||||
|
public class ServerBase
|
||||||
|
{
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
public IConfigSource Config { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Console to be used for any command line output. Can be null, in which case there should be no output.
|
||||||
|
/// </summary>
|
||||||
|
protected ICommandConsole m_console;
|
||||||
|
|
||||||
|
protected OpenSimAppender m_consoleAppender;
|
||||||
|
protected FileAppender m_logFileAppender;
|
||||||
|
|
||||||
|
protected DateTime m_startuptime;
|
||||||
|
protected string m_startupDirectory = Environment.CurrentDirectory;
|
||||||
|
|
||||||
|
protected string m_pidFile = String.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Server version information. Usually VersionInfo + information about git commit, operating system, etc.
|
||||||
|
/// </summary>
|
||||||
|
protected string m_version;
|
||||||
|
|
||||||
|
public ServerBase()
|
||||||
|
{
|
||||||
|
m_startuptime = DateTime.Now;
|
||||||
|
m_version = VersionInfo.Version;
|
||||||
|
EnhanceVersionInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CreatePIDFile(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
|
||||||
|
|
||||||
|
using (FileStream fs = File.Create(path))
|
||||||
|
{
|
||||||
|
Byte[] buf = Encoding.ASCII.GetBytes(pidstring);
|
||||||
|
fs.Write(buf, 0, buf.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pidFile = path;
|
||||||
|
|
||||||
|
m_log.InfoFormat("[SERVER BASE]: Created pid file {0}", m_pidFile);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
m_log.Warn(string.Format("[SERVER BASE]: Could not create PID file at {0} ", path), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RemovePIDFile()
|
||||||
|
{
|
||||||
|
if (m_pidFile != String.Empty)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(m_pidFile);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
m_log.Error(string.Format("[SERVER BASE]: Error whilst removing {0} ", m_pidFile), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pidFile = String.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterCommonAppenders(IConfig startupConfig)
|
||||||
|
{
|
||||||
|
ILoggerRepository repository = LogManager.GetRepository();
|
||||||
|
IAppender[] appenders = repository.GetAppenders();
|
||||||
|
|
||||||
|
foreach (IAppender appender in appenders)
|
||||||
|
{
|
||||||
|
if (appender.Name == "Console")
|
||||||
|
{
|
||||||
|
m_consoleAppender = (OpenSimAppender)appender;
|
||||||
|
}
|
||||||
|
else if (appender.Name == "LogFileAppender")
|
||||||
|
{
|
||||||
|
m_logFileAppender = (FileAppender)appender;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == m_consoleAppender)
|
||||||
|
{
|
||||||
|
Notice("No appender named Console found (see the log4net config file for this executable)!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: This should be done through an interface rather than casting.
|
||||||
|
m_consoleAppender.Console = (ConsoleBase)m_console;
|
||||||
|
|
||||||
|
// If there is no threshold set then the threshold is effectively everything.
|
||||||
|
if (null == m_consoleAppender.Threshold)
|
||||||
|
m_consoleAppender.Threshold = Level.All;
|
||||||
|
|
||||||
|
Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_logFileAppender != null && startupConfig != null)
|
||||||
|
{
|
||||||
|
string cfgFileName = startupConfig.GetString("LogFile", null);
|
||||||
|
if (cfgFileName != null)
|
||||||
|
{
|
||||||
|
m_logFileAppender.File = cfgFileName;
|
||||||
|
m_logFileAppender.ActivateOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.InfoFormat("[SERVER BASE]: Logging started to file {0}", m_logFileAppender.File);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register common commands once m_console has been set if it is going to be set
|
||||||
|
/// </summary>
|
||||||
|
public void RegisterCommonCommands()
|
||||||
|
{
|
||||||
|
if (m_console == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "show info", "show info", "Show general information about the server", HandleShow);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "show version", "show version", "Show server version", HandleShow);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "show uptime", "show uptime", "Show server uptime", HandleShow);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "get log level", "get log level", "Get the current console logging level",
|
||||||
|
(mod, cmd) => ShowLogLevel());
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "set log level", "set log level <level>",
|
||||||
|
"Set the console logging level for this session.", HandleSetLogLevel);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "config set",
|
||||||
|
"config set <section> <key> <value>",
|
||||||
|
"Set a config option. In most cases this is not useful since changed parameters are not dynamically reloaded. Neither do changed parameters persist - you will have to change a config file manually and restart.", HandleConfig);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "config get",
|
||||||
|
"config get [<section>] [<key>]",
|
||||||
|
"Synonym for config show",
|
||||||
|
HandleConfig);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "config show",
|
||||||
|
"config show [<section>] [<key>]",
|
||||||
|
"Show config information",
|
||||||
|
"If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine
|
||||||
|
+ "If a section is given but not a field, then all fields in that section are printed.",
|
||||||
|
HandleConfig);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "config save",
|
||||||
|
"config save <path>",
|
||||||
|
"Save current configuration to a file at the given path", HandleConfig);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "command-script",
|
||||||
|
"command-script <script>",
|
||||||
|
"Run a command script from file", HandleScript);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "show threads",
|
||||||
|
"show threads",
|
||||||
|
"Show thread status", HandleShow);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "threads abort",
|
||||||
|
"threads abort <thread-id>",
|
||||||
|
"Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "threads show",
|
||||||
|
"threads show",
|
||||||
|
"Show thread status. Synonym for \"show threads\"",
|
||||||
|
(string module, string[] args) => Notice(GetThreadsReport()));
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"General", false, "force gc",
|
||||||
|
"force gc",
|
||||||
|
"Manually invoke runtime garbage collection. For debugging purposes",
|
||||||
|
HandleForceGc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleForceGc(string module, string[] args)
|
||||||
|
{
|
||||||
|
Notice("Manually invoking runtime garbage collection");
|
||||||
|
GC.Collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void HandleShow(string module, string[] cmd)
|
||||||
|
{
|
||||||
|
List<string> args = new List<string>(cmd);
|
||||||
|
|
||||||
|
args.RemoveAt(0);
|
||||||
|
|
||||||
|
string[] showParams = args.ToArray();
|
||||||
|
|
||||||
|
switch (showParams[0])
|
||||||
|
{
|
||||||
|
case "info":
|
||||||
|
ShowInfo();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "version":
|
||||||
|
Notice(GetVersionText());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "uptime":
|
||||||
|
Notice(GetUptimeReport());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "threads":
|
||||||
|
Notice(GetThreadsReport());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change and load configuration file data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="module"></param>
|
||||||
|
/// <param name="cmd"></param>
|
||||||
|
private void HandleConfig(string module, string[] cmd)
|
||||||
|
{
|
||||||
|
List<string> args = new List<string>(cmd);
|
||||||
|
args.RemoveAt(0);
|
||||||
|
string[] cmdparams = args.ToArray();
|
||||||
|
|
||||||
|
if (cmdparams.Length > 0)
|
||||||
|
{
|
||||||
|
string firstParam = cmdparams[0].ToLower();
|
||||||
|
|
||||||
|
switch (firstParam)
|
||||||
|
{
|
||||||
|
case "set":
|
||||||
|
if (cmdparams.Length < 4)
|
||||||
|
{
|
||||||
|
Notice("Syntax: config set <section> <key> <value>");
|
||||||
|
Notice("Example: config set ScriptEngine.DotNetEngine NumberOfScriptThreads 5");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IConfig c;
|
||||||
|
IConfigSource source = new IniConfigSource();
|
||||||
|
c = source.AddConfig(cmdparams[1]);
|
||||||
|
if (c != null)
|
||||||
|
{
|
||||||
|
string _value = String.Join(" ", cmdparams, 3, cmdparams.Length - 3);
|
||||||
|
c.Set(cmdparams[2], _value);
|
||||||
|
Config.Merge(source);
|
||||||
|
|
||||||
|
Notice("In section [{0}], set {1} = {2}", c.Name, cmdparams[2], _value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "get":
|
||||||
|
case "show":
|
||||||
|
if (cmdparams.Length == 1)
|
||||||
|
{
|
||||||
|
foreach (IConfig config in Config.Configs)
|
||||||
|
{
|
||||||
|
Notice("[{0}]", config.Name);
|
||||||
|
string[] keys = config.GetKeys();
|
||||||
|
foreach (string key in keys)
|
||||||
|
Notice(" {0} = {1}", key, config.GetString(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cmdparams.Length == 2 || cmdparams.Length == 3)
|
||||||
|
{
|
||||||
|
IConfig config = Config.Configs[cmdparams[1]];
|
||||||
|
if (config == null)
|
||||||
|
{
|
||||||
|
Notice("Section \"{0}\" does not exist.",cmdparams[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cmdparams.Length == 2)
|
||||||
|
{
|
||||||
|
Notice("[{0}]", config.Name);
|
||||||
|
foreach (string key in config.GetKeys())
|
||||||
|
Notice(" {0} = {1}", key, config.GetString(key));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Notice(
|
||||||
|
"config get {0} {1} : {2}",
|
||||||
|
cmdparams[1], cmdparams[2], config.GetString(cmdparams[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Notice("Syntax: config {0} [<section>] [<key>]", firstParam);
|
||||||
|
Notice("Example: config {0} ScriptEngine.DotNetEngine NumberOfScriptThreads", firstParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "save":
|
||||||
|
if (cmdparams.Length < 2)
|
||||||
|
{
|
||||||
|
Notice("Syntax: config save <path>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = cmdparams[1];
|
||||||
|
Notice("Saving configuration file: {0}", path);
|
||||||
|
|
||||||
|
if (Config is IniConfigSource)
|
||||||
|
{
|
||||||
|
IniConfigSource iniCon = (IniConfigSource)Config;
|
||||||
|
iniCon.Save(path);
|
||||||
|
}
|
||||||
|
else if (Config is XmlConfigSource)
|
||||||
|
{
|
||||||
|
XmlConfigSource xmlCon = (XmlConfigSource)Config;
|
||||||
|
xmlCon.Save(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleSetLogLevel(string module, string[] cmd)
|
||||||
|
{
|
||||||
|
if (cmd.Length != 4)
|
||||||
|
{
|
||||||
|
Notice("Usage: set log level <level>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == m_consoleAppender)
|
||||||
|
{
|
||||||
|
Notice("No appender named Console found (see the log4net config file for this executable)!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string rawLevel = cmd[3];
|
||||||
|
|
||||||
|
ILoggerRepository repository = LogManager.GetRepository();
|
||||||
|
Level consoleLevel = repository.LevelMap[rawLevel];
|
||||||
|
|
||||||
|
if (consoleLevel != null)
|
||||||
|
m_consoleAppender.Threshold = consoleLevel;
|
||||||
|
else
|
||||||
|
Notice(
|
||||||
|
"{0} is not a valid logging level. Valid logging levels are ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF",
|
||||||
|
rawLevel);
|
||||||
|
|
||||||
|
ShowLogLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowLogLevel()
|
||||||
|
{
|
||||||
|
Notice("Console log level is {0}", m_consoleAppender.Threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void HandleScript(string module, string[] parms)
|
||||||
|
{
|
||||||
|
if (parms.Length != 2)
|
||||||
|
{
|
||||||
|
Notice("Usage: command-script <path-to-script");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunCommandScript(parms[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run an optional startup list of commands
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName"></param>
|
||||||
|
protected void RunCommandScript(string fileName)
|
||||||
|
{
|
||||||
|
if (m_console == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
m_log.Info("[SERVER BASE]: Running " + fileName);
|
||||||
|
|
||||||
|
using (StreamReader readFile = File.OpenText(fileName))
|
||||||
|
{
|
||||||
|
string currentCommand;
|
||||||
|
while ((currentCommand = readFile.ReadLine()) != null)
|
||||||
|
{
|
||||||
|
currentCommand = currentCommand.Trim();
|
||||||
|
if (!(currentCommand == ""
|
||||||
|
|| currentCommand.StartsWith(";")
|
||||||
|
|| currentCommand.StartsWith("//")
|
||||||
|
|| currentCommand.StartsWith("#")))
|
||||||
|
{
|
||||||
|
m_log.Info("[SERVER BASE]: Running '" + currentCommand + "'");
|
||||||
|
m_console.RunCommand(currentCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return a report about the uptime of this server
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected string GetUptimeReport()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now));
|
||||||
|
sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime));
|
||||||
|
sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime));
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ShowInfo()
|
||||||
|
{
|
||||||
|
Notice(GetVersionText());
|
||||||
|
Notice("Startup directory: " + m_startupDirectory);
|
||||||
|
if (null != m_consoleAppender)
|
||||||
|
Notice(String.Format("Console log level: {0}", m_consoleAppender.Threshold));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enhance the version string with extra information if it's available.
|
||||||
|
/// </summary>
|
||||||
|
protected void EnhanceVersionInformation()
|
||||||
|
{
|
||||||
|
string buildVersion = string.Empty;
|
||||||
|
|
||||||
|
// The subversion information is deprecated and will be removed at a later date
|
||||||
|
// Add subversion revision information if available
|
||||||
|
// Try file "svn_revision" in the current directory first, then the .svn info.
|
||||||
|
// This allows to make the revision available in simulators not running from the source tree.
|
||||||
|
// FIXME: Making an assumption about the directory we're currently in - we do this all over the place
|
||||||
|
// elsewhere as well
|
||||||
|
string gitDir = "../.git/";
|
||||||
|
string gitRefPointerPath = gitDir + "HEAD";
|
||||||
|
|
||||||
|
string svnRevisionFileName = "svn_revision";
|
||||||
|
string svnFileName = ".svn/entries";
|
||||||
|
string manualVersionFileName = ".version";
|
||||||
|
string inputLine;
|
||||||
|
int strcmp;
|
||||||
|
|
||||||
|
if (File.Exists(manualVersionFileName))
|
||||||
|
{
|
||||||
|
using (StreamReader CommitFile = File.OpenText(manualVersionFileName))
|
||||||
|
buildVersion = CommitFile.ReadLine();
|
||||||
|
|
||||||
|
m_version += buildVersion ?? "";
|
||||||
|
}
|
||||||
|
else if (File.Exists(gitRefPointerPath))
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SERVER BASE]: Found {0}", gitRefPointerPath);
|
||||||
|
|
||||||
|
string rawPointer = "";
|
||||||
|
|
||||||
|
using (StreamReader pointerFile = File.OpenText(gitRefPointerPath))
|
||||||
|
rawPointer = pointerFile.ReadLine();
|
||||||
|
|
||||||
|
// m_log.DebugFormat("[SERVER BASE]: rawPointer [{0}]", rawPointer);
|
||||||
|
|
||||||
|
Match m = Regex.Match(rawPointer, "^ref: (.+)$");
|
||||||
|
|
||||||
|
if (m.Success)
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SERVER BASE]: Matched [{0}]", m.Groups[1].Value);
|
||||||
|
|
||||||
|
string gitRef = m.Groups[1].Value;
|
||||||
|
string gitRefPath = gitDir + gitRef;
|
||||||
|
if (File.Exists(gitRefPath))
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SERVER BASE]: Found gitRefPath [{0}]", gitRefPath);
|
||||||
|
|
||||||
|
using (StreamReader refFile = File.OpenText(gitRefPath))
|
||||||
|
{
|
||||||
|
string gitHash = refFile.ReadLine();
|
||||||
|
m_version += gitHash.Substring(0, 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remove the else logic when subversion mirror is no longer used
|
||||||
|
if (File.Exists(svnRevisionFileName))
|
||||||
|
{
|
||||||
|
StreamReader RevisionFile = File.OpenText(svnRevisionFileName);
|
||||||
|
buildVersion = RevisionFile.ReadLine();
|
||||||
|
buildVersion.Trim();
|
||||||
|
RevisionFile.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName))
|
||||||
|
{
|
||||||
|
StreamReader EntriesFile = File.OpenText(svnFileName);
|
||||||
|
inputLine = EntriesFile.ReadLine();
|
||||||
|
while (inputLine != null)
|
||||||
|
{
|
||||||
|
// using the dir svn revision at the top of entries file
|
||||||
|
strcmp = String.Compare(inputLine, "dir");
|
||||||
|
if (strcmp == 0)
|
||||||
|
{
|
||||||
|
buildVersion = EntriesFile.ReadLine();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputLine = EntriesFile.ReadLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntriesFile.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_version += string.IsNullOrEmpty(buildVersion) ? " " : ("." + buildVersion + " ").Substring(0, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string GetVersionText()
|
||||||
|
{
|
||||||
|
return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a report about the registered threads in this server.
|
||||||
|
/// </summary>
|
||||||
|
protected string GetThreadsReport()
|
||||||
|
{
|
||||||
|
// This should be a constant field.
|
||||||
|
string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
|
||||||
|
|
||||||
|
sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
|
||||||
|
|
||||||
|
int timeNow = Environment.TickCount & Int32.MaxValue;
|
||||||
|
|
||||||
|
sb.AppendFormat(reportFormat, "ID", "NAME", "LAST UPDATE (MS)", "LIFETIME (MS)", "PRIORITY", "STATE");
|
||||||
|
sb.Append(Environment.NewLine);
|
||||||
|
|
||||||
|
foreach (Watchdog.ThreadWatchdogInfo twi in threads)
|
||||||
|
{
|
||||||
|
Thread t = twi.Thread;
|
||||||
|
|
||||||
|
sb.AppendFormat(
|
||||||
|
reportFormat,
|
||||||
|
t.ManagedThreadId,
|
||||||
|
t.Name,
|
||||||
|
timeNow - twi.LastTick,
|
||||||
|
timeNow - twi.FirstTick,
|
||||||
|
t.Priority,
|
||||||
|
t.ThreadState);
|
||||||
|
|
||||||
|
sb.Append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append("\n");
|
||||||
|
|
||||||
|
// For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
|
||||||
|
// zero active threads.
|
||||||
|
int totalThreads = Process.GetCurrentProcess().Threads.Count;
|
||||||
|
if (totalThreads > 0)
|
||||||
|
sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
|
||||||
|
|
||||||
|
sb.Append("Main threadpool (excluding script engine pools)\n");
|
||||||
|
sb.Append(Util.GetThreadPoolReport());
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void HandleThreadsAbort(string module, string[] cmd)
|
||||||
|
{
|
||||||
|
if (cmd.Length != 3)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Output("Usage: threads abort <thread-id>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int threadId;
|
||||||
|
if (!int.TryParse(cmd[2], out threadId))
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Output("ERROR: Thread id must be an integer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Watchdog.AbortThread(threadId))
|
||||||
|
MainConsole.Instance.OutputFormat("Aborted thread with id {0}", threadId);
|
||||||
|
else
|
||||||
|
MainConsole.Instance.OutputFormat("ERROR - Thread with id {0} not found in managed threads", threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Console output is only possible if a console has been established.
|
||||||
|
/// That is something that cannot be determined within this class. So
|
||||||
|
/// all attempts to use the console MUST be verified.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msg"></param>
|
||||||
|
protected void Notice(string msg)
|
||||||
|
{
|
||||||
|
if (m_console != null)
|
||||||
|
{
|
||||||
|
m_console.Output(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Console output is only possible if a console has been established.
|
||||||
|
/// That is something that cannot be determined within this class. So
|
||||||
|
/// all attempts to use the console MUST be verified.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format"></param>
|
||||||
|
/// <param name="components"></param>
|
||||||
|
protected void Notice(string format, params object[] components)
|
||||||
|
{
|
||||||
|
if (m_console != null)
|
||||||
|
m_console.OutputFormat(format, components);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,11 +35,12 @@ using HttpServer;
|
||||||
using HttpServer.FormDecoders;
|
using HttpServer.FormDecoders;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using OpenSim.Framework.Servers.HttpServer;
|
using OpenSim.Framework.Servers.HttpServer;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Servers.Tests
|
namespace OpenSim.Framework.Servers.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class OSHttpTests
|
public class OSHttpTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
// we need an IHttpClientContext for our tests
|
// we need an IHttpClientContext for our tests
|
||||||
public class TestHttpClientContext: IHttpClientContext
|
public class TestHttpClientContext: IHttpClientContext
|
||||||
|
|
|
@ -29,11 +29,12 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Servers.Tests
|
namespace OpenSim.Framework.Servers.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class VersionInfoTests
|
public class VersionInfoTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestVersionLength()
|
public void TestVersionLength()
|
||||||
|
|
|
@ -24,16 +24,17 @@
|
||||||
* (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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenMetaverse.StructuredData;
|
using OpenMetaverse.StructuredData;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Tests
|
namespace OpenSim.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class AgentCircuitDataTest
|
public class AgentCircuitDataTest : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private UUID AgentId;
|
private UUID AgentId;
|
||||||
private AvatarAppearance AvAppearance;
|
private AvatarAppearance AvAppearance;
|
||||||
|
|
|
@ -38,7 +38,7 @@ using Animation = OpenSim.Framework.Animation;
|
||||||
namespace OpenSim.Framework.Tests
|
namespace OpenSim.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class AnimationTests
|
public class AnimationTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private Animation anim1 = null;
|
private Animation anim1 = null;
|
||||||
private Animation anim2 = null;
|
private Animation anim2 = null;
|
||||||
|
|
|
@ -30,11 +30,12 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Tests
|
namespace OpenSim.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class AssetBaseTest
|
public class AssetBaseTest : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestContainsReferences()
|
public void TestContainsReferences()
|
||||||
|
|
|
@ -28,11 +28,12 @@
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Tests
|
namespace OpenSim.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class CacheTests
|
public class CacheTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private Cache cache;
|
private Cache cache;
|
||||||
private UUID cacheItemUUID;
|
private UUID cacheItemUUID;
|
||||||
|
|
|
@ -26,11 +26,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Tests
|
namespace OpenSim.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class LocationTest
|
public class LocationTest : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void locationRegionHandleRegionHandle()
|
public void locationRegionHandleRegionHandle()
|
||||||
|
|
|
@ -32,11 +32,12 @@ using OpenMetaverse.StructuredData;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Tests
|
namespace OpenSim.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class MundaneFrameworkTests
|
public class MundaneFrameworkTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private bool m_RegionSettingsOnSaveEventFired;
|
private bool m_RegionSettingsOnSaveEventFired;
|
||||||
private bool m_RegionLightShareDataOnSaveEventFired;
|
private bool m_RegionLightShareDataOnSaveEventFired;
|
||||||
|
|
|
@ -31,11 +31,12 @@ using NUnit.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenMetaverse.StructuredData;
|
using OpenMetaverse.StructuredData;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Tests
|
namespace OpenSim.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PrimeNumberHelperTests
|
public class PrimeNumberHelperTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGetPrime()
|
public void TestGetPrime()
|
||||||
|
|
|
@ -33,7 +33,7 @@ using OpenSim.Tests.Common;
|
||||||
namespace OpenSim.Framework.Tests
|
namespace OpenSim.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class UtilTests
|
public class UtilTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void VectorOperationTests()
|
public void VectorOperationTests()
|
||||||
|
|
|
@ -1741,12 +1741,16 @@ namespace OpenSim.Framework
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
|
if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
|
||||||
{
|
{
|
||||||
threadPoolUsed = "SmartThreadPool";
|
// ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
|
||||||
maxThreads = m_ThreadPool.MaxThreads;
|
if (m_ThreadPool != null)
|
||||||
minThreads = m_ThreadPool.MinThreads;
|
{
|
||||||
inUseThreads = m_ThreadPool.InUseThreads;
|
threadPoolUsed = "SmartThreadPool";
|
||||||
allocatedThreads = m_ThreadPool.ActiveThreads;
|
maxThreads = m_ThreadPool.MaxThreads;
|
||||||
waitingCallbacks = m_ThreadPool.WaitingCallbacks;
|
minThreads = m_ThreadPool.MinThreads;
|
||||||
|
inUseThreads = m_ThreadPool.InUseThreads;
|
||||||
|
allocatedThreads = m_ThreadPool.ActiveThreads;
|
||||||
|
waitingCallbacks = m_ThreadPool.WaitingCallbacks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
|
FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
|
||||||
|
|
|
@ -188,7 +188,6 @@ namespace OpenSim
|
||||||
// Make sure command line options take precedence
|
// Make sure command line options take precedence
|
||||||
m_config.Source.Merge(argvSource);
|
m_config.Source.Merge(argvSource);
|
||||||
|
|
||||||
|
|
||||||
IConfig enVars = m_config.Source.Configs["Environment"];
|
IConfig enVars = m_config.Source.Configs["Environment"];
|
||||||
|
|
||||||
if( enVars != null )
|
if( enVars != null )
|
||||||
|
|
|
@ -82,8 +82,8 @@ namespace OpenSim
|
||||||
{
|
{
|
||||||
base.ReadExtraConfigSettings();
|
base.ReadExtraConfigSettings();
|
||||||
|
|
||||||
IConfig startupConfig = m_config.Source.Configs["Startup"];
|
IConfig startupConfig = Config.Configs["Startup"];
|
||||||
IConfig networkConfig = m_config.Source.Configs["Network"];
|
IConfig networkConfig = Config.Configs["Network"];
|
||||||
|
|
||||||
int stpMaxThreads = 15;
|
int stpMaxThreads = 15;
|
||||||
|
|
||||||
|
@ -106,22 +106,6 @@ namespace OpenSim
|
||||||
m_timeInterval = startupConfig.GetInt("timer_Interval", 1200);
|
m_timeInterval = startupConfig.GetInt("timer_Interval", 1200);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_logFileAppender != null)
|
|
||||||
{
|
|
||||||
if (m_logFileAppender is log4net.Appender.FileAppender)
|
|
||||||
{
|
|
||||||
log4net.Appender.FileAppender appender =
|
|
||||||
(log4net.Appender.FileAppender)m_logFileAppender;
|
|
||||||
string fileName = startupConfig.GetString("LogFile", String.Empty);
|
|
||||||
if (fileName != String.Empty)
|
|
||||||
{
|
|
||||||
appender.File = fileName;
|
|
||||||
appender.ActivateOptions();
|
|
||||||
}
|
|
||||||
m_log.InfoFormat("[LOGGING]: Logging started to file {0}", appender.File);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string asyncCallMethodStr = startupConfig.GetString("async_call_method", String.Empty);
|
string asyncCallMethodStr = startupConfig.GetString("async_call_method", String.Empty);
|
||||||
FireAndForgetMethod asyncCallMethod;
|
FireAndForgetMethod asyncCallMethod;
|
||||||
if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse<FireAndForgetMethod>(asyncCallMethodStr, out asyncCallMethod))
|
if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse<FireAndForgetMethod>(asyncCallMethodStr, out asyncCallMethod))
|
||||||
|
@ -164,7 +148,7 @@ namespace OpenSim
|
||||||
break;
|
break;
|
||||||
case "rest":
|
case "rest":
|
||||||
m_console = new RemoteConsole("Region");
|
m_console = new RemoteConsole("Region");
|
||||||
((RemoteConsole)m_console).ReadConfig(m_config.Source);
|
((RemoteConsole)m_console).ReadConfig(Config);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
m_console = new LocalConsole("Region");
|
m_console = new LocalConsole("Region");
|
||||||
|
@ -174,6 +158,7 @@ namespace OpenSim
|
||||||
|
|
||||||
MainConsole.Instance = m_console;
|
MainConsole.Instance = m_console;
|
||||||
|
|
||||||
|
RegisterCommonAppenders(Config.Configs["Startup"]);
|
||||||
RegisterConsoleCommands();
|
RegisterConsoleCommands();
|
||||||
|
|
||||||
base.StartupSpecific();
|
base.StartupSpecific();
|
||||||
|
@ -372,26 +357,6 @@ namespace OpenSim
|
||||||
"restart",
|
"restart",
|
||||||
"Restart all sims in this instance", RunCommand);
|
"Restart all sims in this instance", RunCommand);
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "config set",
|
|
||||||
"config set <section> <key> <value>",
|
|
||||||
"Set a config option. In most cases this is not useful since changed parameters are not dynamically reloaded. Neither do changed parameters persist - you will have to change a config file manually and restart.", HandleConfig);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "config get",
|
|
||||||
"config get [<section>] [<key>]",
|
|
||||||
"Synonym for config show",
|
|
||||||
HandleConfig);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "config show",
|
|
||||||
"config show [<section>] [<key>]",
|
|
||||||
"Show config information",
|
|
||||||
"If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine
|
|
||||||
+ "If a section is given but not a field, then all fields in that section are printed.",
|
|
||||||
HandleConfig);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "config save",
|
|
||||||
"config save <path>",
|
|
||||||
"Save current configuration to a file at the given path", HandleConfig);
|
|
||||||
|
|
||||||
m_console.Commands.AddCommand("General", false, "command-script",
|
m_console.Commands.AddCommand("General", false, "command-script",
|
||||||
"command-script <script>",
|
"command-script <script>",
|
||||||
"Run a command script from file", RunCommand);
|
"Run a command script from file", RunCommand);
|
||||||
|
@ -501,35 +466,6 @@ namespace OpenSim
|
||||||
MainConsole.Instance.Output("");
|
MainConsole.Instance.Output("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Run an optional startup list of commands
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileName"></param>
|
|
||||||
private void RunCommandScript(string fileName)
|
|
||||||
{
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
{
|
|
||||||
m_log.Info("[COMMANDFILE]: Running " + fileName);
|
|
||||||
|
|
||||||
using (StreamReader readFile = File.OpenText(fileName))
|
|
||||||
{
|
|
||||||
string currentCommand;
|
|
||||||
while ((currentCommand = readFile.ReadLine()) != null)
|
|
||||||
{
|
|
||||||
currentCommand = currentCommand.Trim();
|
|
||||||
if (!(currentCommand == ""
|
|
||||||
|| currentCommand.StartsWith(";")
|
|
||||||
|| currentCommand.StartsWith("//")
|
|
||||||
|| currentCommand.StartsWith("#")))
|
|
||||||
{
|
|
||||||
m_log.Info("[COMMANDFILE]: Running '" + currentCommand + "'");
|
|
||||||
m_console.RunCommand(currentCommand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens a file and uses it as input to the console command parser.
|
/// Opens a file and uses it as input to the console command parser.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -634,111 +570,9 @@ namespace OpenSim
|
||||||
bool changed = PopulateRegionEstateInfo(regInfo);
|
bool changed = PopulateRegionEstateInfo(regInfo);
|
||||||
IScene scene;
|
IScene scene;
|
||||||
CreateRegion(regInfo, true, out scene);
|
CreateRegion(regInfo, true, out scene);
|
||||||
|
|
||||||
if (changed)
|
if (changed)
|
||||||
regInfo.EstateSettings.Save();
|
regInfo.EstateSettings.Save();
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Change and load configuration file data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="module"></param>
|
|
||||||
/// <param name="cmd"></param>
|
|
||||||
private void HandleConfig(string module, string[] cmd)
|
|
||||||
{
|
|
||||||
List<string> args = new List<string>(cmd);
|
|
||||||
args.RemoveAt(0);
|
|
||||||
string[] cmdparams = args.ToArray();
|
|
||||||
|
|
||||||
if (cmdparams.Length > 0)
|
|
||||||
{
|
|
||||||
string firstParam = cmdparams[0].ToLower();
|
|
||||||
|
|
||||||
switch (firstParam)
|
|
||||||
{
|
|
||||||
case "set":
|
|
||||||
if (cmdparams.Length < 4)
|
|
||||||
{
|
|
||||||
Notice("Syntax: config set <section> <key> <value>");
|
|
||||||
Notice("Example: config set ScriptEngine.DotNetEngine NumberOfScriptThreads 5");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IConfig c;
|
|
||||||
IConfigSource source = new IniConfigSource();
|
|
||||||
c = source.AddConfig(cmdparams[1]);
|
|
||||||
if (c != null)
|
|
||||||
{
|
|
||||||
string _value = String.Join(" ", cmdparams, 3, cmdparams.Length - 3);
|
|
||||||
c.Set(cmdparams[2], _value);
|
|
||||||
m_config.Source.Merge(source);
|
|
||||||
|
|
||||||
Notice("In section [{0}], set {1} = {2}", c.Name, cmdparams[2], _value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "get":
|
|
||||||
case "show":
|
|
||||||
if (cmdparams.Length == 1)
|
|
||||||
{
|
|
||||||
foreach (IConfig config in m_config.Source.Configs)
|
|
||||||
{
|
|
||||||
Notice("[{0}]", config.Name);
|
|
||||||
string[] keys = config.GetKeys();
|
|
||||||
foreach (string key in keys)
|
|
||||||
Notice(" {0} = {1}", key, config.GetString(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cmdparams.Length == 2 || cmdparams.Length == 3)
|
|
||||||
{
|
|
||||||
IConfig config = m_config.Source.Configs[cmdparams[1]];
|
|
||||||
if (config == null)
|
|
||||||
{
|
|
||||||
Notice("Section \"{0}\" does not exist.",cmdparams[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (cmdparams.Length == 2)
|
|
||||||
{
|
|
||||||
Notice("[{0}]", config.Name);
|
|
||||||
foreach (string key in config.GetKeys())
|
|
||||||
Notice(" {0} = {1}", key, config.GetString(key));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Notice(
|
|
||||||
"config get {0} {1} : {2}",
|
|
||||||
cmdparams[1], cmdparams[2], config.GetString(cmdparams[2]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Notice("Syntax: config {0} [<section>] [<key>]", firstParam);
|
|
||||||
Notice("Example: config {0} ScriptEngine.DotNetEngine NumberOfScriptThreads", firstParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "save":
|
|
||||||
if (cmdparams.Length < 2)
|
|
||||||
{
|
|
||||||
Notice("Syntax: config save <path>");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Application.iniFilePath == cmdparams[1])
|
|
||||||
{
|
|
||||||
Notice("Path can not be " + Application.iniFilePath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Notice("Saving configuration file: " + cmdparams[1]);
|
|
||||||
m_config.Save(cmdparams[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -787,13 +621,6 @@ namespace OpenSim
|
||||||
|
|
||||||
switch (command)
|
switch (command)
|
||||||
{
|
{
|
||||||
case "command-script":
|
|
||||||
if (cmdparams.Length > 0)
|
|
||||||
{
|
|
||||||
RunCommandScript(cmdparams[0]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "backup":
|
case "backup":
|
||||||
MainConsole.Instance.Output("Triggering save of pending object updates to persistent store");
|
MainConsole.Instance.Output("Triggering save of pending object updates to persistent store");
|
||||||
SceneManager.BackupCurrentScene();
|
SceneManager.BackupCurrentScene();
|
||||||
|
@ -837,12 +664,20 @@ namespace OpenSim
|
||||||
|
|
||||||
if (!SceneManager.TrySetCurrentScene(newRegionName))
|
if (!SceneManager.TrySetCurrentScene(newRegionName))
|
||||||
MainConsole.Instance.Output(String.Format("Couldn't select region {0}", newRegionName));
|
MainConsole.Instance.Output(String.Format("Couldn't select region {0}", newRegionName));
|
||||||
|
else
|
||||||
|
RefreshPrompt();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MainConsole.Instance.Output("Usage: change region <region name>");
|
MainConsole.Instance.Output("Usage: change region <region name>");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Refreshs prompt with the current selection details.
|
||||||
|
/// </summary>
|
||||||
|
private void RefreshPrompt()
|
||||||
|
{
|
||||||
string regionName = (SceneManager.CurrentScene == null ? "root" : SceneManager.CurrentScene.RegionInfo.RegionName);
|
string regionName = (SceneManager.CurrentScene == null ? "root" : SceneManager.CurrentScene.RegionInfo.RegionName);
|
||||||
MainConsole.Instance.Output(String.Format("Currently selected region is {0}", regionName));
|
MainConsole.Instance.Output(String.Format("Currently selected region is {0}", regionName));
|
||||||
|
|
||||||
|
@ -864,6 +699,18 @@ namespace OpenSim
|
||||||
m_console.ConsoleScene = SceneManager.CurrentScene;
|
m_console.ConsoleScene = SceneManager.CurrentScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void HandleRestartRegion(RegionInfo whichRegion)
|
||||||
|
{
|
||||||
|
base.HandleRestartRegion(whichRegion);
|
||||||
|
|
||||||
|
// Where we are restarting multiple scenes at once, a previous call to RefreshPrompt may have set the
|
||||||
|
// m_console.ConsoleScene to null (indicating all scenes).
|
||||||
|
if (m_console.ConsoleScene != null && whichRegion.RegionName == ((Scene)m_console.ConsoleScene).Name)
|
||||||
|
SceneManager.TrySetCurrentScene(whichRegion.RegionName);
|
||||||
|
|
||||||
|
RefreshPrompt();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Turn on some debugging values for OpenSim.
|
/// Turn on some debugging values for OpenSim.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -100,13 +100,7 @@ namespace OpenSim
|
||||||
/// <value>
|
/// <value>
|
||||||
/// The config information passed into the OpenSimulator region server.
|
/// The config information passed into the OpenSimulator region server.
|
||||||
/// </value>
|
/// </value>
|
||||||
public OpenSimConfigSource ConfigSource
|
public OpenSimConfigSource ConfigSource { get; private set; }
|
||||||
{
|
|
||||||
get { return m_config; }
|
|
||||||
set { m_config = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected OpenSimConfigSource m_config;
|
|
||||||
|
|
||||||
public List<IClientNetworkServer> ClientServers
|
public List<IClientNetworkServer> ClientServers
|
||||||
{
|
{
|
||||||
|
@ -146,13 +140,14 @@ namespace OpenSim
|
||||||
protected virtual void LoadConfigSettings(IConfigSource configSource)
|
protected virtual void LoadConfigSettings(IConfigSource configSource)
|
||||||
{
|
{
|
||||||
m_configLoader = new ConfigurationLoader();
|
m_configLoader = new ConfigurationLoader();
|
||||||
m_config = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo);
|
ConfigSource = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo);
|
||||||
|
Config = ConfigSource.Source;
|
||||||
ReadExtraConfigSettings();
|
ReadExtraConfigSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ReadExtraConfigSettings()
|
protected virtual void ReadExtraConfigSettings()
|
||||||
{
|
{
|
||||||
IConfig networkConfig = m_config.Source.Configs["Network"];
|
IConfig networkConfig = Config.Configs["Network"];
|
||||||
if (networkConfig != null)
|
if (networkConfig != null)
|
||||||
{
|
{
|
||||||
proxyUrl = networkConfig.GetString("proxy_url", "");
|
proxyUrl = networkConfig.GetString("proxy_url", "");
|
||||||
|
@ -185,7 +180,7 @@ namespace OpenSim
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void StartupSpecific()
|
protected override void StartupSpecific()
|
||||||
{
|
{
|
||||||
IConfig startupConfig = m_config.Source.Configs["Startup"];
|
IConfig startupConfig = Config.Configs["Startup"];
|
||||||
if (startupConfig != null)
|
if (startupConfig != null)
|
||||||
{
|
{
|
||||||
string pidFile = startupConfig.GetString("PIDFile", String.Empty);
|
string pidFile = startupConfig.GetString("PIDFile", String.Empty);
|
||||||
|
@ -196,7 +191,7 @@ namespace OpenSim
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the simulation data service
|
// Load the simulation data service
|
||||||
IConfig simDataConfig = m_config.Source.Configs["SimulationDataStore"];
|
IConfig simDataConfig = Config.Configs["SimulationDataStore"];
|
||||||
if (simDataConfig == null)
|
if (simDataConfig == null)
|
||||||
throw new Exception("Configuration file is missing the [SimulationDataStore] section. Have you copied OpenSim.ini.example to OpenSim.ini to reference config-include/ files?");
|
throw new Exception("Configuration file is missing the [SimulationDataStore] section. Have you copied OpenSim.ini.example to OpenSim.ini to reference config-include/ files?");
|
||||||
|
|
||||||
|
@ -204,7 +199,7 @@ namespace OpenSim
|
||||||
if (String.IsNullOrEmpty(module))
|
if (String.IsNullOrEmpty(module))
|
||||||
throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [SimulationDataStore] section.");
|
throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [SimulationDataStore] section.");
|
||||||
|
|
||||||
m_simulationDataService = ServerUtils.LoadPlugin<ISimulationDataService>(module, new object[] { m_config.Source });
|
m_simulationDataService = ServerUtils.LoadPlugin<ISimulationDataService>(module, new object[] { Config });
|
||||||
if (m_simulationDataService == null)
|
if (m_simulationDataService == null)
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
string.Format(
|
string.Format(
|
||||||
|
@ -212,7 +207,7 @@ namespace OpenSim
|
||||||
module));
|
module));
|
||||||
|
|
||||||
// Load the estate data service
|
// Load the estate data service
|
||||||
IConfig estateDataConfig = m_config.Source.Configs["EstateDataStore"];
|
IConfig estateDataConfig = Config.Configs["EstateDataStore"];
|
||||||
if (estateDataConfig == null)
|
if (estateDataConfig == null)
|
||||||
throw new Exception("Configuration file is missing the [EstateDataStore] section. Have you copied OpenSim.ini.example to OpenSim.ini to reference config-include/ files?");
|
throw new Exception("Configuration file is missing the [EstateDataStore] section. Have you copied OpenSim.ini.example to OpenSim.ini to reference config-include/ files?");
|
||||||
|
|
||||||
|
@ -220,7 +215,7 @@ namespace OpenSim
|
||||||
if (String.IsNullOrEmpty(module))
|
if (String.IsNullOrEmpty(module))
|
||||||
throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [EstateDataStore] section");
|
throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [EstateDataStore] section");
|
||||||
|
|
||||||
m_estateDataService = ServerUtils.LoadPlugin<IEstateDataService>(module, new object[] { m_config.Source });
|
m_estateDataService = ServerUtils.LoadPlugin<IEstateDataService>(module, new object[] { Config });
|
||||||
if (m_estateDataService == null)
|
if (m_estateDataService == null)
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
string.Format(
|
string.Format(
|
||||||
|
@ -242,7 +237,7 @@ namespace OpenSim
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void AddPluginCommands(CommandConsole console)
|
protected virtual void AddPluginCommands(ICommandConsole console)
|
||||||
{
|
{
|
||||||
List<string> topics = GetHelpTopics();
|
List<string> topics = GetHelpTopics();
|
||||||
|
|
||||||
|
@ -304,7 +299,7 @@ namespace OpenSim
|
||||||
// Called from base.StartUp()
|
// Called from base.StartUp()
|
||||||
|
|
||||||
m_httpServerPort = m_networkServersInfo.HttpListenerPort;
|
m_httpServerPort = m_networkServersInfo.HttpListenerPort;
|
||||||
SceneManager.OnRestartSim += handleRestartRegion;
|
SceneManager.OnRestartSim += HandleRestartRegion;
|
||||||
|
|
||||||
// Only enable the watchdogs when all regions are ready. Otherwise we get false positives when cpu is
|
// Only enable the watchdogs when all regions are ready. Otherwise we get false positives when cpu is
|
||||||
// heavily used during initial startup.
|
// heavily used during initial startup.
|
||||||
|
@ -369,7 +364,7 @@ namespace OpenSim
|
||||||
}
|
}
|
||||||
|
|
||||||
IClientNetworkServer clientServer;
|
IClientNetworkServer clientServer;
|
||||||
Scene scene = SetupScene(regionInfo, proxyOffset, m_config.Source, out clientServer);
|
Scene scene = SetupScene(regionInfo, proxyOffset, Config, out clientServer);
|
||||||
|
|
||||||
m_log.Info("[MODULES]: Loading Region's modules (old style)");
|
m_log.Info("[MODULES]: Loading Region's modules (old style)");
|
||||||
|
|
||||||
|
@ -451,10 +446,10 @@ namespace OpenSim
|
||||||
string estateOwnerPassword = null;
|
string estateOwnerPassword = null;
|
||||||
string rawEstateOwnerUuid = null;
|
string rawEstateOwnerUuid = null;
|
||||||
|
|
||||||
if (m_config.Source.Configs[ESTATE_SECTION_NAME] != null)
|
if (Config.Configs[ESTATE_SECTION_NAME] != null)
|
||||||
{
|
{
|
||||||
string defaultEstateOwnerName
|
string defaultEstateOwnerName
|
||||||
= m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
|
= Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
|
||||||
string[] ownerNames = defaultEstateOwnerName.Split(' ');
|
string[] ownerNames = defaultEstateOwnerName.Split(' ');
|
||||||
|
|
||||||
if (ownerNames.Length >= 2)
|
if (ownerNames.Length >= 2)
|
||||||
|
@ -464,9 +459,9 @@ namespace OpenSim
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info to be used only on Standalone Mode
|
// Info to be used only on Standalone Mode
|
||||||
rawEstateOwnerUuid = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerUUID", null);
|
rawEstateOwnerUuid = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerUUID", null);
|
||||||
estateOwnerEMail = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerEMail", null);
|
estateOwnerEMail = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerEMail", null);
|
||||||
estateOwnerPassword = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerPassword", null);
|
estateOwnerPassword = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerPassword", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainConsole.Instance.OutputFormat("Estate {0} has no owner set.", regionInfo.EstateSettings.EstateName);
|
MainConsole.Instance.OutputFormat("Estate {0} has no owner set.", regionInfo.EstateSettings.EstateName);
|
||||||
|
@ -713,7 +708,7 @@ namespace OpenSim
|
||||||
return new Scene(
|
return new Scene(
|
||||||
regionInfo, circuitManager, sceneGridService,
|
regionInfo, circuitManager, sceneGridService,
|
||||||
simDataService, estateDataService, false,
|
simDataService, estateDataService, false,
|
||||||
m_config.Source, m_version);
|
Config, m_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ShutdownClientServer(RegionInfo whichRegion)
|
protected void ShutdownClientServer(RegionInfo whichRegion)
|
||||||
|
@ -740,9 +735,11 @@ namespace OpenSim
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleRestartRegion(RegionInfo whichRegion)
|
protected virtual void HandleRestartRegion(RegionInfo whichRegion)
|
||||||
{
|
{
|
||||||
m_log.Info("[OPENSIM]: Got restart signal from SceneManager");
|
m_log.InfoFormat(
|
||||||
|
"[OPENSIM]: Got restart signal from SceneManager for region {0} ({1},{2})",
|
||||||
|
whichRegion.RegionName, whichRegion.RegionLocX, whichRegion.RegionLocY);
|
||||||
|
|
||||||
ShutdownClientServer(whichRegion);
|
ShutdownClientServer(whichRegion);
|
||||||
IScene scene;
|
IScene scene;
|
||||||
|
@ -754,7 +751,7 @@ namespace OpenSim
|
||||||
protected override PhysicsScene GetPhysicsScene(string osSceneIdentifier)
|
protected override PhysicsScene GetPhysicsScene(string osSceneIdentifier)
|
||||||
{
|
{
|
||||||
return GetPhysicsScene(
|
return GetPhysicsScene(
|
||||||
m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, m_config.Source, osSceneIdentifier);
|
m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, Config, osSceneIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -888,7 +885,6 @@ namespace OpenSim
|
||||||
m_log.Info("[SHUTDOWN]: Closing all threads");
|
m_log.Info("[SHUTDOWN]: Closing all threads");
|
||||||
m_log.Info("[SHUTDOWN]: Killing listener thread");
|
m_log.Info("[SHUTDOWN]: Killing listener thread");
|
||||||
m_log.Info("[SHUTDOWN]: Killing clients");
|
m_log.Info("[SHUTDOWN]: Killing clients");
|
||||||
// TODO: implement this
|
|
||||||
m_log.Info("[SHUTDOWN]: Closing console and terminating");
|
m_log.Info("[SHUTDOWN]: Closing console and terminating");
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -897,7 +893,7 @@ namespace OpenSim
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat("[SHUTDOWN]: Ignoring failure during shutdown - {0}", e);
|
m_log.Error("[SHUTDOWN]: Ignoring failure during shutdown - ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -991,9 +987,9 @@ namespace OpenSim
|
||||||
|
|
||||||
string defaultEstateName = null;
|
string defaultEstateName = null;
|
||||||
|
|
||||||
if (m_config.Source.Configs[ESTATE_SECTION_NAME] != null)
|
if (Config.Configs[ESTATE_SECTION_NAME] != null)
|
||||||
{
|
{
|
||||||
defaultEstateName = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
|
defaultEstateName = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
|
||||||
|
|
||||||
if (defaultEstateName != null)
|
if (defaultEstateName != null)
|
||||||
{
|
{
|
||||||
|
@ -1076,28 +1072,14 @@ namespace OpenSim
|
||||||
MainConsole.Instance.Output("Joining the estate failed. Please try again.");
|
MainConsole.Instance.Output("Joining the estate failed. Please try again.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // need to update the database
|
return true; // need to update the database
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OpenSimConfigSource
|
public class OpenSimConfigSource
|
||||||
{
|
{
|
||||||
public IConfigSource Source;
|
public IConfigSource Source;
|
||||||
|
|
||||||
public void Save(string path)
|
|
||||||
{
|
|
||||||
if (Source is IniConfigSource)
|
|
||||||
{
|
|
||||||
IniConfigSource iniCon = (IniConfigSource) Source;
|
|
||||||
iniCon.Save(path);
|
|
||||||
}
|
|
||||||
else if (Source is XmlConfigSource)
|
|
||||||
{
|
|
||||||
XmlConfigSource xmlCon = (XmlConfigSource) Source;
|
|
||||||
xmlCon.Save(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -44,7 +44,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.ClientStack.Linden.Tests
|
namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class EventQueueTests
|
public class EventQueueTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private TestScene m_scene;
|
private TestScene m_scene;
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class LLImageManagerTests
|
public class LLImageManagerTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private AssetBase m_testImageAsset;
|
private AssetBase m_testImageAsset;
|
||||||
private Scene scene;
|
private Scene scene;
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||||
/// Tests for the LL packet handler
|
/// Tests for the LL packet handler
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PacketHandlerTests
|
public class PacketHandlerTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
// [Test]
|
// [Test]
|
||||||
// /// <summary>
|
// /// <summary>
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace OpenSim.Region.CoreModules.Asset.Tests
|
||||||
/// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness.
|
/// At the moment we're only test the in-memory part of the FlotsamAssetCache. This is a considerable weakness.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class FlotsamAssetCacheTests
|
public class FlotsamAssetCacheTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
protected TestScene m_scene;
|
protected TestScene m_scene;
|
||||||
protected FlotsamAssetCache m_cache;
|
protected FlotsamAssetCache m_cache;
|
||||||
|
|
|
@ -39,7 +39,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class AvatarFactoryModuleTests
|
public class AvatarFactoryModuleTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Only partial right now since we don't yet test that it's ended up in the avatar appearance service.
|
/// Only partial right now since we don't yet test that it's ended up in the avatar appearance service.
|
||||||
|
|
|
@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
|
namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class FriendsModuleTests
|
public class FriendsModuleTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private FriendsModule m_fm;
|
private FriendsModule m_fm;
|
||||||
private TestScene m_scene;
|
private TestScene m_scene;
|
||||||
|
|
|
@ -49,7 +49,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
|
namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class InventoryAccessModuleTests
|
public class InventoryAccessModuleTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
protected TestScene m_scene;
|
protected TestScene m_scene;
|
||||||
protected BasicInventoryAccessModule m_iam;
|
protected BasicInventoryAccessModule m_iam;
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using log4net;
|
||||||
|
using Mono.Addins;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Server.Base;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
||||||
|
{
|
||||||
|
public class BasePresenceServiceConnector : IPresenceService
|
||||||
|
{
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
protected bool m_Enabled;
|
||||||
|
|
||||||
|
protected PresenceDetector m_PresenceDetector;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Underlying presence service. Do not use directly.
|
||||||
|
/// </summary>
|
||||||
|
public IPresenceService m_PresenceService;
|
||||||
|
|
||||||
|
public Type ReplaceableInterface
|
||||||
|
{
|
||||||
|
get { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRegion(Scene scene)
|
||||||
|
{
|
||||||
|
if (!m_Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// m_log.DebugFormat(
|
||||||
|
// "[LOCAL PRESENCE CONNECTOR]: Registering IPresenceService to scene {0}", scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
|
scene.RegisterModuleInterface<IPresenceService>(this);
|
||||||
|
m_PresenceDetector.AddRegion(scene);
|
||||||
|
|
||||||
|
m_log.InfoFormat("[BASE PRESENCE SERVICE CONNECTOR]: Enabled for region {0}", scene.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveRegion(Scene scene)
|
||||||
|
{
|
||||||
|
if (!m_Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_PresenceDetector.RemoveRegion(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegionLoaded(Scene scene)
|
||||||
|
{
|
||||||
|
if (!m_Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostInitialise()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IPresenceService
|
||||||
|
|
||||||
|
public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID)
|
||||||
|
{
|
||||||
|
m_log.Warn("[BASE PRESENCE SERVICE CONNECTOR]: LoginAgent connector not implemented at the simulators");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LogoutAgent(UUID sessionID)
|
||||||
|
{
|
||||||
|
return m_PresenceService.LogoutAgent(sessionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LogoutRegionAgents(UUID regionID)
|
||||||
|
{
|
||||||
|
return m_PresenceService.LogoutRegionAgents(regionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ReportAgent(UUID sessionID, UUID regionID)
|
||||||
|
{
|
||||||
|
return m_PresenceService.ReportAgent(sessionID, regionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceInfo GetAgent(UUID sessionID)
|
||||||
|
{
|
||||||
|
return m_PresenceService.GetAgent(sessionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresenceInfo[] GetAgents(string[] userIDs)
|
||||||
|
{
|
||||||
|
// Don't bother potentially making a useless network call if we not going to ask for any users anyway.
|
||||||
|
if (userIDs.Length == 0)
|
||||||
|
return new PresenceInfo[0];
|
||||||
|
|
||||||
|
return m_PresenceService.GetAgents(userIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,53 +24,29 @@
|
||||||
* (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.Reflection;
|
using System.Reflection;
|
||||||
|
using log4net;
|
||||||
|
using Mono.Addins;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenMetaverse;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
using OpenSim.Server.Base;
|
using OpenSim.Server.Base;
|
||||||
using OpenSim.Services.Interfaces;
|
using OpenSim.Services.Interfaces;
|
||||||
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
|
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
|
||||||
|
|
||||||
using OpenMetaverse;
|
|
||||||
using log4net;
|
|
||||||
using Mono.Addins;
|
|
||||||
using Nini.Config;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
||||||
{
|
{
|
||||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalPresenceServicesConnector")]
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalPresenceServicesConnector")]
|
||||||
public class LocalPresenceServicesConnector : ISharedRegionModule, IPresenceService
|
public class LocalPresenceServicesConnector : BasePresenceServiceConnector, ISharedRegionModule, IPresenceService
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private bool m_Enabled = false;
|
|
||||||
|
|
||||||
private PresenceDetector m_PresenceDetector;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Underlying presence service. Do not use directly.
|
|
||||||
/// </summary>
|
|
||||||
public IPresenceService m_PresenceService;
|
|
||||||
|
|
||||||
public LocalPresenceServicesConnector()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalPresenceServicesConnector(IConfigSource source)
|
|
||||||
{
|
|
||||||
Initialise(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region ISharedRegionModule
|
#region ISharedRegionModule
|
||||||
|
|
||||||
public Type ReplaceableInterface
|
|
||||||
{
|
|
||||||
get { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return "LocalPresenceServicesConnector"; }
|
get { return "LocalPresenceServicesConnector"; }
|
||||||
|
@ -121,81 +97,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PostInitialise()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRegion(Scene scene)
|
|
||||||
{
|
|
||||||
if (!m_Enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// m_log.DebugFormat(
|
|
||||||
// "[LOCAL PRESENCE CONNECTOR]: Registering IPresenceService to scene {0}", scene.RegionInfo.RegionName);
|
|
||||||
|
|
||||||
scene.RegisterModuleInterface<IPresenceService>(this);
|
|
||||||
m_PresenceDetector.AddRegion(scene);
|
|
||||||
|
|
||||||
m_log.InfoFormat("[LOCAL PRESENCE CONNECTOR]: Enabled local presence for region {0}", scene.RegionInfo.RegionName);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRegion(Scene scene)
|
|
||||||
{
|
|
||||||
if (!m_Enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_PresenceDetector.RemoveRegion(scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegionLoaded(Scene scene)
|
|
||||||
{
|
|
||||||
if (!m_Enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IPresenceService
|
|
||||||
|
|
||||||
public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID)
|
|
||||||
{
|
|
||||||
m_log.Warn("[LOCAL PRESENCE CONNECTOR]: LoginAgent connector not implemented at the simulators");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool LogoutAgent(UUID sessionID)
|
|
||||||
{
|
|
||||||
return m_PresenceService.LogoutAgent(sessionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool LogoutRegionAgents(UUID regionID)
|
|
||||||
{
|
|
||||||
return m_PresenceService.LogoutRegionAgents(regionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ReportAgent(UUID sessionID, UUID regionID)
|
|
||||||
{
|
|
||||||
return m_PresenceService.ReportAgent(sessionID, regionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PresenceInfo GetAgent(UUID sessionID)
|
|
||||||
{
|
|
||||||
return m_PresenceService.GetAgent(sessionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PresenceInfo[] GetAgents(string[] userIDs)
|
|
||||||
{
|
|
||||||
return m_PresenceService.GetAgents(userIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,22 +43,12 @@ using Nini.Config;
|
||||||
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
||||||
{
|
{
|
||||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemotePresenceServicesConnector")]
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemotePresenceServicesConnector")]
|
||||||
public class RemotePresenceServicesConnector : ISharedRegionModule, IPresenceService
|
public class RemotePresenceServicesConnector : BasePresenceServiceConnector, ISharedRegionModule
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
#region ISharedRegionModule
|
#region ISharedRegionModule
|
||||||
|
|
||||||
private bool m_Enabled = false;
|
|
||||||
|
|
||||||
private PresenceDetector m_PresenceDetector;
|
|
||||||
private IPresenceService m_RemoteConnector;
|
|
||||||
|
|
||||||
public Type ReplaceableInterface
|
|
||||||
{
|
|
||||||
get { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return "RemotePresenceServicesConnector"; }
|
get { return "RemotePresenceServicesConnector"; }
|
||||||
|
@ -72,7 +62,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
||||||
string name = moduleConfig.GetString("PresenceServices", "");
|
string name = moduleConfig.GetString("PresenceServices", "");
|
||||||
if (name == Name)
|
if (name == Name)
|
||||||
{
|
{
|
||||||
m_RemoteConnector = new PresenceServicesConnector(source);
|
m_PresenceService = new PresenceServicesConnector(source);
|
||||||
|
|
||||||
m_Enabled = true;
|
m_Enabled = true;
|
||||||
|
|
||||||
|
@ -81,81 +71,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
|
||||||
m_log.Info("[REMOTE PRESENCE CONNECTOR]: Remote presence enabled");
|
m_log.Info("[REMOTE PRESENCE CONNECTOR]: Remote presence enabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PostInitialise()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRegion(Scene scene)
|
|
||||||
{
|
|
||||||
if (!m_Enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scene.RegisterModuleInterface<IPresenceService>(this);
|
|
||||||
m_PresenceDetector.AddRegion(scene);
|
|
||||||
|
|
||||||
m_log.InfoFormat("[REMOTE PRESENCE CONNECTOR]: Enabled remote presence for region {0}", scene.RegionInfo.RegionName);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRegion(Scene scene)
|
|
||||||
{
|
|
||||||
if (!m_Enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_PresenceDetector.RemoveRegion(scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegionLoaded(Scene scene)
|
|
||||||
{
|
|
||||||
if (!m_Enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IPresenceService
|
|
||||||
|
|
||||||
public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID)
|
|
||||||
{
|
|
||||||
m_log.Warn("[REMOTE PRESENCE CONNECTOR]: LoginAgent connector not implemented at the simulators");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool LogoutAgent(UUID sessionID)
|
|
||||||
{
|
|
||||||
return m_RemoteConnector.LogoutAgent(sessionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool LogoutRegionAgents(UUID regionID)
|
|
||||||
{
|
|
||||||
return m_RemoteConnector.LogoutRegionAgents(regionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ReportAgent(UUID sessionID, UUID regionID)
|
|
||||||
{
|
|
||||||
return m_RemoteConnector.ReportAgent(sessionID, regionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PresenceInfo GetAgent(UUID sessionID)
|
|
||||||
{
|
|
||||||
return m_RemoteConnector.GetAgent(sessionID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PresenceInfo[] GetAgents(string[] userIDs)
|
|
||||||
{
|
|
||||||
return m_RemoteConnector.GetAgents(userIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -35,7 +35,6 @@ using NUnit.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
|
|
||||||
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence;
|
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
|
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
|
||||||
|
@ -44,7 +43,7 @@ using OpenSim.Tests.Common;
|
||||||
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests
|
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PresenceConnectorsTests
|
public class PresenceConnectorsTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
LocalPresenceServicesConnector m_LocalConnector;
|
LocalPresenceServicesConnector m_LocalConnector;
|
||||||
private void SetUp()
|
private void SetUp()
|
||||||
|
@ -56,7 +55,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests
|
||||||
config.Configs["PresenceService"].Set("LocalServiceModule", "OpenSim.Services.PresenceService.dll:PresenceService");
|
config.Configs["PresenceService"].Set("LocalServiceModule", "OpenSim.Services.PresenceService.dll:PresenceService");
|
||||||
config.Configs["PresenceService"].Set("StorageProvider", "OpenSim.Data.Null.dll");
|
config.Configs["PresenceService"].Set("StorageProvider", "OpenSim.Data.Null.dll");
|
||||||
|
|
||||||
m_LocalConnector = new LocalPresenceServicesConnector(config);
|
m_LocalConnector = new LocalPresenceServicesConnector();
|
||||||
|
m_LocalConnector.Initialise(config);
|
||||||
|
|
||||||
// Let's stick in a test presence
|
// Let's stick in a test presence
|
||||||
m_LocalConnector.m_PresenceService.LoginAgent(UUID.Zero.ToString(), UUID.Zero, UUID.Zero);
|
m_LocalConnector.m_PresenceService.LoginAgent(UUID.Zero.ToString(), UUID.Zero, UUID.Zero);
|
||||||
|
|
|
@ -552,13 +552,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
|
|
||||||
// Validate User and Group UUID's
|
// Validate User and Group UUID's
|
||||||
|
|
||||||
if (!ResolveUserUuid(scene, parcel.OwnerID))
|
if (parcel.IsGroupOwned)
|
||||||
parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
|
|
||||||
|
|
||||||
if (!ResolveGroupUuid(parcel.GroupID))
|
|
||||||
{
|
{
|
||||||
parcel.GroupID = UUID.Zero;
|
if (!ResolveGroupUuid(parcel.GroupID))
|
||||||
parcel.IsGroupOwned = false;
|
{
|
||||||
|
parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
|
||||||
|
parcel.GroupID = UUID.Zero;
|
||||||
|
parcel.IsGroupOwned = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!ResolveUserUuid(scene, parcel.OwnerID))
|
||||||
|
parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
|
||||||
|
|
||||||
|
if (!ResolveGroupUuid(parcel.GroupID))
|
||||||
|
parcel.GroupID = UUID.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<LandAccessEntry> accessList = new List<LandAccessEntry>();
|
List<LandAccessEntry> accessList = new List<LandAccessEntry>();
|
||||||
|
@ -571,8 +580,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
parcel.ParcelAccessList = accessList;
|
parcel.ParcelAccessList = accessList;
|
||||||
|
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[ARCHIVER]: Adding parcel {0}, local id {1}, area {2}",
|
// "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}",
|
||||||
// parcel.Name, parcel.LocalID, parcel.Area);
|
// parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area);
|
||||||
|
|
||||||
landData.Add(parcel);
|
landData.Add(parcel);
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
}
|
}
|
||||||
scenesGroup.CalcSceneLocations();
|
scenesGroup.CalcSceneLocations();
|
||||||
|
|
||||||
|
|
||||||
m_archiveWriter = new TarArchiveWriter(m_saveStream);
|
m_archiveWriter = new TarArchiveWriter(m_saveStream);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -216,7 +215,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
|
private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
|
m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
|
||||||
|
@ -540,7 +538,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
|
xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
|
protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
|
||||||
{
|
{
|
||||||
if (regionDir != string.Empty)
|
if (regionDir != string.Empty)
|
||||||
|
@ -560,8 +557,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
foreach (ILandObject lo in landObjects)
|
foreach (ILandObject lo in landObjects)
|
||||||
{
|
{
|
||||||
LandData landData = lo.LandData;
|
LandData landData = lo.LandData;
|
||||||
string landDataPath = String.Format("{0}{1}{2}.xml",
|
string landDataPath
|
||||||
regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString());
|
= String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData));
|
||||||
m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
|
m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +601,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
|
|
||||||
CloseArchive(String.Empty);
|
CloseArchive(String.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Closes the archive and notifies that we're done.
|
/// Closes the archive and notifies that we're done.
|
||||||
|
@ -629,6 +625,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
|
|
||||||
m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
|
m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -31,16 +31,19 @@ using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using log4net.Config;
|
using log4net.Config;
|
||||||
|
using Nini.Config;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenMetaverse.Assets;
|
using OpenMetaverse.Assets;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Framework.Serialization;
|
using OpenSim.Framework.Serialization;
|
||||||
using OpenSim.Framework.Serialization.External;
|
using OpenSim.Framework.Serialization.External;
|
||||||
|
using OpenSim.Region.CoreModules.World.Land;
|
||||||
using OpenSim.Region.CoreModules.World.Serialiser;
|
using OpenSim.Region.CoreModules.World.Serialiser;
|
||||||
using OpenSim.Region.CoreModules.World.Terrain;
|
using OpenSim.Region.CoreModules.World.Terrain;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
using OpenSim.Region.Framework.Scenes.Serialization;
|
using OpenSim.Region.Framework.Scenes.Serialization;
|
||||||
|
using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
|
||||||
using OpenSim.Tests.Common;
|
using OpenSim.Tests.Common;
|
||||||
using OpenSim.Tests.Common.Mock;
|
using OpenSim.Tests.Common.Mock;
|
||||||
using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
|
using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
|
||||||
|
@ -69,9 +72,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
{
|
{
|
||||||
base.SetUp();
|
base.SetUp();
|
||||||
|
|
||||||
// FIXME: Do something about this - relying on statics in unit tests causes trouble sooner or later
|
|
||||||
new SceneManager();
|
|
||||||
|
|
||||||
m_archiverModule = new ArchiverModule();
|
m_archiverModule = new ArchiverModule();
|
||||||
m_serialiserModule = new SerialiserModule();
|
m_serialiserModule = new SerialiserModule();
|
||||||
TerrainModule terrainModule = new TerrainModule();
|
TerrainModule terrainModule = new TerrainModule();
|
||||||
|
@ -127,6 +127,53 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
|
|
||||||
return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName };
|
return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid)
|
||||||
|
{
|
||||||
|
SceneObjectPart part1 = CreateSceneObjectPart1();
|
||||||
|
sog1 = new SceneObjectGroup(part1);
|
||||||
|
scene.AddNewSceneObject(sog1, false);
|
||||||
|
|
||||||
|
AssetNotecard nc = new AssetNotecard();
|
||||||
|
nc.BodyText = "Hello World!";
|
||||||
|
nc.Encode();
|
||||||
|
ncAssetUuid = UUID.Random();
|
||||||
|
UUID ncItemUuid = UUID.Random();
|
||||||
|
AssetBase ncAsset
|
||||||
|
= AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
|
||||||
|
m_scene.AssetService.Store(ncAsset);
|
||||||
|
|
||||||
|
TaskInventoryItem ncItem
|
||||||
|
= new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
|
||||||
|
SceneObjectPart part2 = CreateSceneObjectPart2();
|
||||||
|
sog2 = new SceneObjectGroup(part2);
|
||||||
|
part2.Inventory.AddInventoryItem(ncItem, true);
|
||||||
|
|
||||||
|
scene.AddNewSceneObject(sog2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid)
|
||||||
|
{
|
||||||
|
using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
|
||||||
|
{
|
||||||
|
using (BinaryReader br = new BinaryReader(resource))
|
||||||
|
{
|
||||||
|
// FIXME: Use the inspector instead
|
||||||
|
soundData = br.ReadBytes(99999999);
|
||||||
|
soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
|
||||||
|
string soundAssetFileName
|
||||||
|
= ArchiveConstants.ASSETS_PATH + soundUuid
|
||||||
|
+ ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
|
||||||
|
tar.WriteFile(soundAssetFileName, soundData);
|
||||||
|
|
||||||
|
/*
|
||||||
|
AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
|
||||||
|
scene.AssetService.Store(soundAsset);
|
||||||
|
asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test saving an OpenSim Region Archive.
|
/// Test saving an OpenSim Region Archive.
|
||||||
|
@ -204,30 +251,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
// TODO: Test presence of more files and contents of files.
|
// TODO: Test presence of more files and contents of files.
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid)
|
|
||||||
{
|
|
||||||
SceneObjectPart part1 = CreateSceneObjectPart1();
|
|
||||||
sog1 = new SceneObjectGroup(part1);
|
|
||||||
scene.AddNewSceneObject(sog1, false);
|
|
||||||
|
|
||||||
AssetNotecard nc = new AssetNotecard();
|
|
||||||
nc.BodyText = "Hello World!";
|
|
||||||
nc.Encode();
|
|
||||||
ncAssetUuid = UUID.Random();
|
|
||||||
UUID ncItemUuid = UUID.Random();
|
|
||||||
AssetBase ncAsset
|
|
||||||
= AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
|
|
||||||
m_scene.AssetService.Store(ncAsset);
|
|
||||||
|
|
||||||
TaskInventoryItem ncItem
|
|
||||||
= new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
|
|
||||||
SceneObjectPart part2 = CreateSceneObjectPart2();
|
|
||||||
sog2 = new SceneObjectGroup(part2);
|
|
||||||
part2.Inventory.AddInventoryItem(ncItem, true);
|
|
||||||
|
|
||||||
scene.AddNewSceneObject(sog2, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test saving an OpenSim Region Archive with the no assets option
|
/// Test saving an OpenSim Region Archive with the no assets option
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -308,59 +331,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
// TODO: Test presence of more files and contents of files.
|
// TODO: Test presence of more files and contents of files.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g.
|
|
||||||
/// 2 can come after 3).
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestLoadOarUnorderedParts()
|
|
||||||
{
|
|
||||||
TestHelpers.InMethod();
|
|
||||||
|
|
||||||
UUID ownerId = TestHelpers.ParseTail(0xaaaa);
|
|
||||||
|
|
||||||
MemoryStream archiveWriteStream = new MemoryStream();
|
|
||||||
TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
|
|
||||||
|
|
||||||
tar.WriteFile(
|
|
||||||
ArchiveConstants.CONTROL_FILE_PATH,
|
|
||||||
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
|
|
||||||
|
|
||||||
SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
|
|
||||||
SceneObjectPart sop2
|
|
||||||
= SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId);
|
|
||||||
SceneObjectPart sop3
|
|
||||||
= SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId);
|
|
||||||
|
|
||||||
// Add the parts so they will be written out in reverse order to the oar
|
|
||||||
sog1.AddPart(sop3);
|
|
||||||
sop3.LinkNum = 3;
|
|
||||||
sog1.AddPart(sop2);
|
|
||||||
sop2.LinkNum = 2;
|
|
||||||
|
|
||||||
tar.WriteFile(
|
|
||||||
ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition),
|
|
||||||
SceneObjectSerializer.ToXml2Format(sog1));
|
|
||||||
|
|
||||||
tar.Close();
|
|
||||||
|
|
||||||
MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
|
|
||||||
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
|
|
||||||
m_archiverModule.DearchiveRegion(archiveReadStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.That(m_lastErrorMessage, Is.Null);
|
|
||||||
|
|
||||||
SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2");
|
|
||||||
Assert.That(part2.LinkNum, Is.EqualTo(2));
|
|
||||||
|
|
||||||
SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3");
|
|
||||||
Assert.That(part3.LinkNum, Is.EqualTo(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test loading an OpenSim Region Archive.
|
/// Test loading an OpenSim Region Archive.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -435,50 +405,57 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
TestLoadedRegion(part1, soundItemName, soundData);
|
TestLoadedRegion(part1, soundItemName, soundData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid)
|
/// <summary>
|
||||||
|
/// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g.
|
||||||
|
/// 2 can come after 3).
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestLoadOarUnorderedParts()
|
||||||
{
|
{
|
||||||
using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
|
TestHelpers.InMethod();
|
||||||
|
|
||||||
|
UUID ownerId = TestHelpers.ParseTail(0xaaaa);
|
||||||
|
|
||||||
|
MemoryStream archiveWriteStream = new MemoryStream();
|
||||||
|
TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
|
||||||
|
|
||||||
|
tar.WriteFile(
|
||||||
|
ArchiveConstants.CONTROL_FILE_PATH,
|
||||||
|
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
|
||||||
|
|
||||||
|
SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
|
||||||
|
SceneObjectPart sop2
|
||||||
|
= SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId);
|
||||||
|
SceneObjectPart sop3
|
||||||
|
= SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId);
|
||||||
|
|
||||||
|
// Add the parts so they will be written out in reverse order to the oar
|
||||||
|
sog1.AddPart(sop3);
|
||||||
|
sop3.LinkNum = 3;
|
||||||
|
sog1.AddPart(sop2);
|
||||||
|
sop2.LinkNum = 2;
|
||||||
|
|
||||||
|
tar.WriteFile(
|
||||||
|
ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition),
|
||||||
|
SceneObjectSerializer.ToXml2Format(sog1));
|
||||||
|
|
||||||
|
tar.Close();
|
||||||
|
|
||||||
|
MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
|
||||||
|
|
||||||
|
lock (this)
|
||||||
{
|
{
|
||||||
using (BinaryReader br = new BinaryReader(resource))
|
m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
|
||||||
{
|
m_archiverModule.DearchiveRegion(archiveReadStream);
|
||||||
// FIXME: Use the inspector instead
|
|
||||||
soundData = br.ReadBytes(99999999);
|
|
||||||
soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
|
|
||||||
string soundAssetFileName
|
|
||||||
= ArchiveConstants.ASSETS_PATH + soundUuid
|
|
||||||
+ ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
|
|
||||||
tar.WriteFile(soundAssetFileName, soundData);
|
|
||||||
|
|
||||||
/*
|
|
||||||
AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
|
|
||||||
scene.AssetService.Store(soundAsset);
|
|
||||||
asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData)
|
Assert.That(m_lastErrorMessage, Is.Null);
|
||||||
{
|
|
||||||
SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
|
|
||||||
|
|
||||||
Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded");
|
SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2");
|
||||||
Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical");
|
Assert.That(part2.LinkNum, Is.EqualTo(2));
|
||||||
Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal");
|
|
||||||
Assert.That(
|
|
||||||
object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal");
|
|
||||||
Assert.That(
|
|
||||||
object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal");
|
|
||||||
Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation));
|
|
||||||
Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition));
|
|
||||||
|
|
||||||
TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0];
|
SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3");
|
||||||
Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null");
|
Assert.That(part3.LinkNum, Is.EqualTo(3));
|
||||||
AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString());
|
|
||||||
Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null");
|
|
||||||
Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match");
|
|
||||||
|
|
||||||
Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -538,8 +515,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
SerialiserModule serialiserModule = new SerialiserModule();
|
SerialiserModule serialiserModule = new SerialiserModule();
|
||||||
TerrainModule terrainModule = new TerrainModule();
|
TerrainModule terrainModule = new TerrainModule();
|
||||||
|
|
||||||
m_sceneHelpers = new SceneHelpers();
|
SceneHelpers m_sceneHelpers2 = new SceneHelpers();
|
||||||
TestScene scene2 = m_sceneHelpers.SetupScene();
|
TestScene scene2 = m_sceneHelpers2.SetupScene();
|
||||||
SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule);
|
SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule);
|
||||||
|
|
||||||
// Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is
|
// Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is
|
||||||
|
@ -562,6 +539,71 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test OAR loading where the land parcel is group deeded.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In this situation, the owner ID is set to the group ID.
|
||||||
|
/// </remarks>
|
||||||
|
[Test]
|
||||||
|
public void TestLoadOarDeededLand()
|
||||||
|
{
|
||||||
|
TestHelpers.InMethod();
|
||||||
|
// TestHelpers.EnableLogging();
|
||||||
|
|
||||||
|
UUID landID = TestHelpers.ParseTail(0x10);
|
||||||
|
|
||||||
|
MockGroupsServicesConnector groupsService = new MockGroupsServicesConnector();
|
||||||
|
|
||||||
|
IConfigSource configSource = new IniConfigSource();
|
||||||
|
IConfig config = configSource.AddConfig("Groups");
|
||||||
|
config.Set("Enabled", true);
|
||||||
|
config.Set("Module", "GroupsModule");
|
||||||
|
config.Set("DebugEnabled", true);
|
||||||
|
SceneHelpers.SetupSceneModules(
|
||||||
|
m_scene, configSource, new object[] { new GroupsModule(), groupsService, new LandManagementModule() });
|
||||||
|
|
||||||
|
// Create group in scene for loading
|
||||||
|
// FIXME: For now we'll put up with the issue that we'll get a group ID that varies across tests.
|
||||||
|
UUID groupID
|
||||||
|
= groupsService.CreateGroup(UUID.Zero, "group1", "", true, UUID.Zero, 3, true, true, true, UUID.Zero);
|
||||||
|
|
||||||
|
// Construct OAR
|
||||||
|
MemoryStream oarStream = new MemoryStream();
|
||||||
|
TarArchiveWriter tar = new TarArchiveWriter(oarStream);
|
||||||
|
|
||||||
|
tar.WriteDir(ArchiveConstants.LANDDATA_PATH);
|
||||||
|
tar.WriteFile(
|
||||||
|
ArchiveConstants.CONTROL_FILE_PATH,
|
||||||
|
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
|
||||||
|
|
||||||
|
LandObject lo = new LandObject(groupID, true, null);
|
||||||
|
lo.SetLandBitmap(lo.BasicFullRegionLandBitmap());
|
||||||
|
LandData ld = lo.LandData;
|
||||||
|
ld.GlobalID = landID;
|
||||||
|
|
||||||
|
string ldPath = ArchiveConstants.CreateOarLandDataPath(ld);
|
||||||
|
tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null));
|
||||||
|
tar.Close();
|
||||||
|
|
||||||
|
oarStream = new MemoryStream(oarStream.ToArray());
|
||||||
|
|
||||||
|
// Load OAR
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
|
||||||
|
m_archiverModule.DearchiveRegion(oarStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
ILandObject rLo = m_scene.LandChannel.GetLandObject(16, 16);
|
||||||
|
LandData rLd = rLo.LandData;
|
||||||
|
|
||||||
|
Assert.That(rLd.GlobalID, Is.EqualTo(landID));
|
||||||
|
Assert.That(rLd.OwnerID, Is.EqualTo(groupID));
|
||||||
|
Assert.That(rLd.GroupID, Is.EqualTo(groupID));
|
||||||
|
Assert.That(rLd.IsGroupOwned, Is.EqualTo(true));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test loading the region settings of an OpenSim Region Archive.
|
/// Test loading the region settings of an OpenSim Region Archive.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -781,9 +823,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Save OAR
|
// Save OAR
|
||||||
|
|
||||||
MemoryStream archiveWriteStream = new MemoryStream();
|
MemoryStream archiveWriteStream = new MemoryStream();
|
||||||
m_scene.EventManager.OnOarFileSaved += SaveCompleted;
|
m_scene.EventManager.OnOarFileSaved += SaveCompleted;
|
||||||
|
|
||||||
|
@ -800,7 +840,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
|
|
||||||
|
|
||||||
// Check that the OAR contains the expected data
|
// Check that the OAR contains the expected data
|
||||||
|
|
||||||
Assert.That(m_lastRequestId, Is.EqualTo(requestId));
|
Assert.That(m_lastRequestId, Is.EqualTo(requestId));
|
||||||
|
|
||||||
byte[] archive = archiveWriteStream.ToArray();
|
byte[] archive = archiveWriteStream.ToArray();
|
||||||
|
@ -892,7 +931,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
|
ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
|
||||||
SceneManager.Instance.ForEachScene(delegate(Scene scene)
|
m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene)
|
||||||
{
|
{
|
||||||
scenesGroup.AddScene(scene);
|
scenesGroup.AddScene(scene);
|
||||||
});
|
});
|
||||||
|
@ -950,13 +989,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
|
|
||||||
// Delete the current objects, to test that they're loaded from the OAR and didn't
|
// Delete the current objects, to test that they're loaded from the OAR and didn't
|
||||||
// just remain in the scene.
|
// just remain in the scene.
|
||||||
SceneManager.Instance.ForEachScene(delegate(Scene scene)
|
m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene)
|
||||||
{
|
{
|
||||||
scene.DeleteAllSceneObjects();
|
scene.DeleteAllSceneObjects();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a "hole", to test that that the corresponding region isn't loaded from the OAR
|
// Create a "hole", to test that that the corresponding region isn't loaded from the OAR
|
||||||
SceneManager.Instance.CloseScene(SceneManager.Instance.Scenes[1]);
|
m_sceneHelpers.SceneManager.CloseScene(SceneManager.Instance.Scenes[1]);
|
||||||
|
|
||||||
|
|
||||||
// Check thay the OAR file contains the expected data
|
// Check thay the OAR file contains the expected data
|
||||||
|
@ -971,10 +1010,32 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||||
|
|
||||||
Assert.That(m_lastErrorMessage, Is.Null);
|
Assert.That(m_lastErrorMessage, Is.Null);
|
||||||
|
|
||||||
Assert.AreEqual(3, SceneManager.Instance.Scenes.Count);
|
Assert.AreEqual(3, m_sceneHelpers.SceneManager.Scenes.Count);
|
||||||
|
|
||||||
TestLoadedRegion(part1, soundItemName, soundData);
|
TestLoadedRegion(part1, soundItemName, soundData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData)
|
||||||
|
{
|
||||||
|
SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
|
||||||
|
|
||||||
|
Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded");
|
||||||
|
Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical");
|
||||||
|
Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal");
|
||||||
|
Assert.That(
|
||||||
|
object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal");
|
||||||
|
Assert.That(
|
||||||
|
object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal");
|
||||||
|
Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation));
|
||||||
|
Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition));
|
||||||
|
|
||||||
|
TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0];
|
||||||
|
Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null");
|
||||||
|
AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString());
|
||||||
|
Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null");
|
||||||
|
Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match");
|
||||||
|
|
||||||
|
Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -53,6 +53,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
|
|
||||||
protected EstateManagementCommands m_commands;
|
protected EstateManagementCommands m_commands;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If false, region restart requests from the client are blocked even if they are otherwise legitimate.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowRegionRestartFromClient { get; set; }
|
||||||
|
|
||||||
private EstateTerrainXferHandler TerrainUploader;
|
private EstateTerrainXferHandler TerrainUploader;
|
||||||
public TelehubManager m_Telehub;
|
public TelehubManager m_Telehub;
|
||||||
|
|
||||||
|
@ -60,6 +65,53 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
public event ChangeDelegate OnEstateInfoChange;
|
public event ChangeDelegate OnEstateInfoChange;
|
||||||
public event MessageDelegate OnEstateMessage;
|
public event MessageDelegate OnEstateMessage;
|
||||||
|
|
||||||
|
#region Region Module interface
|
||||||
|
|
||||||
|
public string Name { get { return "EstateManagementModule"; } }
|
||||||
|
|
||||||
|
public Type ReplaceableInterface { get { return null; } }
|
||||||
|
|
||||||
|
public void Initialise(IConfigSource source)
|
||||||
|
{
|
||||||
|
AllowRegionRestartFromClient = true;
|
||||||
|
|
||||||
|
IConfig config = source.Configs["EstateManagement"];
|
||||||
|
|
||||||
|
if (config != null)
|
||||||
|
AllowRegionRestartFromClient = config.GetBoolean("AllowRegionRestartFromClient", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRegion(Scene scene)
|
||||||
|
{
|
||||||
|
Scene = scene;
|
||||||
|
Scene.RegisterModuleInterface<IEstateModule>(this);
|
||||||
|
Scene.EventManager.OnNewClient += EventManager_OnNewClient;
|
||||||
|
Scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight;
|
||||||
|
|
||||||
|
m_Telehub = new TelehubManager(scene);
|
||||||
|
|
||||||
|
m_commands = new EstateManagementCommands(this);
|
||||||
|
m_commands.Initialise();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveRegion(Scene scene) {}
|
||||||
|
|
||||||
|
public void RegionLoaded(Scene scene)
|
||||||
|
{
|
||||||
|
// Sets up the sun module based no the saved Estate and Region Settings
|
||||||
|
// DO NOT REMOVE or the sun will stop working
|
||||||
|
scene.TriggerEstateSunUpdate();
|
||||||
|
|
||||||
|
UserManager = scene.RequestModuleInterface<IUserManagement>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
m_commands.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Packet Data Responders
|
#region Packet Data Responders
|
||||||
|
|
||||||
private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice)
|
private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice)
|
||||||
|
@ -184,6 +236,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture;
|
Scene.RegionInfo.RegionSettings.TerrainTexture4 = texture;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene.RegionInfo.RegionSettings.Save();
|
Scene.RegionInfo.RegionSettings.Save();
|
||||||
TriggerRegionInfoChange();
|
TriggerRegionInfoChange();
|
||||||
sendRegionInfoPacketToAll();
|
sendRegionInfoPacketToAll();
|
||||||
|
@ -215,6 +268,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
Scene.RegionInfo.RegionSettings.Elevation2NE = highValue;
|
Scene.RegionInfo.RegionSettings.Elevation2NE = highValue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene.RegionInfo.RegionSettings.Save();
|
Scene.RegionInfo.RegionSettings.Save();
|
||||||
TriggerRegionInfoChange();
|
TriggerRegionInfoChange();
|
||||||
sendRegionHandshakeToAll();
|
sendRegionHandshakeToAll();
|
||||||
|
@ -255,6 +309,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
|
|
||||||
private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds)
|
private void handleEstateRestartSimRequest(IClientAPI remoteClient, int timeInSeconds)
|
||||||
{
|
{
|
||||||
|
if (!AllowRegionRestartFromClient)
|
||||||
|
{
|
||||||
|
remoteClient.SendAlertMessage("Region restart has been disabled on this simulator.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>();
|
IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>();
|
||||||
if (restartModule != null)
|
if (restartModule != null)
|
||||||
{
|
{
|
||||||
|
@ -271,6 +331,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
}
|
}
|
||||||
|
|
||||||
restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true);
|
restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true);
|
||||||
|
|
||||||
|
m_log.InfoFormat(
|
||||||
|
"User {0} requested restart of region {1} in {2} seconds",
|
||||||
|
remoteClient.Name, Scene.Name, times.Count != 0 ? times[0] : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +359,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
|
|
||||||
if ((estateAccessType & 4) != 0) // User add
|
if ((estateAccessType & 4) != 0) // User add
|
||||||
{
|
{
|
||||||
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || Scene.Permissions.BypassPermissions())
|
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true))
|
||||||
{
|
{
|
||||||
if ((estateAccessType & 1) != 0) // All estates
|
if ((estateAccessType & 1) != 0) // All estates
|
||||||
{
|
{
|
||||||
|
@ -325,9 +389,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((estateAccessType & 8) != 0) // User remove
|
if ((estateAccessType & 8) != 0) // User remove
|
||||||
{
|
{
|
||||||
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || Scene.Permissions.BypassPermissions())
|
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true))
|
||||||
{
|
{
|
||||||
if ((estateAccessType & 1) != 0) // All estates
|
if ((estateAccessType & 1) != 0) // All estates
|
||||||
{
|
{
|
||||||
|
@ -356,9 +421,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((estateAccessType & 16) != 0) // Group add
|
if ((estateAccessType & 16) != 0) // Group add
|
||||||
{
|
{
|
||||||
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || Scene.Permissions.BypassPermissions())
|
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true))
|
||||||
{
|
{
|
||||||
if ((estateAccessType & 1) != 0) // All estates
|
if ((estateAccessType & 1) != 0) // All estates
|
||||||
{
|
{
|
||||||
|
@ -387,9 +453,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((estateAccessType & 32) != 0) // Group remove
|
if ((estateAccessType & 32) != 0) // Group remove
|
||||||
{
|
{
|
||||||
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || Scene.Permissions.BypassPermissions())
|
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true))
|
||||||
{
|
{
|
||||||
if ((estateAccessType & 1) != 0) // All estates
|
if ((estateAccessType & 1) != 0) // All estates
|
||||||
{
|
{
|
||||||
|
@ -418,9 +485,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((estateAccessType & 64) != 0) // Ban add
|
if ((estateAccessType & 64) != 0) // Ban add
|
||||||
{
|
{
|
||||||
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || Scene.Permissions.BypassPermissions())
|
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false))
|
||||||
{
|
{
|
||||||
EstateBan[] banlistcheck = Scene.RegionInfo.EstateSettings.EstateBans;
|
EstateBan[] banlistcheck = Scene.RegionInfo.EstateSettings.EstateBans;
|
||||||
|
|
||||||
|
@ -495,9 +563,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((estateAccessType & 128) != 0) // Ban remove
|
if ((estateAccessType & 128) != 0) // Ban remove
|
||||||
{
|
{
|
||||||
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || Scene.Permissions.BypassPermissions())
|
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false))
|
||||||
{
|
{
|
||||||
EstateBan[] banlistcheck = Scene.RegionInfo.EstateSettings.EstateBans;
|
EstateBan[] banlistcheck = Scene.RegionInfo.EstateSettings.EstateBans;
|
||||||
|
|
||||||
|
@ -550,9 +619,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((estateAccessType & 256) != 0) // Manager add
|
if ((estateAccessType & 256) != 0) // Manager add
|
||||||
{
|
{
|
||||||
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || Scene.Permissions.BypassPermissions())
|
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true))
|
||||||
{
|
{
|
||||||
if ((estateAccessType & 1) != 0) // All estates
|
if ((estateAccessType & 1) != 0) // All estates
|
||||||
{
|
{
|
||||||
|
@ -581,9 +651,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
remote_client.SendAlertMessage("Method EstateAccessDelta Failed, you don't have permissions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((estateAccessType & 512) != 0) // Manager remove
|
if ((estateAccessType & 512) != 0) // Manager remove
|
||||||
{
|
{
|
||||||
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || Scene.Permissions.BypassPermissions())
|
if (Scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true))
|
||||||
{
|
{
|
||||||
if ((estateAccessType & 1) != 0) // All estates
|
if ((estateAccessType & 1) != 0) // All estates
|
||||||
{
|
{
|
||||||
|
@ -614,7 +685,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleOnEstateManageTelehub (IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
|
public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
|
||||||
{
|
{
|
||||||
SceneObjectPart part;
|
SceneObjectPart part;
|
||||||
|
|
||||||
|
@ -1072,45 +1143,6 @@ namespace OpenSim.Region.CoreModules.World.Estate
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Region Module interface
|
|
||||||
|
|
||||||
public string Name { get { return "EstateManagementModule"; } }
|
|
||||||
|
|
||||||
public Type ReplaceableInterface { get { return null; } }
|
|
||||||
|
|
||||||
public void Initialise(IConfigSource source) {}
|
|
||||||
|
|
||||||
public void AddRegion(Scene scene)
|
|
||||||
{
|
|
||||||
Scene = scene;
|
|
||||||
Scene.RegisterModuleInterface<IEstateModule>(this);
|
|
||||||
Scene.EventManager.OnNewClient += EventManager_OnNewClient;
|
|
||||||
Scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight;
|
|
||||||
|
|
||||||
m_Telehub = new TelehubManager(scene);
|
|
||||||
|
|
||||||
m_commands = new EstateManagementCommands(this);
|
|
||||||
m_commands.Initialise();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRegion(Scene scene) {}
|
|
||||||
|
|
||||||
public void RegionLoaded(Scene scene)
|
|
||||||
{
|
|
||||||
// Sets up the sun module based no the saved Estate and Region Settings
|
|
||||||
// DO NOT REMOVE or the sun will stop working
|
|
||||||
scene.TriggerEstateSunUpdate();
|
|
||||||
|
|
||||||
UserManager = scene.RequestModuleInterface<IUserManagement>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
m_commands.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Other Functions
|
#region Other Functions
|
||||||
|
|
||||||
public void changeWaterHeight(float height)
|
public void changeWaterHeight(float height)
|
||||||
|
|
|
@ -1378,10 +1378,11 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
|
|
||||||
public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
|
public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
|
||||||
{
|
{
|
||||||
|
// m_log.DebugFormat(
|
||||||
|
// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name);
|
||||||
|
|
||||||
for (int i = 0; i < data.Count; i++)
|
for (int i = 0; i < data.Count; i++)
|
||||||
{
|
|
||||||
IncomingLandObjectFromStorage(data[i]);
|
IncomingLandObjectFromStorage(data[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void IncomingLandObjectFromStorage(LandData data)
|
public void IncomingLandObjectFromStorage(LandData data)
|
||||||
|
|
|
@ -727,9 +727,10 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
int ty = min_y * 4;
|
int ty = min_y * 4;
|
||||||
if (ty > ((int)Constants.RegionSize - 1))
|
if (ty > ((int)Constants.RegionSize - 1))
|
||||||
ty = ((int)Constants.RegionSize - 1);
|
ty = ((int)Constants.RegionSize - 1);
|
||||||
|
|
||||||
LandData.AABBMin =
|
LandData.AABBMin =
|
||||||
new Vector3((float) (min_x * 4), (float) (min_y * 4),
|
new Vector3(
|
||||||
(float) m_scene.Heightmap[tx, ty]);
|
(float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
|
||||||
|
|
||||||
tx = max_x * 4;
|
tx = max_x * 4;
|
||||||
if (tx > ((int)Constants.RegionSize - 1))
|
if (tx > ((int)Constants.RegionSize - 1))
|
||||||
|
@ -737,9 +738,11 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
ty = max_y * 4;
|
ty = max_y * 4;
|
||||||
if (ty > ((int)Constants.RegionSize - 1))
|
if (ty > ((int)Constants.RegionSize - 1))
|
||||||
ty = ((int)Constants.RegionSize - 1);
|
ty = ((int)Constants.RegionSize - 1);
|
||||||
LandData.AABBMax =
|
|
||||||
new Vector3((float) (max_x * 4), (float) (max_y * 4),
|
LandData.AABBMax
|
||||||
(float) m_scene.Heightmap[tx, ty]);
|
= new Vector3(
|
||||||
|
(float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
|
||||||
|
|
||||||
LandData.Area = tempArea;
|
LandData.Area = tempArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.CoreModules.World.Land.Tests
|
namespace OpenSim.Region.CoreModules.World.Land.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class PrimCountModuleTests
|
public class PrimCountModuleTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000");
|
protected UUID m_userId = new UUID("00000000-0000-0000-0000-100000000000");
|
||||||
protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000");
|
protected UUID m_groupId = new UUID("00000000-0000-0000-8888-000000000000");
|
||||||
|
|
|
@ -44,7 +44,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests
|
namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class MoapTests
|
public class MoapTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
protected TestScene m_scene;
|
protected TestScene m_scene;
|
||||||
protected MoapModule m_module;
|
protected MoapModule m_module;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -264,7 +265,10 @@ namespace OpenSim.Region.CoreModules.World.Region
|
||||||
for (int i = 4 ; i < args.Length ; i++)
|
for (int i = 4 ; i < args.Length ; i++)
|
||||||
times.Add(Convert.ToInt32(args[i]));
|
times.Add(Convert.ToInt32(args[i]));
|
||||||
|
|
||||||
|
MainConsole.Instance.OutputFormat(
|
||||||
|
"Region {0} scheduled for restart in {1} seconds", m_Scene.Name, times.Sum());
|
||||||
|
|
||||||
ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice);
|
ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -39,7 +39,7 @@ using OpenSim.Tests.Common;
|
||||||
namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
|
namespace OpenSim.Region.CoreModules.World.Serialiser.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SerialiserTests
|
public class SerialiserTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private string xml = @"
|
private string xml = @"
|
||||||
<SceneObjectGroup>
|
<SceneObjectGroup>
|
||||||
|
|
|
@ -43,8 +43,8 @@ namespace OpenSim.Region.CoreModules.World.Sound
|
||||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")]
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")]
|
||||||
public class SoundModule : INonSharedRegionModule, ISoundModule
|
public class SoundModule : INonSharedRegionModule, ISoundModule
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(
|
// private static readonly ILog m_log = LogManager.GetLogger(
|
||||||
MethodBase.GetCurrentMethod().DeclaringType);
|
// MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private Scene m_scene;
|
private Scene m_scene;
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,12 @@ using NUnit.Framework;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
|
using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
|
||||||
namespace OpenSim.Region.CoreModules.World.Terrain.Tests
|
namespace OpenSim.Region.CoreModules.World.Terrain.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TerrainTest
|
public class TerrainTest : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void BrushTest()
|
public void BrushTest()
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules
|
||||||
public void Initialise(IConfigSource config)
|
public void Initialise(IConfigSource config)
|
||||||
{
|
{
|
||||||
m_windConfig = config.Configs["Wind"];
|
m_windConfig = config.Configs["Wind"];
|
||||||
string desiredWindPlugin = m_dWindPluginName;
|
// string desiredWindPlugin = m_dWindPluginName;
|
||||||
|
|
||||||
if (m_windConfig != null)
|
if (m_windConfig != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -740,7 +740,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
//
|
//
|
||||||
// Out of memory
|
// Out of memory
|
||||||
// Operating system has killed the plugin
|
// Operating system has killed the plugin
|
||||||
m_sceneGraph.UnRecoverableError += RestartNow;
|
m_sceneGraph.UnRecoverableError
|
||||||
|
+= () =>
|
||||||
|
{
|
||||||
|
m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
|
||||||
|
RestartNow();
|
||||||
|
};
|
||||||
|
|
||||||
RegisterDefaultSceneEvents();
|
RegisterDefaultSceneEvents();
|
||||||
|
|
||||||
|
@ -1134,16 +1139,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.Error("[REGION]: Closing");
|
m_log.InfoFormat("[REGION]: Restarting region {0}", Name);
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
if (PhysicsScene != null)
|
|
||||||
{
|
|
||||||
PhysicsScene.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.Error("[REGION]: Firing Region Restart Message");
|
|
||||||
|
|
||||||
base.Restart();
|
base.Restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,23 +100,25 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<Scene> m_localScenes = new List<Scene>();
|
private readonly List<Scene> m_localScenes = new List<Scene>();
|
||||||
private Scene m_currentScene = null;
|
|
||||||
|
|
||||||
public List<Scene> Scenes
|
public List<Scene> Scenes
|
||||||
{
|
{
|
||||||
get { return new List<Scene>(m_localScenes); }
|
get { return new List<Scene>(m_localScenes); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Scene CurrentScene
|
/// <summary>
|
||||||
{
|
/// Scene selected from the console.
|
||||||
get { return m_currentScene; }
|
/// </summary>
|
||||||
}
|
/// <value>
|
||||||
|
/// If null, then all scenes are considered selected (signalled as "Root" on the console).
|
||||||
|
/// </value>
|
||||||
|
public Scene CurrentScene { get; private set; }
|
||||||
|
|
||||||
public Scene CurrentOrFirstScene
|
public Scene CurrentOrFirstScene
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_currentScene == null)
|
if (CurrentScene == null)
|
||||||
{
|
{
|
||||||
lock (m_localScenes)
|
lock (m_localScenes)
|
||||||
{
|
{
|
||||||
|
@ -128,7 +130,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return m_currentScene;
|
return CurrentScene;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,6 +143,13 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
|
lock (m_localScenes)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_localScenes.Count; i++)
|
||||||
|
{
|
||||||
|
m_localScenes[i].Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close(Scene cscene)
|
public void Close(Scene cscene)
|
||||||
|
@ -171,8 +180,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
public void HandleRestart(RegionInfo rdata)
|
public void HandleRestart(RegionInfo rdata)
|
||||||
{
|
{
|
||||||
m_log.Error("[SCENEMANAGER]: Got Restart message for region:" + rdata.RegionName + " Sending up to main");
|
Scene restartedScene = null;
|
||||||
int RegionSceneElement = -1;
|
|
||||||
|
|
||||||
lock (m_localScenes)
|
lock (m_localScenes)
|
||||||
{
|
{
|
||||||
|
@ -180,19 +188,18 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
if (rdata.RegionName == m_localScenes[i].RegionInfo.RegionName)
|
if (rdata.RegionName == m_localScenes[i].RegionInfo.RegionName)
|
||||||
{
|
{
|
||||||
RegionSceneElement = i;
|
restartedScene = m_localScenes[i];
|
||||||
|
m_localScenes.RemoveAt(i);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we make sure the region is no longer known about by the SceneManager
|
|
||||||
// Prevents duplicates.
|
|
||||||
|
|
||||||
if (RegionSceneElement >= 0)
|
|
||||||
{
|
|
||||||
m_localScenes.RemoveAt(RegionSceneElement);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the currently selected scene has been restarted, then we can't reselect here since we the scene
|
||||||
|
// hasn't yet been recreated. We will have to leave this to the caller.
|
||||||
|
if (CurrentScene == restartedScene)
|
||||||
|
CurrentScene = null;
|
||||||
|
|
||||||
// Send signal to main that we're restarting this sim.
|
// Send signal to main that we're restarting this sim.
|
||||||
OnRestartSim(rdata);
|
OnRestartSim(rdata);
|
||||||
}
|
}
|
||||||
|
@ -334,14 +341,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
private void ForEachCurrentScene(Action<Scene> func)
|
private void ForEachCurrentScene(Action<Scene> func)
|
||||||
{
|
{
|
||||||
if (m_currentScene == null)
|
if (CurrentScene == null)
|
||||||
{
|
{
|
||||||
lock (m_localScenes)
|
lock (m_localScenes)
|
||||||
m_localScenes.ForEach(func);
|
m_localScenes.ForEach(func);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
func(m_currentScene);
|
func(CurrentScene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +368,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|| (String.Compare(regionName, "..") == 0)
|
|| (String.Compare(regionName, "..") == 0)
|
||||||
|| (String.Compare(regionName, "/") == 0))
|
|| (String.Compare(regionName, "/") == 0))
|
||||||
{
|
{
|
||||||
m_currentScene = null;
|
CurrentScene = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -372,7 +379,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
if (String.Compare(scene.RegionInfo.RegionName, regionName, true) == 0)
|
if (String.Compare(scene.RegionInfo.RegionName, regionName, true) == 0)
|
||||||
{
|
{
|
||||||
m_currentScene = scene;
|
CurrentScene = scene;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,7 +399,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
if (scene.RegionInfo.RegionID == regionID)
|
if (scene.RegionInfo.RegionID == regionID)
|
||||||
{
|
{
|
||||||
m_currentScene = scene;
|
CurrentScene = scene;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1698,8 +1698,16 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}",
|
// "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}",
|
||||||
// Name, pos, m_scene.RegionInfo.RegionName);
|
// Name, pos, m_scene.RegionInfo.RegionName);
|
||||||
|
|
||||||
if (pos.X < 0 || pos.X >= Constants.RegionSize
|
// Allow move to another sub-region within a megaregion
|
||||||
|| pos.Y < 0 || pos.Y >= Constants.RegionSize
|
Vector2 regionSize;
|
||||||
|
IRegionCombinerModule regionCombinerModule = m_scene.RequestModuleInterface<IRegionCombinerModule>();
|
||||||
|
if (regionCombinerModule != null)
|
||||||
|
regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
|
||||||
|
else
|
||||||
|
regionSize = new Vector2(Constants.RegionSize);
|
||||||
|
|
||||||
|
if (pos.X < 0 || pos.X >= regionSize.X
|
||||||
|
|| pos.Y < 0 || pos.Y >= regionSize.Y
|
||||||
|| pos.Z < 0)
|
|| pos.Z < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1713,7 +1721,16 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// pos.Z = AbsolutePosition.Z;
|
// pos.Z = AbsolutePosition.Z;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
float terrainHeight = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
|
// Get terrain height for sub-region in a megaregion if necessary
|
||||||
|
int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X);
|
||||||
|
int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y);
|
||||||
|
UUID target_regionID = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y).RegionID;
|
||||||
|
Scene targetScene = m_scene;
|
||||||
|
|
||||||
|
if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
|
||||||
|
targetScene = m_scene;
|
||||||
|
|
||||||
|
float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % Constants.RegionSize), (int)(pos.Y % Constants.RegionSize)];
|
||||||
pos.Z = Math.Max(terrainHeight, pos.Z);
|
pos.Z = Math.Max(terrainHeight, pos.Z);
|
||||||
|
|
||||||
// Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is
|
// Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is
|
||||||
|
|
|
@ -37,7 +37,7 @@ using OpenSim.Tests.Common;
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BorderTests
|
public class BorderTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCross()
|
public void TestCross()
|
||||||
|
|
|
@ -41,7 +41,7 @@ using OpenSim.Tests.Common;
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
[TestFixture, LongRunning]
|
[TestFixture, LongRunning]
|
||||||
public class EntityManagerTests
|
public class EntityManagerTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
static public Random random;
|
static public Random random;
|
||||||
SceneObjectGroup found;
|
SceneObjectGroup found;
|
||||||
|
|
|
@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SceneGraphTests
|
public class SceneGraphTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDuplicateObject()
|
public void TestDuplicateObject()
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Communications;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
using OpenSim.Tests.Common.Mock;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class SceneManagerTests : OpenSimTestCase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestClose()
|
||||||
|
{
|
||||||
|
TestHelpers.InMethod();
|
||||||
|
|
||||||
|
SceneHelpers sh = new SceneHelpers();
|
||||||
|
Scene scene = sh.SetupScene();
|
||||||
|
|
||||||
|
sh.SceneManager.Close();
|
||||||
|
Assert.That(scene.ShuttingDown, Is.True);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Nini.Config;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
@ -182,6 +183,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test deleting an object from a scene.
|
/// Test deleting an object from a scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is the most basic form of delete. For all more sophisticated forms of derez (done asynchrnously
|
||||||
|
/// and where object can be taken to user inventory, etc.), see SceneObjectDeRezTests.
|
||||||
|
/// </remarks>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDeleteSceneObject()
|
public void TestDeleteSceneObject()
|
||||||
{
|
{
|
||||||
|
@ -200,100 +205,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
Assert.That(retrievedPart, Is.Null);
|
Assert.That(retrievedPart, Is.Null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test deleting an object asynchronously
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestDeleteSceneObjectAsync()
|
|
||||||
{
|
|
||||||
TestHelpers.InMethod();
|
|
||||||
//log4net.Config.XmlConfigurator.Configure();
|
|
||||||
|
|
||||||
UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001");
|
|
||||||
|
|
||||||
TestScene scene = new SceneHelpers().SetupScene();
|
|
||||||
|
|
||||||
// Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
|
|
||||||
AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
|
|
||||||
sogd.Enabled = false;
|
|
||||||
|
|
||||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene);
|
|
||||||
|
|
||||||
IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient;
|
|
||||||
scene.DeRezObjects(client, new System.Collections.Generic.List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero);
|
|
||||||
|
|
||||||
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
|
|
||||||
|
|
||||||
Assert.That(retrievedPart, Is.Not.Null);
|
|
||||||
|
|
||||||
Assert.That(so.IsDeleted, Is.False);
|
|
||||||
|
|
||||||
sogd.InventoryDeQueueAndDelete();
|
|
||||||
|
|
||||||
Assert.That(so.IsDeleted, Is.True);
|
|
||||||
|
|
||||||
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
|
|
||||||
Assert.That(retrievedPart2, Is.Null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test deleting an object asynchronously to user inventory.
|
|
||||||
/// </summary>
|
|
||||||
// [Test]
|
|
||||||
public void TestDeleteSceneObjectAsyncToUserInventory()
|
|
||||||
{
|
|
||||||
TestHelpers.InMethod();
|
|
||||||
TestHelpers.EnableLogging();
|
|
||||||
|
|
||||||
UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001");
|
|
||||||
string myObjectName = "Fred";
|
|
||||||
|
|
||||||
TestScene scene = new SceneHelpers().SetupScene();
|
|
||||||
|
|
||||||
// Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
|
|
||||||
AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
|
|
||||||
sogd.Enabled = false;
|
|
||||||
|
|
||||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId);
|
|
||||||
|
|
||||||
// Assert.That(
|
|
||||||
// scene.CommsManager.UserAdminService.AddUser(
|
|
||||||
// "Bob", "Hoskins", "test", "test@test.com", 1000, 1000, agentId),
|
|
||||||
// Is.EqualTo(agentId));
|
|
||||||
|
|
||||||
UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId);
|
|
||||||
InventoryFolderBase folder1
|
|
||||||
= UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1");
|
|
||||||
|
|
||||||
IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient;
|
|
||||||
scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID);
|
|
||||||
|
|
||||||
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
|
|
||||||
|
|
||||||
Assert.That(retrievedPart, Is.Not.Null);
|
|
||||||
Assert.That(so.IsDeleted, Is.False);
|
|
||||||
|
|
||||||
sogd.InventoryDeQueueAndDelete();
|
|
||||||
|
|
||||||
Assert.That(so.IsDeleted, Is.True);
|
|
||||||
|
|
||||||
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
|
|
||||||
Assert.That(retrievedPart2, Is.Null);
|
|
||||||
|
|
||||||
// SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client);
|
|
||||||
|
|
||||||
InventoryItemBase retrievedItem
|
|
||||||
= UserInventoryHelpers.GetInventoryItem(
|
|
||||||
scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName);
|
|
||||||
|
|
||||||
// Check that we now have the taken part in our inventory
|
|
||||||
Assert.That(retrievedItem, Is.Not.Null);
|
|
||||||
|
|
||||||
// Check that the taken part has actually disappeared
|
|
||||||
// SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
|
|
||||||
// Assert.That(retrievedPart, Is.Null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not
|
/// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not
|
||||||
/// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by
|
/// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by
|
||||||
|
@ -329,4 +240,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
Assert.That(sog.Parts.Length, Is.EqualTo(2));
|
Assert.That(sog.Parts.Length, Is.EqualTo(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -33,22 +33,24 @@ using NUnit.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Framework.Communications;
|
using OpenSim.Framework.Communications;
|
||||||
|
using OpenSim.Region.CoreModules.Framework.InventoryAccess;
|
||||||
using OpenSim.Region.CoreModules.World.Permissions;
|
using OpenSim.Region.CoreModules.World.Permissions;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
using OpenSim.Tests.Common;
|
using OpenSim.Tests.Common;
|
||||||
using OpenSim.Tests.Common.Mock;
|
using OpenSim.Tests.Common.Mock;
|
||||||
|
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests derez of scene objects by users.
|
/// Tests derez of scene objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This is at a level above the SceneObjectBasicTests, which act on the scene directly.
|
/// This is at a level above the SceneObjectBasicTests, which act on the scene directly.
|
||||||
/// TODO: These tests are very incomplete - they only test for a few conditions.
|
/// TODO: These tests are incomplete - need to test more kinds of derez (e.g. return object).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SceneObjectDeRezTests
|
public class SceneObjectDeRezTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test deleting an object from a scene.
|
/// Test deleting an object from a scene.
|
||||||
|
@ -76,14 +78,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
= new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero);
|
= new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero);
|
||||||
part.Name = "obj1";
|
part.Name = "obj1";
|
||||||
scene.AddNewSceneObject(new SceneObjectGroup(part), false);
|
scene.AddNewSceneObject(new SceneObjectGroup(part), false);
|
||||||
|
|
||||||
List<uint> localIds = new List<uint>();
|
List<uint> localIds = new List<uint>();
|
||||||
localIds.Add(part.LocalId);
|
localIds.Add(part.LocalId);
|
||||||
|
|
||||||
scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero);
|
scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero);
|
||||||
|
|
||||||
|
// Check that object isn't deleted until we crank the sogd handle.
|
||||||
|
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
|
||||||
|
Assert.That(retrievedPart, Is.Not.Null);
|
||||||
|
Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
|
||||||
|
|
||||||
sogd.InventoryDeQueueAndDelete();
|
sogd.InventoryDeQueueAndDelete();
|
||||||
|
|
||||||
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
|
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId);
|
||||||
Assert.That(retrievedPart, Is.Null);
|
Assert.That(retrievedPart2, Is.Null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -124,6 +132,67 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
// Object should still be in the scene.
|
// Object should still be in the scene.
|
||||||
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
|
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
|
||||||
Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID));
|
Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test deleting an object asynchronously to user inventory.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestDeleteSceneObjectAsyncToUserInventory()
|
||||||
|
{
|
||||||
|
TestHelpers.InMethod();
|
||||||
|
// TestHelpers.EnableLogging();
|
||||||
|
|
||||||
|
UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001");
|
||||||
|
string myObjectName = "Fred";
|
||||||
|
|
||||||
|
TestScene scene = new SceneHelpers().SetupScene();
|
||||||
|
|
||||||
|
IConfigSource configSource = new IniConfigSource();
|
||||||
|
IConfig config = configSource.AddConfig("Modules");
|
||||||
|
config.Set("InventoryAccessModule", "BasicInventoryAccessModule");
|
||||||
|
SceneHelpers.SetupSceneModules(
|
||||||
|
scene, configSource, new object[] { new BasicInventoryAccessModule() });
|
||||||
|
|
||||||
|
SceneHelpers.SetupSceneModules(scene, new object[] { });
|
||||||
|
|
||||||
|
// Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
|
||||||
|
AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
|
||||||
|
sogd.Enabled = false;
|
||||||
|
|
||||||
|
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, myObjectName, agentId);
|
||||||
|
|
||||||
|
UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId);
|
||||||
|
InventoryFolderBase folder1
|
||||||
|
= UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1");
|
||||||
|
|
||||||
|
IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient;
|
||||||
|
scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID);
|
||||||
|
|
||||||
|
SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
|
||||||
|
|
||||||
|
Assert.That(retrievedPart, Is.Not.Null);
|
||||||
|
Assert.That(so.IsDeleted, Is.False);
|
||||||
|
|
||||||
|
sogd.InventoryDeQueueAndDelete();
|
||||||
|
|
||||||
|
Assert.That(so.IsDeleted, Is.True);
|
||||||
|
|
||||||
|
SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
|
||||||
|
Assert.That(retrievedPart2, Is.Null);
|
||||||
|
|
||||||
|
// SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client);
|
||||||
|
|
||||||
|
InventoryItemBase retrievedItem
|
||||||
|
= UserInventoryHelpers.GetInventoryItem(
|
||||||
|
scene.InventoryService, ua.PrincipalID, "folder1/" + myObjectName);
|
||||||
|
|
||||||
|
// Check that we now have the taken part in our inventory
|
||||||
|
Assert.That(retrievedItem, Is.Not.Null);
|
||||||
|
|
||||||
|
// Check that the taken part has actually disappeared
|
||||||
|
// SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
|
||||||
|
// Assert.That(retrievedPart, Is.Null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,7 +40,7 @@ using log4net;
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SceneObjectLinkingTests
|
public class SceneObjectLinkingTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
/// Basic scene object resize tests
|
/// Basic scene object resize tests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SceneObjectResizeTests
|
public class SceneObjectResizeTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test resizing an object
|
/// Test resizing an object
|
||||||
|
|
|
@ -40,7 +40,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SceneObjectScriptTests
|
public class SceneObjectScriptTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAddScript()
|
public void TestAddScript()
|
||||||
|
|
|
@ -42,14 +42,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
/// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.)
|
/// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SceneObjectSpatialTests
|
public class SceneObjectSpatialTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
TestScene m_scene;
|
TestScene m_scene;
|
||||||
UUID m_ownerId = TestHelpers.ParseTail(0x1);
|
UUID m_ownerId = TestHelpers.ParseTail(0x1);
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
m_scene = new SceneHelpers().SetupScene();
|
m_scene = new SceneHelpers().SetupScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
/// Basic scene object status tests
|
/// Basic scene object status tests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SceneObjectStatusTests
|
public class SceneObjectStatusTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private TestScene m_scene;
|
private TestScene m_scene;
|
||||||
private UUID m_ownerId = TestHelpers.ParseTail(0x1);
|
private UUID m_ownerId = TestHelpers.ParseTail(0x1);
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
/// Scene presence animation tests
|
/// Scene presence animation tests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ScenePresenceAnimationTests
|
public class ScenePresenceAnimationTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestFlyingAnimation()
|
public void TestFlyingAnimation()
|
||||||
|
|
|
@ -42,7 +42,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ScenePresenceAutopilotTests
|
public class ScenePresenceAutopilotTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private TestScene m_scene;
|
private TestScene m_scene;
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ using System.Threading;
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ScenePresenceSitTests
|
public class ScenePresenceSitTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private TestScene m_scene;
|
private TestScene m_scene;
|
||||||
private ScenePresence m_sp;
|
private ScenePresence m_sp;
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
/// Teleport tests in a standalone OpenSim
|
/// Teleport tests in a standalone OpenSim
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ScenePresenceTeleportTests
|
public class ScenePresenceTeleportTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[TestFixtureSetUp]
|
[TestFixtureSetUp]
|
||||||
public void FixtureInit()
|
public void FixtureInit()
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
/// Scene presence tests
|
/// Scene presence tests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class SceneTests
|
public class SceneTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Very basic scene update test. Should become more elaborate with time.
|
/// Very basic scene update test. Should become more elaborate with time.
|
||||||
|
|
|
@ -50,7 +50,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.Framework.Tests
|
namespace OpenSim.Region.Framework.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TaskInventoryTests
|
public class TaskInventoryTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAddTaskInventoryItem()
|
public void TestAddTaskInventoryItem()
|
||||||
|
|
|
@ -38,7 +38,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class UuidGathererTests
|
public class UuidGathererTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
protected IAssetService m_assetService;
|
protected IAssetService m_assetService;
|
||||||
protected UuidGatherer m_uuidGatherer;
|
protected UuidGatherer m_uuidGatherer;
|
||||||
|
|
|
@ -36,7 +36,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
{
|
{
|
||||||
UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID);
|
UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID);
|
||||||
void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish);
|
void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the group record.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <param name='RequestingAgentID'>The UUID of the user making the request.</param>
|
||||||
|
/// <param name='GroupID'>
|
||||||
|
/// The ID of the record to retrieve.
|
||||||
|
/// GroupName may be specified instead, in which case this parameter will be UUID.Zero
|
||||||
|
/// </param>
|
||||||
|
/// <param name='GroupName'>
|
||||||
|
/// The name of the group to retrieve.
|
||||||
|
/// GroupID may be specified instead, in which case this parmeter will be null.
|
||||||
|
/// </param>
|
||||||
GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName);
|
GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName);
|
||||||
|
|
||||||
List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search);
|
List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search);
|
||||||
List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID);
|
List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID);
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests
|
||||||
/// Basic groups module tests
|
/// Basic groups module tests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class GroupsModuleTests
|
public class GroupsModuleTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBasic()
|
public void TestBasic()
|
||||||
|
|
|
@ -54,13 +54,62 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
private bool m_debugEnabled = false;
|
private bool m_debugEnabled = false;
|
||||||
|
|
||||||
public const GroupPowers m_DefaultEveryonePowers = GroupPowers.AllowSetHome |
|
public const GroupPowers DefaultEveryonePowers
|
||||||
GroupPowers.Accountable |
|
= GroupPowers.AllowSetHome
|
||||||
GroupPowers.JoinChat |
|
| GroupPowers.Accountable
|
||||||
GroupPowers.AllowVoiceChat |
|
| GroupPowers.JoinChat
|
||||||
GroupPowers.ReceiveNotices |
|
| GroupPowers.AllowVoiceChat
|
||||||
GroupPowers.StartProposal |
|
| GroupPowers.ReceiveNotices
|
||||||
GroupPowers.VoteOnProposal;
|
| GroupPowers.StartProposal
|
||||||
|
| GroupPowers.VoteOnProposal;
|
||||||
|
|
||||||
|
// Would this be cleaner as (GroupPowers)ulong.MaxValue?
|
||||||
|
public const GroupPowers DefaultOwnerPowers
|
||||||
|
= GroupPowers.Accountable
|
||||||
|
| GroupPowers.AllowEditLand
|
||||||
|
| GroupPowers.AllowFly
|
||||||
|
| GroupPowers.AllowLandmark
|
||||||
|
| GroupPowers.AllowRez
|
||||||
|
| GroupPowers.AllowSetHome
|
||||||
|
| GroupPowers.AllowVoiceChat
|
||||||
|
| GroupPowers.AssignMember
|
||||||
|
| GroupPowers.AssignMemberLimited
|
||||||
|
| GroupPowers.ChangeActions
|
||||||
|
| GroupPowers.ChangeIdentity
|
||||||
|
| GroupPowers.ChangeMedia
|
||||||
|
| GroupPowers.ChangeOptions
|
||||||
|
| GroupPowers.CreateRole
|
||||||
|
| GroupPowers.DeedObject
|
||||||
|
| GroupPowers.DeleteRole
|
||||||
|
| GroupPowers.Eject
|
||||||
|
| GroupPowers.FindPlaces
|
||||||
|
| GroupPowers.Invite
|
||||||
|
| GroupPowers.JoinChat
|
||||||
|
| GroupPowers.LandChangeIdentity
|
||||||
|
| GroupPowers.LandDeed
|
||||||
|
| GroupPowers.LandDivideJoin
|
||||||
|
| GroupPowers.LandEdit
|
||||||
|
| GroupPowers.LandEjectAndFreeze
|
||||||
|
| GroupPowers.LandGardening
|
||||||
|
| GroupPowers.LandManageAllowed
|
||||||
|
| GroupPowers.LandManageBanned
|
||||||
|
| GroupPowers.LandManagePasses
|
||||||
|
| GroupPowers.LandOptions
|
||||||
|
| GroupPowers.LandRelease
|
||||||
|
| GroupPowers.LandSetSale
|
||||||
|
| GroupPowers.ModerateChat
|
||||||
|
| GroupPowers.ObjectManipulate
|
||||||
|
| GroupPowers.ObjectSetForSale
|
||||||
|
| GroupPowers.ReceiveNotices
|
||||||
|
| GroupPowers.RemoveMember
|
||||||
|
| GroupPowers.ReturnGroupOwned
|
||||||
|
| GroupPowers.ReturnGroupSet
|
||||||
|
| GroupPowers.ReturnNonGroup
|
||||||
|
| GroupPowers.RoleProperties
|
||||||
|
| GroupPowers.SendNotices
|
||||||
|
| GroupPowers.SetLandingPoint
|
||||||
|
| GroupPowers.StartProposal
|
||||||
|
| GroupPowers.VoteOnProposal;
|
||||||
|
|
||||||
private bool m_connectorEnabled = false;
|
private bool m_connectorEnabled = false;
|
||||||
|
|
||||||
|
@ -219,59 +268,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
param["AllowPublish"] = allowPublish == true ? 1 : 0;
|
param["AllowPublish"] = allowPublish == true ? 1 : 0;
|
||||||
param["MaturePublish"] = maturePublish == true ? 1 : 0;
|
param["MaturePublish"] = maturePublish == true ? 1 : 0;
|
||||||
param["FounderID"] = founderID.ToString();
|
param["FounderID"] = founderID.ToString();
|
||||||
param["EveryonePowers"] = ((ulong)m_DefaultEveryonePowers).ToString();
|
param["EveryonePowers"] = ((ulong)DefaultEveryonePowers).ToString();
|
||||||
param["OwnerRoleID"] = OwnerRoleID.ToString();
|
param["OwnerRoleID"] = OwnerRoleID.ToString();
|
||||||
|
param["OwnersPowers"] = ((ulong)DefaultOwnerPowers).ToString();
|
||||||
// Would this be cleaner as (GroupPowers)ulong.MaxValue;
|
|
||||||
GroupPowers OwnerPowers = GroupPowers.Accountable
|
|
||||||
| GroupPowers.AllowEditLand
|
|
||||||
| GroupPowers.AllowFly
|
|
||||||
| GroupPowers.AllowLandmark
|
|
||||||
| GroupPowers.AllowRez
|
|
||||||
| GroupPowers.AllowSetHome
|
|
||||||
| GroupPowers.AllowVoiceChat
|
|
||||||
| GroupPowers.AssignMember
|
|
||||||
| GroupPowers.AssignMemberLimited
|
|
||||||
| GroupPowers.ChangeActions
|
|
||||||
| GroupPowers.ChangeIdentity
|
|
||||||
| GroupPowers.ChangeMedia
|
|
||||||
| GroupPowers.ChangeOptions
|
|
||||||
| GroupPowers.CreateRole
|
|
||||||
| GroupPowers.DeedObject
|
|
||||||
| GroupPowers.DeleteRole
|
|
||||||
| GroupPowers.Eject
|
|
||||||
| GroupPowers.FindPlaces
|
|
||||||
| GroupPowers.Invite
|
|
||||||
| GroupPowers.JoinChat
|
|
||||||
| GroupPowers.LandChangeIdentity
|
|
||||||
| GroupPowers.LandDeed
|
|
||||||
| GroupPowers.LandDivideJoin
|
|
||||||
| GroupPowers.LandEdit
|
|
||||||
| GroupPowers.LandEjectAndFreeze
|
|
||||||
| GroupPowers.LandGardening
|
|
||||||
| GroupPowers.LandManageAllowed
|
|
||||||
| GroupPowers.LandManageBanned
|
|
||||||
| GroupPowers.LandManagePasses
|
|
||||||
| GroupPowers.LandOptions
|
|
||||||
| GroupPowers.LandRelease
|
|
||||||
| GroupPowers.LandSetSale
|
|
||||||
| GroupPowers.ModerateChat
|
|
||||||
| GroupPowers.ObjectManipulate
|
|
||||||
| GroupPowers.ObjectSetForSale
|
|
||||||
| GroupPowers.ReceiveNotices
|
|
||||||
| GroupPowers.RemoveMember
|
|
||||||
| GroupPowers.ReturnGroupOwned
|
|
||||||
| GroupPowers.ReturnGroupSet
|
|
||||||
| GroupPowers.ReturnNonGroup
|
|
||||||
| GroupPowers.RoleProperties
|
|
||||||
| GroupPowers.SendNotices
|
|
||||||
| GroupPowers.SetLandingPoint
|
|
||||||
| GroupPowers.StartProposal
|
|
||||||
| GroupPowers.VoteOnProposal;
|
|
||||||
param["OwnersPowers"] = ((ulong)OwnerPowers).ToString();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param);
|
Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param);
|
||||||
|
|
||||||
|
@ -612,8 +611,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
return Roles;
|
return Roles;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID)
|
public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID)
|
||||||
|
@ -676,7 +673,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
return members;
|
return members;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID)
|
public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID)
|
||||||
|
@ -727,9 +723,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
values.Add(data);
|
values.Add(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values;
|
|
||||||
|
|
||||||
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID)
|
public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID)
|
||||||
{
|
{
|
||||||
Hashtable param = new Hashtable();
|
Hashtable param = new Hashtable();
|
||||||
|
@ -737,7 +734,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param);
|
Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param);
|
||||||
|
|
||||||
|
|
||||||
if (respData.Contains("error"))
|
if (respData.Contains("error"))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -761,6 +757,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket)
|
public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket)
|
||||||
{
|
{
|
||||||
string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, "");
|
string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, "");
|
||||||
|
@ -777,8 +774,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||||
XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param);
|
XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region GroupSessionTracking
|
#region GroupSessionTracking
|
||||||
|
|
|
@ -48,7 +48,7 @@ using OpenSim.Tests.Common.Mock;
|
||||||
namespace OpenSim.Region.OptionalModules.World.NPC.Tests
|
namespace OpenSim.Region.OptionalModules.World.NPC.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class NPCModuleTests
|
public class NPCModuleTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private TestScene m_scene;
|
private TestScene m_scene;
|
||||||
private AvatarFactoryModule m_afMod;
|
private AvatarFactoryModule m_afMod;
|
||||||
|
|
|
@ -78,11 +78,17 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
private float _PIDHoverTao;
|
private float _PIDHoverTao;
|
||||||
|
|
||||||
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
|
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
|
||||||
|
: base(parent_scene, localID, avName, "BSCharacter")
|
||||||
{
|
{
|
||||||
base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
|
|
||||||
_physicsActorType = (int)ActorTypes.Agent;
|
_physicsActorType = (int)ActorTypes.Agent;
|
||||||
_position = pos;
|
_position = pos;
|
||||||
|
|
||||||
|
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
|
||||||
|
// replace with the default values.
|
||||||
_size = size;
|
_size = size;
|
||||||
|
if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
|
||||||
|
if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
|
||||||
|
|
||||||
_flying = isFlying;
|
_flying = isFlying;
|
||||||
_orientation = OMV.Quaternion.Identity;
|
_orientation = OMV.Quaternion.Identity;
|
||||||
_velocity = OMV.Vector3.Zero;
|
_velocity = OMV.Vector3.Zero;
|
||||||
|
@ -131,6 +137,10 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
// Set the velocity and compute the proper friction
|
// Set the velocity and compute the proper friction
|
||||||
ForceVelocity = _velocity;
|
ForceVelocity = _velocity;
|
||||||
|
|
||||||
|
// This will enable or disable the flying buoyancy of the avatar.
|
||||||
|
// Needs to be reset especially when an avatar is recreated after crossing a region boundry.
|
||||||
|
Flying = _flying;
|
||||||
|
|
||||||
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
|
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
|
||||||
BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
|
BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
|
||||||
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
|
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
|
||||||
|
@ -171,8 +181,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// Avatar capsule size is kept in the scale parameter.
|
// Avatar capsule size is kept in the scale parameter.
|
||||||
// return _size;
|
return _size;
|
||||||
return new OMV.Vector3(Scale.X * 2f, Scale.Y * 2f, Scale.Z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
|
@ -180,8 +189,8 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
_size = value;
|
_size = value;
|
||||||
ComputeAvatarScale(_size);
|
ComputeAvatarScale(_size);
|
||||||
ComputeAvatarVolumeAndMass();
|
ComputeAvatarVolumeAndMass();
|
||||||
DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
|
DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
||||||
LocalID, Scale, _avatarDensity, _avatarVolume, RawMass);
|
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
|
||||||
|
|
||||||
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
|
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
|
||||||
{
|
{
|
||||||
|
@ -199,9 +208,9 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
set { BaseShape = value; }
|
set { BaseShape = value; }
|
||||||
}
|
}
|
||||||
// I want the physics engine to make an avatar capsule
|
// I want the physics engine to make an avatar capsule
|
||||||
public override ShapeData.PhysicsShapeType PreferredPhysicalShape
|
public override BSPhysicsShapeType PreferredPhysicalShape
|
||||||
{
|
{
|
||||||
get {return ShapeData.PhysicsShapeType.SHAPE_AVATAR; }
|
get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Grabbed {
|
public override bool Grabbed {
|
||||||
|
@ -610,13 +619,19 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
// The 'size' given by the simulator is the mid-point of the avatar
|
// The 'size' given by the simulator is the mid-point of the avatar
|
||||||
// and X and Y are unspecified.
|
// and X and Y are unspecified.
|
||||||
|
|
||||||
OMV.Vector3 newScale = OMV.Vector3.Zero;
|
OMV.Vector3 newScale = size;
|
||||||
newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
// newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
|
||||||
newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
// newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
|
||||||
|
|
||||||
// From the total height, remove the capsule half spheres that are at each end
|
// From the total height, remove the capsule half spheres that are at each end
|
||||||
newScale.Z = size.Z- (newScale.X + newScale.Y);
|
// The 1.15f came from ODE. Not sure what this factors in.
|
||||||
Scale = newScale;
|
// newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
|
||||||
|
|
||||||
|
// The total scale height is the central cylindar plus the caps on the two ends.
|
||||||
|
newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
|
||||||
|
|
||||||
|
// Convert diameters to radii and height to half height -- the way Bullet expects it.
|
||||||
|
Scale = newScale / 2f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set _avatarVolume and _mass based on capsule size, _density and Scale
|
// set _avatarVolume and _mass based on capsule size, _density and Scale
|
||||||
|
|
|
@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
private Quaternion m_referenceFrame = Quaternion.Identity;
|
private Quaternion m_referenceFrame = Quaternion.Identity;
|
||||||
|
|
||||||
// Linear properties
|
// Linear properties
|
||||||
|
private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
|
||||||
private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
|
private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
|
||||||
private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
|
private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
|
||||||
private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
|
private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
|
||||||
private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
|
|
||||||
private Vector3 m_linearFrictionTimescale = Vector3.Zero;
|
private Vector3 m_linearFrictionTimescale = Vector3.Zero;
|
||||||
private float m_linearMotorDecayTimescale = 0;
|
private float m_linearMotorDecayTimescale = 0;
|
||||||
private float m_linearMotorTimescale = 0;
|
private float m_linearMotorTimescale = 0;
|
||||||
|
@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// private Vector3 m_linearMotorOffset = Vector3.Zero;
|
// private Vector3 m_linearMotorOffset = Vector3.Zero;
|
||||||
|
|
||||||
//Angular properties
|
//Angular properties
|
||||||
|
private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
|
||||||
private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
|
private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
|
||||||
// private int m_angularMotorApply = 0; // application frame counter
|
// private int m_angularMotorApply = 0; // application frame counter
|
||||||
private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
|
private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
|
||||||
|
@ -124,6 +125,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
|
// Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
|
||||||
|
|
||||||
//Attractor properties
|
//Attractor properties
|
||||||
|
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 = 500f; // Timescale > 300 means no vert attractor.
|
private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
|
||||||
|
|
||||||
|
@ -152,10 +154,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
|
m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
|
||||||
break;
|
break;
|
||||||
case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
|
case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
|
||||||
m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
|
m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
|
||||||
|
m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
|
||||||
break;
|
break;
|
||||||
case Vehicle.ANGULAR_MOTOR_TIMESCALE:
|
case Vehicle.ANGULAR_MOTOR_TIMESCALE:
|
||||||
m_angularMotorTimescale = Math.Max(pValue, 0.01f);
|
m_angularMotorTimescale = Math.Max(pValue, 0.01f);
|
||||||
|
m_angularMotor.TimeScale = m_angularMotorTimescale;
|
||||||
break;
|
break;
|
||||||
case Vehicle.BANKING_EFFICIENCY:
|
case Vehicle.BANKING_EFFICIENCY:
|
||||||
m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
|
m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
|
||||||
|
@ -185,33 +189,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
|
m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
|
||||||
break;
|
break;
|
||||||
case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
|
case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
|
||||||
m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
|
m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
|
||||||
|
m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
|
||||||
break;
|
break;
|
||||||
case Vehicle.LINEAR_MOTOR_TIMESCALE:
|
case Vehicle.LINEAR_MOTOR_TIMESCALE:
|
||||||
m_linearMotorTimescale = Math.Max(pValue, 0.01f);
|
m_linearMotorTimescale = Math.Max(pValue, 0.01f);
|
||||||
|
m_linearMotor.TimeScale = m_linearMotorTimescale;
|
||||||
break;
|
break;
|
||||||
case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
|
case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
|
||||||
m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
|
m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
|
||||||
|
m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
|
||||||
break;
|
break;
|
||||||
case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
|
case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
|
||||||
m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
|
m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
|
||||||
|
m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// These are vector properties but the engine lets you use a single float value to
|
// These are vector properties but the engine lets you use a single float value to
|
||||||
// set all of the components to the same value
|
// set all of the components to the same value
|
||||||
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
|
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
|
||||||
m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
|
m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
|
||||||
|
m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
|
||||||
break;
|
break;
|
||||||
case Vehicle.ANGULAR_MOTOR_DIRECTION:
|
case Vehicle.ANGULAR_MOTOR_DIRECTION:
|
||||||
m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
|
m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
|
||||||
// m_angularMotorApply = 100;
|
m_angularMotor.SetTarget(m_angularMotorDirection);
|
||||||
break;
|
break;
|
||||||
case Vehicle.LINEAR_FRICTION_TIMESCALE:
|
case Vehicle.LINEAR_FRICTION_TIMESCALE:
|
||||||
m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
|
m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
|
||||||
|
m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
|
||||||
break;
|
break;
|
||||||
case Vehicle.LINEAR_MOTOR_DIRECTION:
|
case Vehicle.LINEAR_MOTOR_DIRECTION:
|
||||||
m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
|
m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
|
||||||
m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
|
m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
|
||||||
|
m_linearMotor.SetTarget(m_linearMotorDirection);
|
||||||
break;
|
break;
|
||||||
case Vehicle.LINEAR_MOTOR_OFFSET:
|
case Vehicle.LINEAR_MOTOR_OFFSET:
|
||||||
m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
|
m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
|
||||||
|
@ -227,6 +238,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
|
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
|
||||||
m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
||||||
|
m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
|
||||||
break;
|
break;
|
||||||
case Vehicle.ANGULAR_MOTOR_DIRECTION:
|
case Vehicle.ANGULAR_MOTOR_DIRECTION:
|
||||||
// Limit requested angular speed to 2 rps= 4 pi rads/sec
|
// Limit requested angular speed to 2 rps= 4 pi rads/sec
|
||||||
|
@ -234,14 +246,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
|
pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
|
||||||
pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
|
pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
|
||||||
m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
||||||
// m_angularMotorApply = 100;
|
m_angularMotor.SetTarget(m_angularMotorDirection);
|
||||||
break;
|
break;
|
||||||
case Vehicle.LINEAR_FRICTION_TIMESCALE:
|
case Vehicle.LINEAR_FRICTION_TIMESCALE:
|
||||||
m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
||||||
|
m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
|
||||||
break;
|
break;
|
||||||
case Vehicle.LINEAR_MOTOR_DIRECTION:
|
case Vehicle.LINEAR_MOTOR_DIRECTION:
|
||||||
m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
||||||
m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
||||||
|
m_linearMotor.SetTarget(m_linearMotorDirection);
|
||||||
break;
|
break;
|
||||||
case Vehicle.LINEAR_MOTOR_OFFSET:
|
case Vehicle.LINEAR_MOTOR_OFFSET:
|
||||||
m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
|
||||||
|
@ -303,7 +317,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_VhoverEfficiency = 0;
|
m_VhoverEfficiency = 0;
|
||||||
m_VhoverTimescale = 0;
|
m_VhoverTimescale = 0;
|
||||||
m_VehicleBuoyancy = 0;
|
m_VehicleBuoyancy = 0;
|
||||||
|
|
||||||
m_linearDeflectionEfficiency = 1;
|
m_linearDeflectionEfficiency = 1;
|
||||||
m_linearDeflectionTimescale = 1;
|
m_linearDeflectionTimescale = 1;
|
||||||
|
|
||||||
|
@ -319,6 +333,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
|
||||||
m_referenceFrame = Quaternion.Identity;
|
m_referenceFrame = Quaternion.Identity;
|
||||||
m_flags = (VehicleFlag)0;
|
m_flags = (VehicleFlag)0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Vehicle.TYPE_SLED:
|
case Vehicle.TYPE_SLED:
|
||||||
|
@ -351,10 +366,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
m_bankingMix = 1;
|
m_bankingMix = 1;
|
||||||
|
|
||||||
m_referenceFrame = Quaternion.Identity;
|
m_referenceFrame = Quaternion.Identity;
|
||||||
m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
|
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
|
||||||
m_flags &=
|
| VehicleFlag.HOVER_TERRAIN_ONLY
|
||||||
~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
|
| VehicleFlag.HOVER_GLOBAL_HEIGHT
|
||||||
VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
|
| VehicleFlag.HOVER_UP_ONLY);
|
||||||
|
m_flags |= (VehicleFlag.NO_DEFLECTION_UP
|
||||||
|
| VehicleFlag.LIMIT_ROLL_ONLY
|
||||||
|
| VehicleFlag.LIMIT_MOTOR_UP);
|
||||||
break;
|
break;
|
||||||
case Vehicle.TYPE_CAR:
|
case Vehicle.TYPE_CAR:
|
||||||
m_linearMotorDirection = Vector3.Zero;
|
m_linearMotorDirection = Vector3.Zero;
|
||||||
|
@ -510,6 +528,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
| VehicleFlag.HOVER_GLOBAL_HEIGHT);
|
| VehicleFlag.HOVER_GLOBAL_HEIGHT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update any physical parameters based on this type.
|
||||||
|
Refresh();
|
||||||
|
|
||||||
|
m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
|
||||||
|
m_linearMotorDecayTimescale, m_linearFrictionTimescale,
|
||||||
|
1f);
|
||||||
|
m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
|
||||||
|
|
||||||
|
m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
|
||||||
|
m_angularMotorDecayTimescale, m_angularFrictionTimescale,
|
||||||
|
1f);
|
||||||
|
m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
|
||||||
|
|
||||||
|
m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
|
||||||
|
BSMotor.Infinite, BSMotor.InfiniteVector,
|
||||||
|
m_verticalAttractionEfficiency);
|
||||||
|
// Z goes away and we keep X and Y
|
||||||
|
m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
|
||||||
|
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.
|
||||||
|
@ -518,13 +558,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
if (IsActive)
|
if (IsActive)
|
||||||
{
|
{
|
||||||
|
m_vehicleMass = Prim.Linkset.LinksetMass;
|
||||||
|
|
||||||
// Friction effects are handled by this vehicle code
|
// Friction effects are handled by this vehicle code
|
||||||
BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
|
float friction = 0f;
|
||||||
BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
|
BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
|
||||||
|
|
||||||
// BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
|
// Moderate angular movement introduced by Bullet.
|
||||||
|
// TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
|
||||||
|
// Maybe compute linear and angular factor and damping from params.
|
||||||
|
float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
|
||||||
|
BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
|
||||||
|
|
||||||
VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID);
|
// DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
|
||||||
|
// Vector3 localInertia = new Vector3(1f, 1f, 1f);
|
||||||
|
Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
|
||||||
|
BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
|
||||||
|
|
||||||
|
VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
|
||||||
|
Prim.LocalID, friction, localInertia, angularDamping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,111 +603,109 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
if (!IsActive) return;
|
if (!IsActive) return;
|
||||||
|
|
||||||
// DEBUG
|
|
||||||
// Because Bullet does apply forces to the vehicle, our last computed
|
|
||||||
// linear and angular velocities are not what is happening now.
|
|
||||||
// Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
|
|
||||||
// m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
|
|
||||||
// m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
|
|
||||||
// m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
|
|
||||||
// END DEBUG
|
|
||||||
|
|
||||||
m_vehicleMass = Prim.Linkset.LinksetMass;
|
|
||||||
|
|
||||||
MoveLinear(pTimestep);
|
MoveLinear(pTimestep);
|
||||||
// Commented out for debug
|
|
||||||
MoveAngular(pTimestep);
|
MoveAngular(pTimestep);
|
||||||
// Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
|
|
||||||
// Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
|
|
||||||
|
|
||||||
LimitRotation(pTimestep);
|
LimitRotation(pTimestep);
|
||||||
|
|
||||||
// remember the position so next step we can limit absolute movement effects
|
// remember the position so next step we can limit absolute movement effects
|
||||||
m_lastPositionVector = Prim.ForcePosition;
|
m_lastPositionVector = Prim.ForcePosition;
|
||||||
|
|
||||||
VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG
|
|
||||||
Prim.LocalID,
|
|
||||||
BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
|
|
||||||
BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
|
|
||||||
Prim.Inertia,
|
|
||||||
m_vehicleMass
|
|
||||||
);
|
|
||||||
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
|
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
|
||||||
Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
|
Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
|
||||||
}// end Step
|
}
|
||||||
|
|
||||||
// Apply the effect of the linear motor.
|
// Apply the effect of the linear motor.
|
||||||
// Also does hover and float.
|
// Also does hover and float.
|
||||||
private void MoveLinear(float pTimestep)
|
private void MoveLinear(float pTimestep)
|
||||||
{
|
{
|
||||||
// m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates
|
Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
|
||||||
// m_lastLinearVelocityVector is the current speed we are moving in that direction
|
|
||||||
if (m_linearMotorDirection.LengthSquared() > 0.001f)
|
|
||||||
{
|
|
||||||
Vector3 origDir = m_linearMotorDirection; // DEBUG
|
|
||||||
Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
|
|
||||||
// DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
|
|
||||||
Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
|
|
||||||
|
|
||||||
// Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete
|
// Rotate new object velocity from vehicle relative to world coordinates
|
||||||
Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
|
linearMotorContribution *= Prim.ForceOrientation;
|
||||||
m_lastLinearVelocityVector += addAmount;
|
|
||||||
|
|
||||||
float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
|
|
||||||
m_linearMotorDirection *= (1f - decayFactor);
|
|
||||||
|
|
||||||
// Rotate new object velocity from vehicle relative to world coordinates
|
|
||||||
m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
|
|
||||||
|
|
||||||
// Apply friction for next time
|
|
||||||
Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
|
|
||||||
m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
|
|
||||||
|
|
||||||
VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}",
|
|
||||||
Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
|
|
||||||
m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if what remains of direction is very small, zero it.
|
|
||||||
m_linearMotorDirection = Vector3.Zero;
|
|
||||||
m_lastLinearVelocityVector = Vector3.Zero;
|
|
||||||
m_newVelocity = Vector3.Zero;
|
|
||||||
|
|
||||||
VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// m_newVelocity is velocity computed from linear motor in world coordinates
|
|
||||||
|
|
||||||
|
// ==================================================================
|
||||||
// Gravity and Buoyancy
|
// Gravity and Buoyancy
|
||||||
// There is some gravity, make a gravity force vector that is applied after object velocity.
|
// 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);
|
Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
|
||||||
|
|
||||||
/*
|
|
||||||
* RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
|
|
||||||
// Preserve the current Z velocity
|
|
||||||
Vector3 vel_now = m_prim.Velocity;
|
|
||||||
m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
|
|
||||||
*/
|
|
||||||
|
|
||||||
Vector3 pos = Prim.ForcePosition;
|
Vector3 pos = Prim.ForcePosition;
|
||||||
// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
|
|
||||||
|
|
||||||
// If below the terrain, move us above the ground a little.
|
|
||||||
float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
|
float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
|
||||||
|
|
||||||
|
Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight);
|
||||||
|
|
||||||
|
Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight);
|
||||||
|
|
||||||
|
ComputeLinearBlockingEndPoint(pTimestep, ref pos);
|
||||||
|
|
||||||
|
Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight);
|
||||||
|
|
||||||
|
// ==================================================================
|
||||||
|
Vector3 newVelocity = linearMotorContribution
|
||||||
|
+ terrainHeightContribution
|
||||||
|
+ hoverContribution
|
||||||
|
+ limitMotorUpContribution;
|
||||||
|
|
||||||
|
// If not changing some axis, reduce out velocity
|
||||||
|
if ((m_flags & (VehicleFlag.NO_X)) != 0)
|
||||||
|
newVelocity.X = 0;
|
||||||
|
if ((m_flags & (VehicleFlag.NO_Y)) != 0)
|
||||||
|
newVelocity.Y = 0;
|
||||||
|
if ((m_flags & (VehicleFlag.NO_Z)) != 0)
|
||||||
|
newVelocity.Z = 0;
|
||||||
|
|
||||||
|
// ==================================================================
|
||||||
|
// Clamp REALLY high or low velocities
|
||||||
|
float newVelocityLengthSq = newVelocity.LengthSquared();
|
||||||
|
if (newVelocityLengthSq > 1e6f)
|
||||||
|
{
|
||||||
|
newVelocity /= newVelocity.Length();
|
||||||
|
newVelocity *= 1000f;
|
||||||
|
}
|
||||||
|
else if (newVelocityLengthSq < 1e-6f)
|
||||||
|
newVelocity = Vector3.Zero;
|
||||||
|
|
||||||
|
// ==================================================================
|
||||||
|
// Stuff new linear velocity into the vehicle
|
||||||
|
Prim.ForceVelocity = newVelocity;
|
||||||
|
// Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
|
||||||
|
|
||||||
|
// Other linear forces are applied as forces.
|
||||||
|
Vector3 totalDownForce = grav * m_vehicleMass;
|
||||||
|
if (totalDownForce != Vector3.Zero)
|
||||||
|
{
|
||||||
|
Prim.AddForce(totalDownForce, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
|
||||||
|
Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
|
||||||
|
newVelocity, Prim.Velocity, totalDownForce);
|
||||||
|
|
||||||
|
} // end MoveLinear()
|
||||||
|
|
||||||
|
public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep, ref Vector3 pos, float terrainHeight)
|
||||||
|
{
|
||||||
|
Vector3 ret = Vector3.Zero;
|
||||||
|
// If below the terrain, move us above the ground a little.
|
||||||
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
|
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
|
||||||
// TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
|
// TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
|
||||||
// Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
|
// Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
|
||||||
// if (rotatedSize.Z < terrainHeight)
|
// if (rotatedSize.Z < terrainHeight)
|
||||||
if (pos.Z < terrainHeight)
|
if (pos.Z < terrainHeight)
|
||||||
{
|
{
|
||||||
|
// TODO: correct position by applying force rather than forcing position.
|
||||||
pos.Z = terrainHeight + 2;
|
pos.Z = terrainHeight + 2;
|
||||||
Prim.ForcePosition = pos;
|
Prim.ForcePosition = pos;
|
||||||
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
|
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 ComputeLinearHover(float pTimestep, ref Vector3 pos, float terrainHeight)
|
||||||
|
{
|
||||||
|
Vector3 ret = Vector3.Zero;
|
||||||
|
|
||||||
// Check if hovering
|
|
||||||
// m_VhoverEfficiency: 0=bouncy, 1=totally damped
|
// m_VhoverEfficiency: 0=bouncy, 1=totally damped
|
||||||
// m_VhoverTimescale: time to achieve height
|
// m_VhoverTimescale: time to achieve height
|
||||||
if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
|
if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
|
||||||
|
@ -694,28 +744,31 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// RA: where does the 50 come from?
|
// RA: where does the 50 come from?
|
||||||
float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
|
float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
|
||||||
// Replace Vertical speed with correction figure if significant
|
// Replace Vertical speed with correction figure if significant
|
||||||
if (Math.Abs(verticalError) > 0.01f)
|
if (verticalError > 0.01f)
|
||||||
{
|
{
|
||||||
m_newVelocity.Z += verticalCorrectionVelocity;
|
ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
|
||||||
//KF: m_VhoverEfficiency is not yet implemented
|
//KF: m_VhoverEfficiency is not yet implemented
|
||||||
}
|
}
|
||||||
else if (verticalError < -0.01)
|
else if (verticalError < -0.01)
|
||||||
{
|
{
|
||||||
m_newVelocity.Z -= verticalCorrectionVelocity;
|
ret = new Vector3(0f, 0f, -verticalCorrectionVelocity);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_newVelocity.Z = 0f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
|
VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}",
|
||||||
|
Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
Vector3 posChange = pos - m_lastPositionVector;
|
Vector3 posChange = pos - m_lastPositionVector;
|
||||||
if (m_BlockingEndPoint != Vector3.Zero)
|
if (m_BlockingEndPoint != Vector3.Zero)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
|
||||||
if (pos.X >= (m_BlockingEndPoint.X - (float)1))
|
if (pos.X >= (m_BlockingEndPoint.X - (float)1))
|
||||||
{
|
{
|
||||||
pos.X -= posChange.X + 1;
|
pos.X -= posChange.X + 1;
|
||||||
|
@ -748,75 +801,45 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
Prim.LocalID, m_BlockingEndPoint, posChange, pos);
|
Prim.LocalID, m_BlockingEndPoint, posChange, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
#region downForce
|
public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight)
|
||||||
Vector3 downForce = 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.
|
||||||
// Is this an angular force or both linear and angular??
|
|
||||||
float distanceAboveGround = pos.Z - terrainHeight;
|
float distanceAboveGround = pos.Z - terrainHeight;
|
||||||
if (distanceAboveGround > 2f)
|
if (distanceAboveGround > 1f)
|
||||||
{
|
{
|
||||||
// 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);
|
||||||
downForce = new Vector3(0, 0, -distanceAboveGround);
|
ret = new Vector3(0, 0, -distanceAboveGround);
|
||||||
}
|
}
|
||||||
// TODO: this calculation is all wrong. From the description at
|
// TODO: this calculation is all wrong. From the description at
|
||||||
// (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
|
// (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
|
||||||
// has a decay factor. This says this force should
|
// has a decay factor. This says this force should
|
||||||
// be computed with a motor.
|
// be computed with a motor.
|
||||||
VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
|
VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
|
||||||
Prim.LocalID, distanceAboveGround, downForce);
|
Prim.LocalID, distanceAboveGround, ret);
|
||||||
}
|
}
|
||||||
#endregion // downForce
|
return ret;
|
||||||
|
}
|
||||||
// If not changing some axis, reduce out velocity
|
|
||||||
if ((m_flags & (VehicleFlag.NO_X)) != 0)
|
|
||||||
m_newVelocity.X = 0;
|
|
||||||
if ((m_flags & (VehicleFlag.NO_Y)) != 0)
|
|
||||||
m_newVelocity.Y = 0;
|
|
||||||
if ((m_flags & (VehicleFlag.NO_Z)) != 0)
|
|
||||||
m_newVelocity.Z = 0;
|
|
||||||
|
|
||||||
// Clamp REALLY high or low velocities
|
|
||||||
if (m_newVelocity.LengthSquared() > 1e6f)
|
|
||||||
{
|
|
||||||
m_newVelocity /= m_newVelocity.Length();
|
|
||||||
m_newVelocity *= 1000f;
|
|
||||||
}
|
|
||||||
else if (m_newVelocity.LengthSquared() < 1e-6f)
|
|
||||||
m_newVelocity = Vector3.Zero;
|
|
||||||
|
|
||||||
// Stuff new linear velocity into the vehicle
|
|
||||||
Prim.ForceVelocity = m_newVelocity;
|
|
||||||
// Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
|
|
||||||
|
|
||||||
Vector3 totalDownForce = downForce + grav;
|
|
||||||
if (totalDownForce != Vector3.Zero)
|
|
||||||
{
|
|
||||||
Prim.AddForce(totalDownForce * m_vehicleMass, false);
|
|
||||||
// Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
|
|
||||||
Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
|
|
||||||
|
|
||||||
} // end MoveLinear()
|
|
||||||
|
|
||||||
|
// =======================================================================
|
||||||
// =======================================================================
|
// =======================================================================
|
||||||
// Apply the effect of the angular motor.
|
// Apply the effect of the angular motor.
|
||||||
private void MoveAngular(float pTimestep)
|
private void MoveAngular(float pTimestep)
|
||||||
{
|
{
|
||||||
// m_angularMotorDirection // angular velocity requested by LSL motor
|
// m_angularMotorDirection // angular velocity requested by LSL motor
|
||||||
// m_angularMotorApply // application frame counter
|
|
||||||
// m_angularMotorVelocity // current angular motor velocity (ramps up and down)
|
// m_angularMotorVelocity // current angular motor velocity (ramps up and down)
|
||||||
// m_angularMotorTimescale // motor angular velocity ramp up rate
|
// m_angularMotorTimescale // motor angular velocity ramp up time
|
||||||
// m_angularMotorDecayTimescale // motor angular velocity decay rate
|
// m_angularMotorDecayTimescale // motor angular velocity decay rate
|
||||||
// m_angularFrictionTimescale // body angular velocity decay rate
|
// m_angularFrictionTimescale // body angular velocity decay rate
|
||||||
// m_lastAngularVelocity // what was last applied to body
|
// m_lastAngularVelocity // what was last applied to body
|
||||||
|
|
||||||
|
/*
|
||||||
if (m_angularMotorDirection.LengthSquared() > 0.0001)
|
if (m_angularMotorDirection.LengthSquared() > 0.0001)
|
||||||
{
|
{
|
||||||
Vector3 origVel = m_angularMotorVelocity;
|
Vector3 origVel = m_angularMotorVelocity;
|
||||||
|
@ -835,141 +858,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
m_angularMotorVelocity = Vector3.Zero;
|
m_angularMotorVelocity = Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#region Vertical attactor
|
Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
|
||||||
|
|
||||||
Vector3 vertattr = Vector3.Zero;
|
// ==================================================================
|
||||||
Vector3 deflection = Vector3.Zero;
|
// NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
|
||||||
Vector3 banking = Vector3.Zero;
|
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
|
||||||
|
|
||||||
// If vertical attaction timescale is reasonable and we applied an angular force last time...
|
|
||||||
if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
|
|
||||||
{
|
{
|
||||||
float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
|
angularMotorContribution.X = 0f;
|
||||||
if (Prim.IsColliding)
|
angularMotorContribution.Y = 0f;
|
||||||
VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
|
VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
|
||||||
|
|
||||||
VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
|
|
||||||
|
|
||||||
// Create a vector of the vehicle "up" in world coordinates
|
|
||||||
Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
|
|
||||||
// verticalError.X and .Y are the World error amounts. They are 0 when there is no
|
|
||||||
// error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
|
|
||||||
// side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
|
|
||||||
// and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
|
|
||||||
// modulated to prevent a stable inverted body.
|
|
||||||
|
|
||||||
// Error is 0 (no error) to +/- 2 (max error)
|
|
||||||
if (verticalError.Z < 0.0f)
|
|
||||||
{
|
|
||||||
verticalError.X = 2.0f - verticalError.X;
|
|
||||||
verticalError.Y = 2.0f - verticalError.Y;
|
|
||||||
}
|
|
||||||
// scale it by VAservo (timestep and timescale)
|
|
||||||
verticalError = verticalError * VAservo;
|
|
||||||
|
|
||||||
// As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
|
|
||||||
// then .X increases, so change Body angular velocity X based on Y, and Y based on X.
|
|
||||||
// Z is not changed.
|
|
||||||
vertattr.X = verticalError.Y;
|
|
||||||
vertattr.Y = - verticalError.X;
|
|
||||||
vertattr.Z = 0f;
|
|
||||||
|
|
||||||
// scaling appears better usingsquare-law
|
|
||||||
Vector3 angularVelocity = Prim.ForceRotationalVelocity;
|
|
||||||
float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
|
|
||||||
vertattr.X += bounce * angularVelocity.X;
|
|
||||||
vertattr.Y += bounce * angularVelocity.Y;
|
|
||||||
|
|
||||||
VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
|
|
||||||
Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endregion // Vertical attactor
|
|
||||||
|
|
||||||
#region Deflection
|
|
||||||
|
|
||||||
if (m_angularDeflectionEfficiency != 0)
|
|
||||||
{
|
|
||||||
// Compute a scaled vector that points in the preferred axis (X direction)
|
|
||||||
Vector3 scaledDefaultDirection =
|
|
||||||
new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
|
|
||||||
// Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
|
|
||||||
// Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
|
|
||||||
Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
|
|
||||||
|
|
||||||
// Scale by efficiency and timescale
|
|
||||||
deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
|
|
||||||
|
|
||||||
VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
|
|
||||||
Prim.LocalID, preferredAxisOfMotion, deflection);
|
|
||||||
// This deflection computation is not correct.
|
|
||||||
deflection = Vector3.Zero;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep);
|
||||||
|
|
||||||
#region Banking
|
Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep);
|
||||||
|
|
||||||
if (m_bankingEfficiency != 0)
|
Vector3 bankingContribution = ComputeAngularBanking(pTimestep);
|
||||||
{
|
|
||||||
Vector3 dir = Vector3.One * Prim.ForceOrientation;
|
|
||||||
float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
|
|
||||||
//Changes which way it banks in and out of turns
|
|
||||||
|
|
||||||
//Use the square of the efficiency, as it looks much more how SL banking works
|
// ==================================================================
|
||||||
float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
|
m_lastVertAttractor = verticalAttractionContribution;
|
||||||
if (m_bankingEfficiency < 0)
|
|
||||||
effSquared *= -1; //Keep the negative!
|
|
||||||
|
|
||||||
float mix = Math.Abs(m_bankingMix);
|
|
||||||
if (m_angularMotorVelocity.X == 0)
|
|
||||||
{
|
|
||||||
/*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
|
|
||||||
{
|
|
||||||
Vector3 axisAngle;
|
|
||||||
float angle;
|
|
||||||
parent.Orientation.GetAxisAngle(out axisAngle, out angle);
|
|
||||||
Vector3 rotatedVel = parent.Velocity * parent.Orientation;
|
|
||||||
if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
|
|
||||||
m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
|
|
||||||
else
|
|
||||||
m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
|
|
||||||
if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
|
|
||||||
//If they are colliding, we probably shouldn't shove the prim around... probably
|
|
||||||
{
|
|
||||||
float angVelZ = m_angularMotorVelocity.X*-1;
|
|
||||||
/*if(angVelZ > mix)
|
|
||||||
angVelZ = mix;
|
|
||||||
else if(angVelZ < -mix)
|
|
||||||
angVelZ = -mix;*/
|
|
||||||
//This controls how fast and how far the banking occurs
|
|
||||||
Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
|
|
||||||
if (bankingRot.X > 3)
|
|
||||||
bankingRot.X = 3;
|
|
||||||
else if (bankingRot.X < -3)
|
|
||||||
bankingRot.X = -3;
|
|
||||||
bankingRot *= Prim.ForceOrientation;
|
|
||||||
banking += bankingRot;
|
|
||||||
}
|
|
||||||
m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
|
|
||||||
VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
|
|
||||||
Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
m_lastVertAttractor = vertattr;
|
|
||||||
|
|
||||||
// Sum velocities
|
// Sum velocities
|
||||||
m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
|
m_lastAngularVelocity = angularMotorContribution
|
||||||
|
+ verticalAttractionContribution
|
||||||
#region Linear Motor Offset
|
+ bankingContribution
|
||||||
|
+ deflectionContribution;
|
||||||
|
|
||||||
|
// ==================================================================
|
||||||
//Offset section
|
//Offset section
|
||||||
if (m_linearMotorOffset != Vector3.Zero)
|
if (m_linearMotorOffset != Vector3.Zero)
|
||||||
{
|
{
|
||||||
|
@ -985,8 +902,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
//
|
//
|
||||||
// The torque created is the linear velocity crossed with the offset
|
// The torque created is the linear velocity crossed with the offset
|
||||||
|
|
||||||
// NOTE: this computation does should be in the linear section
|
// TODO: this computation should be in the linear section
|
||||||
// because there we know the impulse being applied.
|
// because that is where we know the impulse being applied.
|
||||||
Vector3 torqueFromOffset = Vector3.Zero;
|
Vector3 torqueFromOffset = Vector3.Zero;
|
||||||
// torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
|
// torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
|
||||||
if (float.IsNaN(torqueFromOffset.X))
|
if (float.IsNaN(torqueFromOffset.X))
|
||||||
|
@ -1000,15 +917,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
|
VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
// ==================================================================
|
||||||
|
|
||||||
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
|
|
||||||
{
|
|
||||||
m_lastAngularVelocity.X = 0;
|
|
||||||
m_lastAngularVelocity.Y = 0;
|
|
||||||
VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
|
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
|
||||||
{
|
{
|
||||||
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
|
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
|
||||||
|
@ -1021,18 +930,166 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
// The above calculates the absolute angular velocity needed. Angular velocity is massless.
|
// The above calculates the absolute angular velocity needed. Angular velocity is massless.
|
||||||
// Since we are stuffing the angular velocity directly into the object, the computed
|
// Since we are stuffing the angular velocity directly into the object, the computed
|
||||||
// velocity needs to be scaled by the timestep.
|
// velocity needs to be scaled by the timestep.
|
||||||
Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity);
|
// Also remove any motion that is on the object so added motion is only from vehicle.
|
||||||
|
Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep)
|
||||||
|
- Prim.ForceRotationalVelocity);
|
||||||
|
// Unscale the force by the angular factor so it overwhelmes the Bullet additions.
|
||||||
Prim.ForceRotationalVelocity = applyAngularForce;
|
Prim.ForceRotationalVelocity = applyAngularForce;
|
||||||
|
|
||||||
// Decay the angular movement for next time
|
VDetailLog("{0},MoveAngular,done,angMotor={1},vertAttr={2},bank={3},deflect={4},newAngForce={5},lastAngular={6}",
|
||||||
Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
|
Prim.LocalID,
|
||||||
m_lastAngularVelocity *= Vector3.One - decayamount;
|
angularMotorContribution, verticalAttractionContribution,
|
||||||
|
bankingContribution, deflectionContribution,
|
||||||
VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}",
|
applyAngularForce, m_lastAngularVelocity
|
||||||
Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
|
);
|
||||||
}
|
}
|
||||||
} //end MoveAngular
|
}
|
||||||
|
|
||||||
|
public Vector3 ComputeAngularVerticalAttraction(float pTimestep)
|
||||||
|
{
|
||||||
|
Vector3 ret = Vector3.Zero;
|
||||||
|
|
||||||
|
// If vertical attaction timescale is reasonable and we applied an angular force last time...
|
||||||
|
if (m_verticalAttractionTimescale < 500)
|
||||||
|
{
|
||||||
|
Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
|
||||||
|
verticalError.Normalize();
|
||||||
|
m_verticalAttractionMotor.SetCurrent(verticalError);
|
||||||
|
m_verticalAttractionMotor.SetTarget(Vector3.UnitZ);
|
||||||
|
ret = m_verticalAttractionMotor.Step(pTimestep);
|
||||||
|
/*
|
||||||
|
// Take a vector pointing up and convert it from world to vehicle relative coords.
|
||||||
|
Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
|
||||||
|
verticalError.Normalize();
|
||||||
|
|
||||||
|
// If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
|
||||||
|
// is now leaning to one side (rotated around the X axis) and the Y value will
|
||||||
|
// go from zero (nearly straight up) to one (completely to the side) or leaning
|
||||||
|
// front-to-back (rotated around the Y axis) and the value of X will be between
|
||||||
|
// zero and one.
|
||||||
|
// The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
|
||||||
|
|
||||||
|
// If verticalError.Z is negative, the vehicle is upside down. Add additional push.
|
||||||
|
if (verticalError.Z < 0f)
|
||||||
|
{
|
||||||
|
verticalError.X = 2f - verticalError.X;
|
||||||
|
verticalError.Y = 2f - verticalError.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Y error means needed rotation around X axis and visa versa.
|
||||||
|
verticalAttractionContribution.X = verticalError.Y;
|
||||||
|
verticalAttractionContribution.Y = - verticalError.X;
|
||||||
|
verticalAttractionContribution.Z = 0f;
|
||||||
|
|
||||||
|
// scale by the time scale and timestep
|
||||||
|
Vector3 unscaledContrib = verticalAttractionContribution;
|
||||||
|
verticalAttractionContribution /= m_verticalAttractionTimescale;
|
||||||
|
verticalAttractionContribution *= pTimestep;
|
||||||
|
|
||||||
|
// apply efficiency
|
||||||
|
Vector3 preEfficiencyContrib = verticalAttractionContribution;
|
||||||
|
float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
|
||||||
|
verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
|
||||||
|
|
||||||
|
VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}",
|
||||||
|
Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib,
|
||||||
|
m_verticalAttractionEfficiency, efficencySquared,
|
||||||
|
verticalAttractionContribution);
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 ComputeAngularDeflection(float pTimestep)
|
||||||
|
{
|
||||||
|
Vector3 ret = Vector3.Zero;
|
||||||
|
|
||||||
|
if (m_angularDeflectionEfficiency != 0)
|
||||||
|
{
|
||||||
|
// Compute a scaled vector that points in the preferred axis (X direction)
|
||||||
|
Vector3 scaledDefaultDirection =
|
||||||
|
new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
|
||||||
|
// Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
|
||||||
|
// Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
|
||||||
|
Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
|
||||||
|
|
||||||
|
// Scale by efficiency and timescale
|
||||||
|
ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
|
||||||
|
|
||||||
|
VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret);
|
||||||
|
|
||||||
|
// This deflection computation is not correct.
|
||||||
|
ret = Vector3.Zero;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 ComputeAngularBanking(float pTimestep)
|
||||||
|
{
|
||||||
|
Vector3 ret = Vector3.Zero;
|
||||||
|
|
||||||
|
if (m_bankingEfficiency != 0)
|
||||||
|
{
|
||||||
|
Vector3 dir = Vector3.One * Prim.ForceOrientation;
|
||||||
|
float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1);
|
||||||
|
//Changes which way it banks in and out of turns
|
||||||
|
|
||||||
|
//Use the square of the efficiency, as it looks much more how SL banking works
|
||||||
|
float effSquared = (m_bankingEfficiency * m_bankingEfficiency);
|
||||||
|
if (m_bankingEfficiency < 0)
|
||||||
|
effSquared *= -1; //Keep the negative!
|
||||||
|
|
||||||
|
float mix = Math.Abs(m_bankingMix);
|
||||||
|
if (m_angularMotorVelocity.X == 0)
|
||||||
|
{
|
||||||
|
// The vehicle is stopped
|
||||||
|
/*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
|
||||||
|
{
|
||||||
|
Vector3 axisAngle;
|
||||||
|
float angle;
|
||||||
|
parent.Orientation.GetAxisAngle(out axisAngle, out angle);
|
||||||
|
Vector3 rotatedVel = parent.Velocity * parent.Orientation;
|
||||||
|
if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
|
||||||
|
m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
|
||||||
|
else
|
||||||
|
m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If they are colliding, we probably shouldn't shove the prim around... probably
|
||||||
|
if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
|
||||||
|
{
|
||||||
|
float angVelZ = m_angularMotorVelocity.X * -1;
|
||||||
|
/*if(angVelZ > mix)
|
||||||
|
angVelZ = mix;
|
||||||
|
else if(angVelZ < -mix)
|
||||||
|
angVelZ = -mix;*/
|
||||||
|
//This controls how fast and how far the banking occurs
|
||||||
|
Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0);
|
||||||
|
if (bankingRot.X > 3)
|
||||||
|
bankingRot.X = 3;
|
||||||
|
else if (bankingRot.X < -3)
|
||||||
|
bankingRot.X = -3;
|
||||||
|
bankingRot *= Prim.ForceOrientation;
|
||||||
|
ret += bankingRot;
|
||||||
|
}
|
||||||
|
m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
|
||||||
|
VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
|
||||||
|
Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This is from previous instantiations of XXXDynamics.cs.
|
||||||
|
// Applies roll reference frame.
|
||||||
|
// TODO: is this the right way to separate the code to do this operation?
|
||||||
|
// Should this be in MoveAngular()?
|
||||||
internal void LimitRotation(float timestep)
|
internal void LimitRotation(float timestep)
|
||||||
{
|
{
|
||||||
Quaternion rotq = Prim.ForceOrientation;
|
Quaternion rotq = Prim.ForceOrientation;
|
||||||
|
|
|
@ -82,9 +82,9 @@ public abstract class BSLinkset
|
||||||
|
|
||||||
// Some linksets have a preferred physical shape.
|
// Some linksets have a preferred physical shape.
|
||||||
// Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
|
// Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
|
||||||
public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
|
public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
|
||||||
{
|
{
|
||||||
return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
|
return BSPhysicsShapeType.SHAPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linksets move around the children so the linkset might need to compute the child position
|
// Linksets move around the children so the linkset might need to compute the child position
|
||||||
|
|
|
@ -42,12 +42,12 @@ public sealed class BSLinksetCompound : BSLinkset
|
||||||
}
|
}
|
||||||
|
|
||||||
// For compound implimented linksets, if there are children, use compound shape for the root.
|
// For compound implimented linksets, if there are children, use compound shape for the root.
|
||||||
public override ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
|
public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
|
||||||
{
|
{
|
||||||
ShapeData.PhysicsShapeType ret = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
|
BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
|
||||||
if (IsRoot(requestor) && HasAnyChildren)
|
if (IsRoot(requestor) && HasAnyChildren)
|
||||||
{
|
{
|
||||||
ret = ShapeData.PhysicsShapeType.SHAPE_COMPOUND;
|
ret = BSPhysicsShapeType.SHAPE_COMPOUND;
|
||||||
}
|
}
|
||||||
// DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
|
// DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyrightD
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Reflection;
|
||||||
|
using Nini.Config;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
|
||||||
|
public struct MaterialAttributes
|
||||||
|
{
|
||||||
|
// Material type values that correspond with definitions for LSL
|
||||||
|
public enum Material : int
|
||||||
|
{
|
||||||
|
Stone = 0,
|
||||||
|
Metal,
|
||||||
|
Glass,
|
||||||
|
Wood,
|
||||||
|
Flesh,
|
||||||
|
Plastic,
|
||||||
|
Rubber,
|
||||||
|
Light,
|
||||||
|
// Hereafter are BulletSim additions
|
||||||
|
Avatar,
|
||||||
|
NumberOfTypes // the count of types in the enum.
|
||||||
|
}
|
||||||
|
// Names must be in the order of the above enum.
|
||||||
|
public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
|
||||||
|
"Flesh", "Plastic", "Rubber", "Light", "Avatar" };
|
||||||
|
public static string[] MaterialAttribs = { "Density", "Friction", "Restitution",
|
||||||
|
"ccdMotionThreshold", "ccdSweptSphereRadius" };
|
||||||
|
|
||||||
|
public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS)
|
||||||
|
{
|
||||||
|
type = t;
|
||||||
|
density = d;
|
||||||
|
friction = f;
|
||||||
|
restitution = r;
|
||||||
|
ccdMotionThreshold = ccdM;
|
||||||
|
ccdSweptSphereRadius = ccdS;
|
||||||
|
}
|
||||||
|
public string type;
|
||||||
|
public float density;
|
||||||
|
public float friction;
|
||||||
|
public float restitution;
|
||||||
|
public float ccdMotionThreshold;
|
||||||
|
public float ccdSweptSphereRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BSMaterials
|
||||||
|
{
|
||||||
|
public static MaterialAttributes[] Attributes;
|
||||||
|
|
||||||
|
static BSMaterials()
|
||||||
|
{
|
||||||
|
// Attribute sets for both the non-physical and physical instances of materials.
|
||||||
|
Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is where all the default material attributes are defined.
|
||||||
|
public static void InitializeFromDefaults(ConfigurationParameters parms)
|
||||||
|
{
|
||||||
|
// public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
|
||||||
|
// "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
|
||||||
|
float dFriction = parms.defaultFriction;
|
||||||
|
float dRestitution = parms.defaultRestitution;
|
||||||
|
float dDensity = parms.defaultDensity;
|
||||||
|
float dCcdM = parms.ccdMotionThreshold;
|
||||||
|
float dCcdS = parms.ccdSweptSphereRadius;
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Stone] =
|
||||||
|
new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Metal] =
|
||||||
|
new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Glass] =
|
||||||
|
new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Wood] =
|
||||||
|
new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Flesh] =
|
||||||
|
new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Plastic] =
|
||||||
|
new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Rubber] =
|
||||||
|
new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Light] =
|
||||||
|
new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Avatar] =
|
||||||
|
new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
|
new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
|
new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
|
new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
|
new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
|
new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
|
new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
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] =
|
||||||
|
new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
|
||||||
|
new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Under the [BulletSim] section, one can change the individual material
|
||||||
|
// attribute values. The format of the configuration parameter is:
|
||||||
|
// <materialName><Attribute>["Physical"] = floatValue
|
||||||
|
// For instance:
|
||||||
|
// [BulletSim]
|
||||||
|
// StoneFriction = 0.2
|
||||||
|
// FleshRestitutionPhysical = 0.8
|
||||||
|
// Materials can have different parameters for their static and
|
||||||
|
// physical instantiations. When setting the non-physical value,
|
||||||
|
// both values are changed. Setting the physical value only changes
|
||||||
|
// the physical value.
|
||||||
|
public static void InitializefromParameters(IConfig pConfig)
|
||||||
|
{
|
||||||
|
int matType = 0;
|
||||||
|
foreach (string matName in MaterialAttributes.MaterialNames)
|
||||||
|
{
|
||||||
|
foreach (string attribName in MaterialAttributes.MaterialAttribs)
|
||||||
|
{
|
||||||
|
string paramName = matName + attribName;
|
||||||
|
if (pConfig.Contains(paramName))
|
||||||
|
{
|
||||||
|
float paramValue = pConfig.GetFloat(paramName);
|
||||||
|
SetAttributeValue(matType, attribName, paramValue);
|
||||||
|
// set the physical value also
|
||||||
|
SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
|
||||||
|
}
|
||||||
|
paramName += "Physical";
|
||||||
|
if (pConfig.Contains(paramName))
|
||||||
|
{
|
||||||
|
float paramValue = pConfig.GetFloat(paramName);
|
||||||
|
SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
matType++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetAttributeValue(int matType, string attribName, float val)
|
||||||
|
{
|
||||||
|
MaterialAttributes thisAttrib = Attributes[matType];
|
||||||
|
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
|
||||||
|
if (fieldInfo != null)
|
||||||
|
{
|
||||||
|
fieldInfo.SetValue(thisAttrib, val);
|
||||||
|
Attributes[matType] = thisAttrib;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
|
||||||
|
{
|
||||||
|
int ind = (int)type;
|
||||||
|
if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
|
||||||
|
return Attributes[ind];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,104 +1,169 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public abstract class BSMotor
|
public abstract class BSMotor
|
||||||
{
|
{
|
||||||
public virtual void Reset() { }
|
// Timescales and other things can be turned off by setting them to 'infinite'.
|
||||||
public virtual void Zero() { }
|
public const float Infinite = 10000f;
|
||||||
}
|
public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
|
||||||
// Can all the incremental stepping be replaced with motor classes?
|
|
||||||
public class BSVMotor : BSMotor
|
public BSMotor(string useName)
|
||||||
{
|
{
|
||||||
public Vector3 FrameOfReference { get; set; }
|
UseName = useName;
|
||||||
public Vector3 Offset { get; set; }
|
PhysicsScene = null;
|
||||||
|
}
|
||||||
public float TimeScale { get; set; }
|
public virtual void Reset() { }
|
||||||
public float TargetValueDecayTimeScale { get; set; }
|
public virtual void Zero() { }
|
||||||
public Vector3 CurrentValueReductionTimescale { get; set; }
|
|
||||||
public float Efficiency { get; set; }
|
public string UseName { get; private set; }
|
||||||
|
// Used only for outputting debug information. Might not be set so check for null.
|
||||||
public Vector3 TargetValue { get; private set; }
|
public BSScene PhysicsScene { get; set; }
|
||||||
public Vector3 CurrentValue { get; private set; }
|
protected void MDetailLog(string msg, params Object[] parms)
|
||||||
|
{
|
||||||
|
if (PhysicsScene != null)
|
||||||
|
{
|
||||||
BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
|
if (PhysicsScene.VehicleLoggingEnabled)
|
||||||
{
|
{
|
||||||
TimeScale = timeScale;
|
PhysicsScene.DetailLog(msg, parms);
|
||||||
TargetValueDecayTimeScale = decayTimeScale;
|
}
|
||||||
CurrentValueReductionTimescale = frictionTimeScale;
|
}
|
||||||
Efficiency = efficiency;
|
}
|
||||||
}
|
}
|
||||||
public void SetCurrent(Vector3 current)
|
// Can all the incremental stepping be replaced with motor classes?
|
||||||
{
|
public class BSVMotor : BSMotor
|
||||||
CurrentValue = current;
|
{
|
||||||
}
|
public Vector3 FrameOfReference { get; set; }
|
||||||
public void SetTarget(Vector3 target)
|
public Vector3 Offset { get; set; }
|
||||||
{
|
|
||||||
TargetValue = target;
|
public float TimeScale { get; set; }
|
||||||
}
|
public float TargetValueDecayTimeScale { get; set; }
|
||||||
public Vector3 Step(float timeStep)
|
public Vector3 FrictionTimescale { get; set; }
|
||||||
{
|
public float Efficiency { get; set; }
|
||||||
if (CurrentValue.LengthSquared() > 0.001f)
|
|
||||||
{
|
public Vector3 TargetValue { get; private set; }
|
||||||
// Vector3 origDir = Target; // DEBUG
|
public Vector3 CurrentValue { get; private set; }
|
||||||
// Vector3 origVel = CurrentValue; // DEBUG
|
|
||||||
|
public BSVMotor(string useName)
|
||||||
// Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete
|
: base(useName)
|
||||||
Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep;
|
{
|
||||||
CurrentValue += addAmount;
|
TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
|
||||||
|
Efficiency = 1f;
|
||||||
float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
|
FrictionTimescale = BSMotor.InfiniteVector;
|
||||||
TargetValue *= (1f - decayFactor);
|
CurrentValue = TargetValue = Vector3.Zero;
|
||||||
|
}
|
||||||
Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep;
|
public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
|
||||||
CurrentValue *= (Vector3.One - frictionFactor);
|
: this(useName)
|
||||||
}
|
{
|
||||||
else
|
TimeScale = timeScale;
|
||||||
{
|
TargetValueDecayTimeScale = decayTimeScale;
|
||||||
// if what remains of direction is very small, zero it.
|
FrictionTimescale = frictionTimeScale;
|
||||||
TargetValue = Vector3.Zero;
|
Efficiency = efficiency;
|
||||||
CurrentValue = Vector3.Zero;
|
CurrentValue = TargetValue = Vector3.Zero;
|
||||||
|
}
|
||||||
// VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
|
public void SetCurrent(Vector3 current)
|
||||||
}
|
{
|
||||||
return CurrentValue;
|
CurrentValue = current;
|
||||||
}
|
}
|
||||||
}
|
public void SetTarget(Vector3 target)
|
||||||
|
{
|
||||||
public class BSFMotor : BSMotor
|
TargetValue = target;
|
||||||
{
|
}
|
||||||
public float TimeScale { get; set; }
|
public Vector3 Step(float timeStep)
|
||||||
public float DecayTimeScale { get; set; }
|
{
|
||||||
public float Friction { get; set; }
|
Vector3 returnCurrent = Vector3.Zero;
|
||||||
public float Efficiency { get; set; }
|
if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
|
||||||
|
{
|
||||||
public float Target { get; private set; }
|
Vector3 origTarget = TargetValue; // DEBUG
|
||||||
public float CurrentValue { get; private set; }
|
Vector3 origCurrVal = CurrentValue; // DEBUG
|
||||||
|
|
||||||
BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency)
|
// Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
|
||||||
{
|
Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
|
||||||
}
|
CurrentValue += addAmount;
|
||||||
public void SetCurrent(float target)
|
|
||||||
{
|
returnCurrent = CurrentValue;
|
||||||
}
|
|
||||||
public void SetTarget(float target)
|
// The desired value reduces to zero which also reduces the difference with current.
|
||||||
{
|
// If the decay time is infinite, don't decay at all.
|
||||||
}
|
float decayFactor = 0f;
|
||||||
public float Step(float timeStep)
|
if (TargetValueDecayTimeScale != BSMotor.Infinite)
|
||||||
{
|
{
|
||||||
return 0f;
|
decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
|
||||||
}
|
TargetValue *= (1f - decayFactor);
|
||||||
}
|
}
|
||||||
public class BSPIDMotor : BSMotor
|
|
||||||
{
|
Vector3 frictionFactor = Vector3.Zero;
|
||||||
// TODO: write and use this one
|
if (FrictionTimescale != BSMotor.InfiniteVector)
|
||||||
BSPIDMotor()
|
{
|
||||||
{
|
// frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
|
||||||
}
|
frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
|
||||||
}
|
frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
|
||||||
}
|
frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
|
||||||
|
CurrentValue *= (Vector3.One - frictionFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
MDetailLog("{0},BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
|
||||||
|
BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
|
||||||
|
timeStep, TimeScale, addAmount,
|
||||||
|
TargetValueDecayTimeScale, decayFactor,
|
||||||
|
FrictionTimescale, frictionFactor);
|
||||||
|
MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
|
||||||
|
BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
|
||||||
|
addAmount, decayFactor, frictionFactor, returnCurrent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Difference between what we have and target is small. Motor is done.
|
||||||
|
CurrentValue = Vector3.Zero;
|
||||||
|
TargetValue = Vector3.Zero;
|
||||||
|
|
||||||
|
MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
|
||||||
|
BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
|
||||||
|
|
||||||
|
}
|
||||||
|
return returnCurrent;
|
||||||
|
}
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
|
||||||
|
UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BSFMotor : BSMotor
|
||||||
|
{
|
||||||
|
public float TimeScale { get; set; }
|
||||||
|
public float DecayTimeScale { get; set; }
|
||||||
|
public float Friction { get; set; }
|
||||||
|
public float Efficiency { get; set; }
|
||||||
|
|
||||||
|
public float Target { get; private set; }
|
||||||
|
public float CurrentValue { get; private set; }
|
||||||
|
|
||||||
|
public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
|
||||||
|
: base(useName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void SetCurrent(float target)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void SetTarget(float target)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public float Step(float timeStep)
|
||||||
|
{
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class BSPIDMotor : BSMotor
|
||||||
|
{
|
||||||
|
// TODO: write and use this one
|
||||||
|
public BSPIDMotor(string useName)
|
||||||
|
: base(useName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -47,7 +47,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
*/
|
*/
|
||||||
public abstract class BSPhysObject : PhysicsActor
|
public abstract class BSPhysObject : PhysicsActor
|
||||||
{
|
{
|
||||||
protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
|
protected BSPhysObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
|
||||||
{
|
{
|
||||||
PhysicsScene = parentScene;
|
PhysicsScene = parentScene;
|
||||||
LocalID = localID;
|
LocalID = localID;
|
||||||
|
@ -91,9 +94,9 @@ public abstract class BSPhysObject : PhysicsActor
|
||||||
public PrimitiveBaseShape BaseShape { get; protected set; }
|
public PrimitiveBaseShape BaseShape { get; protected set; }
|
||||||
// Some types of objects have preferred physical representations.
|
// Some types of objects have preferred physical representations.
|
||||||
// Returns SHAPE_UNKNOWN if there is no preference.
|
// Returns SHAPE_UNKNOWN if there is no preference.
|
||||||
public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape
|
public virtual BSPhysicsShapeType PreferredPhysicalShape
|
||||||
{
|
{
|
||||||
get { return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; }
|
get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the physical properties are updated, an EntityProperty holds the update values.
|
// When the physical properties are updated, an EntityProperty holds the update values.
|
||||||
|
|
|
@ -47,7 +47,6 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
|
// _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
|
||||||
// Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
|
// Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
|
||||||
private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
|
private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
|
||||||
// private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
|
|
||||||
|
|
||||||
private bool _grabbed;
|
private bool _grabbed;
|
||||||
private bool _isSelected;
|
private bool _isSelected;
|
||||||
|
@ -88,13 +87,13 @@ public sealed class BSPrim : BSPhysObject
|
||||||
|
|
||||||
public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
|
public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
|
||||||
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
|
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
|
||||||
|
: base(parent_scene, localID, primName, "BSPrim")
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
|
// m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
|
||||||
base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
|
|
||||||
_physicsActorType = (int)ActorTypes.Prim;
|
_physicsActorType = (int)ActorTypes.Prim;
|
||||||
_position = pos;
|
_position = pos;
|
||||||
_size = size;
|
_size = size;
|
||||||
Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
|
Scale = size; // the scale will be set by CreateGeom depending on object type
|
||||||
_orientation = rotation;
|
_orientation = rotation;
|
||||||
_buoyancy = 1f;
|
_buoyancy = 1f;
|
||||||
_velocity = OMV.Vector3.Zero;
|
_velocity = OMV.Vector3.Zero;
|
||||||
|
@ -155,6 +154,8 @@ public sealed class BSPrim : BSPhysObject
|
||||||
public override OMV.Vector3 Size {
|
public override OMV.Vector3 Size {
|
||||||
get { return _size; }
|
get { return _size; }
|
||||||
set {
|
set {
|
||||||
|
// We presume the scale and size are the same. If scale must be changed for
|
||||||
|
// the physical shape, that is done when the geometry is built.
|
||||||
_size = value;
|
_size = value;
|
||||||
ForceBodyShapeRebuild(false);
|
ForceBodyShapeRebuild(false);
|
||||||
}
|
}
|
||||||
|
@ -170,7 +171,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Whatever the linkset wants is what I want.
|
// Whatever the linkset wants is what I want.
|
||||||
public override ShapeData.PhysicsShapeType PreferredPhysicalShape
|
public override BSPhysicsShapeType PreferredPhysicalShape
|
||||||
{ get { return Linkset.PreferredPhysicalShape(this); } }
|
{ get { return Linkset.PreferredPhysicalShape(this); } }
|
||||||
|
|
||||||
public override bool ForceBodyShapeRebuild(bool inTaintTime)
|
public override bool ForceBodyShapeRebuild(bool inTaintTime)
|
||||||
|
@ -274,19 +275,19 @@ public sealed class BSPrim : BSPhysObject
|
||||||
if (!Linkset.IsRoot(this))
|
if (!Linkset.IsRoot(this))
|
||||||
_position = Linkset.Position(this);
|
_position = Linkset.Position(this);
|
||||||
|
|
||||||
// don't do the GetObjectPosition for root elements because this function is called a zillion times
|
// don't do the GetObjectPosition for root elements because this function is called a zillion times.
|
||||||
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
|
// _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||||
return _position;
|
return _position;
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
// If you must push the position into the physics engine, use ForcePosition.
|
// If the position must be forced into the physics engine, use ForcePosition.
|
||||||
if (_position == value)
|
if (_position == value)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_position = value;
|
_position = value;
|
||||||
// TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
|
// TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
|
||||||
PositionSanityCheck();
|
PositionSanityCheck(false);
|
||||||
PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
|
PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
|
||||||
{
|
{
|
||||||
// DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
// DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||||
|
@ -302,7 +303,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
_position = value;
|
_position = value;
|
||||||
PositionSanityCheck();
|
// PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better.
|
||||||
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
|
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
|
||||||
ActivateIfPhysical(false);
|
ActivateIfPhysical(false);
|
||||||
}
|
}
|
||||||
|
@ -311,52 +312,42 @@ public sealed class BSPrim : BSPhysObject
|
||||||
// Check that the current position is sane and, if not, modify the position to make it so.
|
// Check that the current position is sane and, if not, modify the position to make it so.
|
||||||
// Check for being below terrain and being out of bounds.
|
// Check for being below terrain and being out of bounds.
|
||||||
// Returns 'true' of the position was made sane by some action.
|
// Returns 'true' of the position was made sane by some action.
|
||||||
private bool PositionSanityCheck()
|
private bool PositionSanityCheck(bool inTaintTime)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// If totally below the ground, move the prim up
|
|
||||||
// TODO: figure out the right solution for this... only for dynamic objects?
|
|
||||||
/*
|
|
||||||
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
|
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
|
||||||
|
OMV.Vector3 upForce = OMV.Vector3.Zero;
|
||||||
if (Position.Z < terrainHeight)
|
if (Position.Z < terrainHeight)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
||||||
_position.Z = terrainHeight + 2.0f;
|
float targetHeight = terrainHeight + (Size.Z / 2f);
|
||||||
|
// Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
|
||||||
|
upForce.Z = (terrainHeight - Position.Z) * 1f;
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
|
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
|
||||||
{
|
{
|
||||||
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
|
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
|
||||||
// TODO: a floating motor so object will bob in the water
|
// TODO: a floating motor so object will bob in the water
|
||||||
if (Position.Z < waterHeight)
|
if (Math.Abs(Position.Z - waterHeight) > 0.1f)
|
||||||
{
|
{
|
||||||
_position.Z = waterHeight;
|
// Upforce proportional to the distance away from the water. Correct the error in 1 sec.
|
||||||
|
upForce.Z = (waterHeight - Position.Z) * 1f;
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check for out of bounds
|
// TODO: check for out of bounds
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A version of the sanity check that also makes sure a new position value is
|
// The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
|
||||||
// pushed to the physics engine. This routine would be used by anyone
|
// TODO: This should be intergrated with a geneal physics action mechanism.
|
||||||
// who is not already pushing the value.
|
// TODO: This should be moderated with PID'ness.
|
||||||
private bool PositionSanityCheck(bool inTaintTime)
|
if (ret)
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
if (PositionSanityCheck())
|
|
||||||
{
|
{
|
||||||
// The new position value must be pushed into the physics engine but we can't
|
// Apply upforce and overcome gravity.
|
||||||
// just assign to "Position" because of potential call loops.
|
AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime);
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck", delegate()
|
|
||||||
{
|
|
||||||
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
|
||||||
ForcePosition = _position;
|
|
||||||
});
|
|
||||||
ret = true;
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -940,6 +931,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
public override void AddForce(OMV.Vector3 force, bool pushforce) {
|
public override void AddForce(OMV.Vector3 force, bool pushforce) {
|
||||||
AddForce(force, pushforce, false);
|
AddForce(force, pushforce, false);
|
||||||
}
|
}
|
||||||
|
// Applying a force just adds this to the total force on the object.
|
||||||
public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
||||||
// for an object, doesn't matter if force is a pushforce or not
|
// for an object, doesn't matter if force is a pushforce or not
|
||||||
if (force.IsFinite())
|
if (force.IsFinite())
|
||||||
|
@ -971,6 +963,7 @@ public sealed class BSPrim : BSPhysObject
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An impulse force is scaled by the mass of the object.
|
||||||
public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
|
public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
|
||||||
{
|
{
|
||||||
OMV.Vector3 applyImpulse = impulse;
|
OMV.Vector3 applyImpulse = impulse;
|
||||||
|
@ -1387,67 +1380,34 @@ public sealed class BSPrim : BSPhysObject
|
||||||
|
|
||||||
public override void UpdateProperties(EntityProperties entprop)
|
public override void UpdateProperties(EntityProperties entprop)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
UpdatedProperties changed = 0;
|
|
||||||
// assign to the local variables so the normal set action does not happen
|
|
||||||
// if (_position != entprop.Position)
|
|
||||||
if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
|
|
||||||
{
|
|
||||||
_position = entprop.Position;
|
|
||||||
changed |= UpdatedProperties.Position;
|
|
||||||
}
|
|
||||||
// if (_orientation != entprop.Rotation)
|
|
||||||
if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
|
|
||||||
{
|
|
||||||
_orientation = entprop.Rotation;
|
|
||||||
changed |= UpdatedProperties.Rotation;
|
|
||||||
}
|
|
||||||
// if (_velocity != entprop.Velocity)
|
|
||||||
if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
|
|
||||||
{
|
|
||||||
_velocity = entprop.Velocity;
|
|
||||||
changed |= UpdatedProperties.Velocity;
|
|
||||||
}
|
|
||||||
// if (_acceleration != entprop.Acceleration)
|
|
||||||
if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
|
|
||||||
{
|
|
||||||
_acceleration = entprop.Acceleration;
|
|
||||||
changed |= UpdatedProperties.Acceleration;
|
|
||||||
}
|
|
||||||
// if (_rotationalVelocity != entprop.RotationalVelocity)
|
|
||||||
if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
|
|
||||||
{
|
|
||||||
_rotationalVelocity = entprop.RotationalVelocity;
|
|
||||||
changed |= UpdatedProperties.RotationalVel;
|
|
||||||
}
|
|
||||||
if (changed != 0)
|
|
||||||
{
|
|
||||||
// Only update the position of single objects and linkset roots
|
|
||||||
if (this._parentPrim == null)
|
|
||||||
{
|
|
||||||
base.RequestPhysicsterseUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
|
|
||||||
|
|
||||||
// Updates only for individual prims and for the root object of a linkset.
|
// Updates only for individual prims and for the root object of a linkset.
|
||||||
if (Linkset.IsRoot(this))
|
if (Linkset.IsRoot(this))
|
||||||
{
|
{
|
||||||
// Assign to the local variables so the normal set action does not happen
|
// A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
|
||||||
|
// TODO: handle physics introduced by Bullet with computed vehicle physics.
|
||||||
|
if (_vehicle.IsActive)
|
||||||
|
{
|
||||||
|
entprop.RotationalVelocity = OMV.Vector3.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign directly to the local variables so the normal set action does not happen
|
||||||
_position = entprop.Position;
|
_position = entprop.Position;
|
||||||
_orientation = entprop.Rotation;
|
_orientation = entprop.Rotation;
|
||||||
_velocity = entprop.Velocity;
|
_velocity = entprop.Velocity;
|
||||||
_acceleration = entprop.Acceleration;
|
_acceleration = entprop.Acceleration;
|
||||||
_rotationalVelocity = entprop.RotationalVelocity;
|
_rotationalVelocity = entprop.RotationalVelocity;
|
||||||
|
|
||||||
|
// The sanity check can change the velocity and/or position.
|
||||||
|
if (PositionSanityCheck(true))
|
||||||
|
{
|
||||||
|
entprop.Position = _position;
|
||||||
|
entprop.Velocity = _velocity;
|
||||||
|
}
|
||||||
|
|
||||||
// remember the current and last set values
|
// remember the current and last set values
|
||||||
LastEntityProperties = CurrentEntityProperties;
|
LastEntityProperties = CurrentEntityProperties;
|
||||||
CurrentEntityProperties = entprop;
|
CurrentEntityProperties = entprop;
|
||||||
|
|
||||||
PositionSanityCheck(true);
|
|
||||||
|
|
||||||
OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
|
OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
|
||||||
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);
|
||||||
|
|
|
@ -39,23 +39,10 @@ using log4net;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
|
||||||
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
|
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
|
||||||
// Test sculpties (verified that they don't work)
|
|
||||||
// Compute physics FPS reasonably
|
|
||||||
// Based on material, set density and friction
|
// Based on material, set density and friction
|
||||||
// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
|
|
||||||
// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
|
|
||||||
// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
|
|
||||||
// At the moment, physical and phantom causes object to drop through the terrain
|
|
||||||
// Physical phantom objects and related typing (collision options )
|
|
||||||
// Check out llVolumeDetect. Must do something for that.
|
|
||||||
// Use collision masks for collision with terrain and phantom objects
|
|
||||||
// More efficient memory usage when passing hull information from BSPrim to BulletSim
|
// More efficient memory usage when passing hull information from BSPrim to BulletSim
|
||||||
// Should prim.link() and prim.delink() membership checking happen at taint time?
|
|
||||||
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
|
|
||||||
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
|
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
|
||||||
// Implement LockAngularMotion
|
// Implement LockAngularMotion
|
||||||
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
|
|
||||||
// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
|
|
||||||
// Add PID movement operations. What does ScenePresence.MoveToTarget do?
|
// Add PID movement operations. What does ScenePresence.MoveToTarget do?
|
||||||
// Check terrain size. 128 or 127?
|
// Check terrain size. 128 or 127?
|
||||||
// Raycast
|
// Raycast
|
||||||
|
@ -234,6 +221,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
if (m_physicsLoggingEnabled)
|
if (m_physicsLoggingEnabled)
|
||||||
{
|
{
|
||||||
PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
|
PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
|
||||||
|
PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -308,6 +296,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// Do any replacements in the parameters
|
// Do any replacements in the parameters
|
||||||
m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
|
m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The material characteristics.
|
||||||
|
BSMaterials.InitializeFromDefaults(Params);
|
||||||
|
if (pConfig != null)
|
||||||
|
{
|
||||||
|
BSMaterials.InitializefromParameters(pConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,9 +515,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
collidersCount = 0;
|
collidersCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
|
// Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
|
||||||
|
|
||||||
// Get a value for 'now' so all the collision and update routines don't have to get their own
|
// Get a value for 'now' so all the collision and update routines don't have to get their own.
|
||||||
SimulationNowTime = Util.EnvironmentTickCount();
|
SimulationNowTime = Util.EnvironmentTickCount();
|
||||||
|
|
||||||
// If there were collisions, process them by sending the event to the prim.
|
// If there were collisions, process them by sending the event to the prim.
|
||||||
|
@ -568,6 +563,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
ObjectsWithCollisions.Remove(po);
|
ObjectsWithCollisions.Remove(po);
|
||||||
ObjectsWithNoMoreCollisions.Clear();
|
ObjectsWithNoMoreCollisions.Clear();
|
||||||
}
|
}
|
||||||
|
// Done with collisions.
|
||||||
|
|
||||||
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
|
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
|
||||||
if (updatedEntityCount > 0)
|
if (updatedEntityCount > 0)
|
||||||
|
@ -591,9 +587,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
|
|
||||||
// The physics engine returns the number of milliseconds it simulated this call.
|
// The physics engine returns the number of milliseconds it simulated this call.
|
||||||
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
|
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
|
||||||
// We multiply by 55 to give a recognizable running rate (55 or less).
|
// Multiply by 55 to give a nominal frame rate of 55.
|
||||||
return numSubSteps * m_fixedTimeStep * 1000 * 55;
|
return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
|
||||||
// return timeStep * 1000 * 55;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Something has collided
|
// Something has collided
|
||||||
|
@ -683,7 +678,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
#region Taints
|
#region Taints
|
||||||
|
|
||||||
// Calls to the PhysicsActors can't directly call into the physics engine
|
// Calls to the PhysicsActors can't directly call into the physics engine
|
||||||
// because it might be busy. We delay changes to a known time.
|
// because it might be busy. We delay changes to a known time.
|
||||||
// We rely on C#'s closure to save and restore the context for the delegate.
|
// We rely on C#'s closure to save and restore the context for the delegate.
|
||||||
public void TaintedObject(String ident, TaintCallback callback)
|
public void TaintedObject(String ident, TaintCallback callback)
|
||||||
{
|
{
|
||||||
|
@ -712,7 +707,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// here just before the physics engine is called to step the simulation.
|
// here just before the physics engine is called to step the simulation.
|
||||||
public void ProcessTaints()
|
public void ProcessTaints()
|
||||||
{
|
{
|
||||||
InTaintTime = true;
|
InTaintTime = true; // Only used for debugging so locking is not necessary.
|
||||||
ProcessRegularTaints();
|
ProcessRegularTaints();
|
||||||
ProcessPostTaintTaints();
|
ProcessPostTaintTaints();
|
||||||
InTaintTime = false;
|
InTaintTime = false;
|
||||||
|
@ -758,6 +753,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
|
DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// swizzle a new list into the list location so we can process what's there
|
// swizzle a new list into the list location so we can process what's there
|
||||||
List<TaintCallbackEntry> oldList;
|
List<TaintCallbackEntry> oldList;
|
||||||
lock (_taintLock)
|
lock (_taintLock)
|
||||||
|
@ -787,8 +783,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
// will replace any previous operation by the same object.
|
// will replace any previous operation by the same object.
|
||||||
public void PostTaintObject(String ident, uint ID, TaintCallback callback)
|
public void PostTaintObject(String ident, uint ID, TaintCallback callback)
|
||||||
{
|
{
|
||||||
if (!m_initialized) return;
|
|
||||||
|
|
||||||
string uniqueIdent = ident + "-" + ID.ToString();
|
string uniqueIdent = ident + "-" + ID.ToString();
|
||||||
lock (_taintLock)
|
lock (_taintLock)
|
||||||
{
|
{
|
||||||
|
@ -864,13 +858,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only used for debugging. Does not change state of anything so locking is not necessary.
|
||||||
public bool AssertInTaintTime(string whereFrom)
|
public bool AssertInTaintTime(string whereFrom)
|
||||||
{
|
{
|
||||||
if (!InTaintTime)
|
if (!InTaintTime)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
|
DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
|
||||||
m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
|
m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
|
||||||
Util.PrintCallStack();
|
Util.PrintCallStack(); // Prints the stack into the DEBUG log file.
|
||||||
}
|
}
|
||||||
return InTaintTime;
|
return InTaintTime;
|
||||||
}
|
}
|
||||||
|
@ -1069,7 +1064,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s,p,l,v) => { s.PID_P = v; } ),
|
(s,p,l,v) => { s.PID_P = v; } ),
|
||||||
|
|
||||||
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
|
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
|
||||||
0.5f,
|
0.2f,
|
||||||
(s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].defaultFriction; },
|
(s) => { return s.m_params[0].defaultFriction; },
|
||||||
(s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
|
(s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
|
||||||
|
@ -1084,7 +1079,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s) => { return s.m_params[0].defaultRestitution; },
|
(s) => { return s.m_params[0].defaultRestitution; },
|
||||||
(s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
|
(s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
|
||||||
new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
|
new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
|
||||||
0f,
|
0.04f,
|
||||||
(s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].collisionMargin; },
|
(s) => { return s.m_params[0].collisionMargin; },
|
||||||
(s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
|
(s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
|
||||||
|
@ -1145,8 +1140,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
|
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
|
||||||
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
|
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
|
||||||
|
|
||||||
|
new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
|
||||||
|
(float)BSTerrainPhys.TerrainImplementation.Mesh,
|
||||||
|
(s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); },
|
||||||
|
(s) => { return s.m_params[0].terrainImplementation; },
|
||||||
|
(s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
|
||||||
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
|
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
|
||||||
0.5f,
|
0.3f,
|
||||||
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].terrainFriction; },
|
(s) => { return s.m_params[0].terrainFriction; },
|
||||||
(s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
|
(s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
|
||||||
|
@ -1160,13 +1160,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].terrainRestitution; },
|
(s) => { return s.m_params[0].terrainRestitution; },
|
||||||
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
|
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
|
||||||
|
new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
|
||||||
|
0.04f,
|
||||||
|
(s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); },
|
||||||
|
(s) => { return s.m_params[0].terrainCollisionMargin; },
|
||||||
|
(s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
|
||||||
|
|
||||||
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
|
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
|
||||||
0.2f,
|
0.2f,
|
||||||
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].avatarFriction; },
|
(s) => { return s.m_params[0].avatarFriction; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
|
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
|
||||||
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
|
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
|
||||||
10f,
|
10.0f,
|
||||||
(s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].avatarStandingFriction; },
|
(s) => { return s.m_params[0].avatarStandingFriction; },
|
||||||
(s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
|
(s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
|
||||||
|
@ -1180,11 +1186,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].avatarRestitution; },
|
(s) => { return s.m_params[0].avatarRestitution; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
|
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
|
||||||
new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
|
new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
|
||||||
0.37f,
|
0.6f,
|
||||||
(s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); },
|
||||||
(s) => { return s.m_params[0].avatarCapsuleRadius; },
|
(s) => { return s.m_params[0].avatarCapsuleWidth; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
|
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ),
|
||||||
|
new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
|
||||||
|
0.45f,
|
||||||
|
(s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); },
|
||||||
|
(s) => { return s.m_params[0].avatarCapsuleDepth; },
|
||||||
|
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ),
|
||||||
new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
|
new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
|
||||||
1.5f,
|
1.5f,
|
||||||
(s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
|
(s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
|
||||||
|
@ -1196,6 +1207,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||||
(s) => { return s.m_params[0].avatarContactProcessingThreshold; },
|
(s) => { return s.m_params[0].avatarContactProcessingThreshold; },
|
||||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
|
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
|
||||||
|
|
||||||
|
new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
|
||||||
|
0.95f,
|
||||||
|
(s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
|
||||||
|
(s) => { return s.m_params[0].vehicleAngularDamping; },
|
||||||
|
(s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
|
||||||
|
|
||||||
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
|
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
|
||||||
0f,
|
0f,
|
||||||
|
|
|
@ -178,7 +178,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
switch (shape.type)
|
switch (shape.type)
|
||||||
{
|
{
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
case BSPhysicsShapeType.SHAPE_MESH:
|
||||||
MeshDesc meshDesc;
|
MeshDesc meshDesc;
|
||||||
if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
|
if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
|
||||||
{
|
{
|
||||||
|
@ -201,7 +201,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
meshDesc.lastReferenced = System.DateTime.Now;
|
meshDesc.lastReferenced = System.DateTime.Now;
|
||||||
Meshes[shape.shapeKey] = meshDesc;
|
Meshes[shape.shapeKey] = meshDesc;
|
||||||
break;
|
break;
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
case BSPhysicsShapeType.SHAPE_HULL:
|
||||||
HullDesc hullDesc;
|
HullDesc hullDesc;
|
||||||
if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
|
if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
|
||||||
{
|
{
|
||||||
|
@ -224,7 +224,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
hullDesc.lastReferenced = System.DateTime.Now;
|
hullDesc.lastReferenced = System.DateTime.Now;
|
||||||
Hulls[shape.shapeKey] = hullDesc;
|
Hulls[shape.shapeKey] = hullDesc;
|
||||||
break;
|
break;
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
case BSPhysicsShapeType.SHAPE_UNKNOWN:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Native shapes are not tracked and they don't go into any list
|
// Native shapes are not tracked and they don't go into any list
|
||||||
|
@ -255,16 +255,16 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
{
|
{
|
||||||
switch (shape.type)
|
switch (shape.type)
|
||||||
{
|
{
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
case BSPhysicsShapeType.SHAPE_HULL:
|
||||||
DereferenceHull(shape, shapeCallback);
|
DereferenceHull(shape, shapeCallback);
|
||||||
break;
|
break;
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
case BSPhysicsShapeType.SHAPE_MESH:
|
||||||
DereferenceMesh(shape, shapeCallback);
|
DereferenceMesh(shape, shapeCallback);
|
||||||
break;
|
break;
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_COMPOUND:
|
case BSPhysicsShapeType.SHAPE_COMPOUND:
|
||||||
DereferenceCompound(shape, shapeCallback);
|
DereferenceCompound(shape, shapeCallback);
|
||||||
break;
|
break;
|
||||||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
case BSPhysicsShapeType.SHAPE_UNKNOWN:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -352,28 +352,28 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
BulletShape shapeInfo = new BulletShape(cShape);
|
BulletShape shapeInfo = new BulletShape(cShape);
|
||||||
if (TryGetMeshByPtr(cShape, out meshDesc))
|
if (TryGetMeshByPtr(cShape, out meshDesc))
|
||||||
{
|
{
|
||||||
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_MESH;
|
shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
|
||||||
shapeInfo.shapeKey = meshDesc.shapeKey;
|
shapeInfo.shapeKey = meshDesc.shapeKey;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (TryGetHullByPtr(cShape, out hullDesc))
|
if (TryGetHullByPtr(cShape, out hullDesc))
|
||||||
{
|
{
|
||||||
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_HULL;
|
shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
|
||||||
shapeInfo.shapeKey = hullDesc.shapeKey;
|
shapeInfo.shapeKey = hullDesc.shapeKey;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (BulletSimAPI.IsCompound2(cShape))
|
if (BulletSimAPI.IsCompound2(cShape))
|
||||||
{
|
{
|
||||||
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_COMPOUND;
|
shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (BulletSimAPI.IsNativeShape2(cShape))
|
if (BulletSimAPI.IsNativeShape2(cShape))
|
||||||
{
|
{
|
||||||
shapeInfo.isNativeShape = true;
|
shapeInfo.isNativeShape = true;
|
||||||
shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
|
shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,7 +381,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
|
DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
|
||||||
|
|
||||||
if (shapeInfo.type != ShapeData.PhysicsShapeType.SHAPE_UNKNOWN)
|
if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
|
||||||
{
|
{
|
||||||
DereferenceShape(shapeInfo, true, null);
|
DereferenceShape(shapeInfo, true, null);
|
||||||
}
|
}
|
||||||
|
@ -405,11 +405,11 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
bool haveShape = false;
|
bool haveShape = false;
|
||||||
|
|
||||||
if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
|
||||||
{
|
{
|
||||||
// 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, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
|
ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
|
||||||
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
|
FixedShapeKey.KEY_CAPSULE, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
|
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
|
||||||
ret = true;
|
ret = true;
|
||||||
haveShape = true;
|
haveShape = true;
|
||||||
|
@ -417,7 +417,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
// Compound shapes are handled special as they are rebuilt from scratch.
|
// Compound shapes are handled special as they are rebuilt from scratch.
|
||||||
// This isn't too great a hardship since most of the child shapes will already been created.
|
// This isn't too great a hardship since most of the child shapes will already been created.
|
||||||
if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.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);
|
DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
|
||||||
|
@ -460,11 +460,11 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
haveShape = true;
|
haveShape = true;
|
||||||
if (forceRebuild
|
if (forceRebuild
|
||||||
|| prim.Scale != prim.Size
|
|| prim.Scale != prim.Size
|
||||||
|| prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
|
|| prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
|
ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
|
||||||
ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
|
FixedShapeKey.KEY_SPHERE, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
|
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
|
||||||
prim.LocalID, forceRebuild, prim.PhysShape);
|
prim.LocalID, forceRebuild, prim.PhysShape);
|
||||||
}
|
}
|
||||||
|
@ -474,11 +474,11 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
haveShape = true;
|
haveShape = true;
|
||||||
if (forceRebuild
|
if (forceRebuild
|
||||||
|| prim.Scale != prim.Size
|
|| prim.Scale != prim.Size
|
||||||
|| prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
|
|| prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ret = GetReferenceToNativeShape( prim, ShapeData.PhysicsShapeType.SHAPE_BOX,
|
ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
|
||||||
ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
|
FixedShapeKey.KEY_BOX, shapeCallback);
|
||||||
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
|
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
|
||||||
prim.LocalID, forceRebuild, prim.PhysShape);
|
prim.LocalID, forceRebuild, prim.PhysShape);
|
||||||
}
|
}
|
||||||
|
@ -519,15 +519,12 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
// Creates a native shape and assignes it to prim.BSShape.
|
// Creates a native shape and assignes it to prim.BSShape.
|
||||||
// "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
|
// "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
|
||||||
private bool GetReferenceToNativeShape(BSPhysObject prim,
|
private bool GetReferenceToNativeShape(BSPhysObject prim,
|
||||||
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
|
||||||
ShapeDestructionCallback shapeCallback)
|
ShapeDestructionCallback shapeCallback)
|
||||||
{
|
{
|
||||||
// release any previous shape
|
// release any previous shape
|
||||||
DereferenceShape(prim.PhysShape, true, shapeCallback);
|
DereferenceShape(prim.PhysShape, true, shapeCallback);
|
||||||
|
|
||||||
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
|
||||||
prim.Scale = prim.Size;
|
|
||||||
|
|
||||||
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.
|
||||||
|
@ -538,8 +535,8 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, ShapeData.PhysicsShapeType shapeType,
|
private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
|
||||||
ShapeData.FixedShapeKey shapeKey)
|
FixedShapeKey shapeKey)
|
||||||
{
|
{
|
||||||
BulletShape newShape;
|
BulletShape newShape;
|
||||||
// Need to make sure the passed shape information is for the native type.
|
// Need to make sure the passed shape information is for the native type.
|
||||||
|
@ -547,12 +544,13 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
nativeShapeData.Type = shapeType;
|
nativeShapeData.Type = shapeType;
|
||||||
nativeShapeData.ID = prim.LocalID;
|
nativeShapeData.ID = prim.LocalID;
|
||||||
nativeShapeData.Scale = prim.Scale;
|
nativeShapeData.Scale = prim.Scale;
|
||||||
nativeShapeData.Size = prim.Scale;
|
nativeShapeData.Size = prim.Scale; // unneeded, I think.
|
||||||
nativeShapeData.MeshKey = (ulong)shapeKey;
|
nativeShapeData.MeshKey = (ulong)shapeKey;
|
||||||
nativeShapeData.HullKey = (ulong)shapeKey;
|
nativeShapeData.HullKey = (ulong)shapeKey;
|
||||||
|
|
||||||
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
|
||||||
{
|
{
|
||||||
|
// The proper scale has been calculated in the prim.
|
||||||
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);
|
||||||
|
@ -560,6 +558,9 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Native shapes are scaled in Bullet so set the scaling to the size
|
||||||
|
prim.Scale = prim.Size;
|
||||||
|
nativeShapeData.Scale = prim.Scale;
|
||||||
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
|
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
|
||||||
}
|
}
|
||||||
if (newShape.ptr == IntPtr.Zero)
|
if (newShape.ptr == IntPtr.Zero)
|
||||||
|
@ -585,7 +586,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
|
System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
|
||||||
|
|
||||||
// if this new shape is the same as last time, don't recreate the mesh
|
// if this new shape is the same as last time, don't recreate the mesh
|
||||||
if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.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}",
|
DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
|
||||||
|
@ -643,7 +644,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
|
BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
|
||||||
newShape.shapeKey = newMeshKey;
|
newShape.shapeKey = newMeshKey;
|
||||||
|
|
||||||
return newShape;
|
return newShape;
|
||||||
|
@ -659,7 +660,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
|
System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
|
||||||
|
|
||||||
// if the hull hasn't changed, don't rebuild it
|
// if the hull hasn't changed, don't rebuild it
|
||||||
if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.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}",
|
DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
|
||||||
|
@ -780,7 +781,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
|
BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
|
||||||
newShape.shapeKey = newHullKey;
|
newShape.shapeKey = newHullKey;
|
||||||
|
|
||||||
return newShape; // 'true' means a new shape has been added to this prim
|
return newShape; // 'true' means a new shape has been added to this prim
|
||||||
|
@ -803,7 +804,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
// DereferenceShape(prim.PhysShape, true, shapeCallback);
|
// DereferenceShape(prim.PhysShape, true, shapeCallback);
|
||||||
|
|
||||||
BulletShape cShape = new BulletShape(
|
BulletShape cShape = new BulletShape(
|
||||||
BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), ShapeData.PhysicsShapeType.SHAPE_COMPOUND);
|
BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
|
||||||
|
|
||||||
// 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);
|
||||||
|
@ -894,7 +895,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
|
|
||||||
// While we figure out the real problem, stick a simple native shape on the object.
|
// While we figure out the real problem, stick a simple native shape on the object.
|
||||||
BulletShape fillinShape =
|
BulletShape fillinShape =
|
||||||
BuildPhysicalNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX);
|
BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
|
||||||
|
|
||||||
return fillinShape;
|
return fillinShape;
|
||||||
}
|
}
|
||||||
|
@ -940,7 +941,7 @@ public sealed class BSShapeCollection : IDisposable
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
|
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
|
||||||
prim.LocalID, prim.ForcePosition, prim.ForceOrientation);
|
prim.LocalID, prim.RawPosition, prim.RawOrientation);
|
||||||
DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
|
||||||
}
|
}
|
||||||
aBody = new BulletBody(prim.LocalID, bodyPtr);
|
aBody = new BulletBody(prim.LocalID, bodyPtr);
|
||||||
|
|
|
@ -1,213 +1,208 @@
|
||||||
/*
|
/*
|
||||||
* 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.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
public abstract class BSShape
|
public abstract class BSShape
|
||||||
{
|
{
|
||||||
public IntPtr ptr { get; set; }
|
public IntPtr ptr { get; set; }
|
||||||
public ShapeData.PhysicsShapeType type { get; set; }
|
public BSPhysicsShapeType type { get; set; }
|
||||||
public System.UInt64 key { get; set; }
|
public System.UInt64 key { get; set; }
|
||||||
public int referenceCount { get; set; }
|
public int referenceCount { get; set; }
|
||||||
public DateTime lastReferenced { get; set; }
|
public DateTime lastReferenced { get; set; }
|
||||||
|
|
||||||
protected void Initialize()
|
public BSShape()
|
||||||
{
|
{
|
||||||
ptr = IntPtr.Zero;
|
ptr = IntPtr.Zero;
|
||||||
type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
|
type = BSPhysicsShapeType.SHAPE_UNKNOWN;
|
||||||
key = 0;
|
key = 0;
|
||||||
referenceCount = 0;
|
referenceCount = 0;
|
||||||
lastReferenced = DateTime.Now;
|
lastReferenced = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a reference to a physical shape. Create if it doesn't exist
|
// Get a reference to a physical shape. Create if it doesn't exist
|
||||||
public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
|
public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
|
||||||
{
|
{
|
||||||
BSShape ret = null;
|
BSShape ret = null;
|
||||||
|
|
||||||
if (prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
|
||||||
{
|
{
|
||||||
// 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 = BSShapeNative.GetReference(physicsScene, prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
|
ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
|
||||||
ShapeData.FixedShapeKey.KEY_CAPSULE);
|
FixedShapeKey.KEY_CAPSULE);
|
||||||
physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
|
physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compound shapes are handled special as they are rebuilt from scratch.
|
// Compound shapes are handled special as they are rebuilt from scratch.
|
||||||
// This isn't too great a hardship since most of the child shapes will already been created.
|
// This isn't too great a hardship since most of the child shapes will already been created.
|
||||||
if (ret == null && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND)
|
if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
|
||||||
{
|
{
|
||||||
// Getting a reference to a compound shape gets you the compound shape with the root prim shape added
|
// Getting a reference to a compound shape gets you the compound shape with the root prim shape added
|
||||||
ret = BSShapeCompound.GetReference(prim);
|
ret = BSShapeCompound.GetReference(prim);
|
||||||
physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
|
physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
|
ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
|
public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
|
public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the use of a physical shape.
|
// Release the use of a physical shape.
|
||||||
public abstract void Dereference(BSScene physicsScene);
|
public abstract void Dereference(BSScene physicsScene);
|
||||||
|
|
||||||
// All shapes have a static call to get a reference to the physical shape
|
// All shapes have a static call to get a reference to the physical shape
|
||||||
// protected abstract static BSShape GetReference();
|
// protected abstract static BSShape GetReference();
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
StringBuilder buff = new StringBuilder();
|
StringBuilder buff = new StringBuilder();
|
||||||
buff.Append("<p=");
|
buff.Append("<p=");
|
||||||
buff.Append(ptr.ToString("X"));
|
buff.Append(ptr.ToString("X"));
|
||||||
buff.Append(",s=");
|
buff.Append(",s=");
|
||||||
buff.Append(type.ToString());
|
buff.Append(type.ToString());
|
||||||
buff.Append(",k=");
|
buff.Append(",k=");
|
||||||
buff.Append(key.ToString("X"));
|
buff.Append(key.ToString("X"));
|
||||||
buff.Append(",c=");
|
buff.Append(",c=");
|
||||||
buff.Append(referenceCount.ToString());
|
buff.Append(referenceCount.ToString());
|
||||||
buff.Append(">");
|
buff.Append(">");
|
||||||
return buff.ToString();
|
return buff.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BSShapeNull : BSShape
|
public class BSShapeNull : BSShape
|
||||||
{
|
{
|
||||||
public BSShapeNull()
|
public BSShapeNull() : base()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
}
|
||||||
}
|
public static BSShape GetReference() { return new BSShapeNull(); }
|
||||||
public static BSShape GetReference() { return new BSShapeNull(); }
|
public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
|
||||||
public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
|
}
|
||||||
}
|
|
||||||
|
public class BSShapeNative : BSShape
|
||||||
public class BSShapeNative : BSShape
|
{
|
||||||
{
|
private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
|
||||||
private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
|
public BSShapeNative() : base()
|
||||||
public BSShapeNative()
|
{
|
||||||
{
|
}
|
||||||
base.Initialize();
|
public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
|
||||||
}
|
BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
|
||||||
public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
|
{
|
||||||
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey)
|
// Native shapes are not shared and are always built anew.
|
||||||
{
|
return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
|
||||||
// Native shapes are not shared and are always built anew.
|
}
|
||||||
return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
|
|
||||||
}
|
private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
|
||||||
|
BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
|
||||||
private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
|
{
|
||||||
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey)
|
ShapeData nativeShapeData = new ShapeData();
|
||||||
{
|
nativeShapeData.Type = shapeType;
|
||||||
ShapeData nativeShapeData = new ShapeData();
|
nativeShapeData.ID = prim.LocalID;
|
||||||
nativeShapeData.Type = shapeType;
|
nativeShapeData.Scale = prim.Scale;
|
||||||
nativeShapeData.ID = prim.LocalID;
|
nativeShapeData.Size = prim.Scale;
|
||||||
nativeShapeData.Scale = prim.Scale;
|
nativeShapeData.MeshKey = (ulong)shapeKey;
|
||||||
nativeShapeData.Size = prim.Scale;
|
nativeShapeData.HullKey = (ulong)shapeKey;
|
||||||
nativeShapeData.MeshKey = (ulong)shapeKey;
|
|
||||||
nativeShapeData.HullKey = (ulong)shapeKey;
|
|
||||||
|
if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
|
||||||
|
{
|
||||||
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
|
||||||
{
|
physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
|
||||||
ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
|
}
|
||||||
physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
|
else
|
||||||
}
|
{
|
||||||
else
|
ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData);
|
||||||
{
|
}
|
||||||
ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData);
|
if (ptr == IntPtr.Zero)
|
||||||
}
|
{
|
||||||
if (ptr == IntPtr.Zero)
|
physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
|
||||||
{
|
LogHeader, prim.LocalID, shapeType);
|
||||||
physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
|
}
|
||||||
LogHeader, prim.LocalID, shapeType);
|
type = shapeType;
|
||||||
}
|
key = (UInt64)shapeKey;
|
||||||
type = shapeType;
|
}
|
||||||
key = (UInt64)shapeKey;
|
// Make this reference to the physical shape go away since native shapes are not shared.
|
||||||
}
|
public override void Dereference(BSScene physicsScene)
|
||||||
// Make this reference to the physical shape go away since native shapes are not shared.
|
{
|
||||||
public override void Dereference(BSScene physicsScene)
|
// Native shapes are not tracked and are released immediately
|
||||||
{
|
physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
|
||||||
// Native shapes are not tracked and are released immediately
|
BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr);
|
||||||
physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
|
ptr = IntPtr.Zero;
|
||||||
BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr);
|
// Garbage collection will free up this instance.
|
||||||
ptr = IntPtr.Zero;
|
}
|
||||||
// Garbage collection will free up this instance.
|
}
|
||||||
}
|
|
||||||
}
|
public class BSShapeMesh : BSShape
|
||||||
|
{
|
||||||
public class BSShapeMesh : BSShape
|
private static string LogHeader = "[BULLETSIM SHAPE MESH]";
|
||||||
{
|
private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
|
||||||
private static string LogHeader = "[BULLETSIM SHAPE MESH]";
|
|
||||||
private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
|
public BSShapeMesh() : base()
|
||||||
|
{
|
||||||
public BSShapeMesh()
|
}
|
||||||
{
|
public static BSShape GetReference() { return new BSShapeNull(); }
|
||||||
base.Initialize();
|
public override void Dereference(BSScene physicsScene) { }
|
||||||
}
|
}
|
||||||
public static BSShape GetReference() { return new BSShapeNull(); }
|
|
||||||
public override void Dereference(BSScene physicsScene) { }
|
public class BSShapeHull : BSShape
|
||||||
}
|
{
|
||||||
|
private static string LogHeader = "[BULLETSIM SHAPE HULL]";
|
||||||
public class BSShapeHull : BSShape
|
private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
|
||||||
{
|
|
||||||
private static string LogHeader = "[BULLETSIM SHAPE HULL]";
|
public BSShapeHull() : base()
|
||||||
private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
|
{
|
||||||
|
}
|
||||||
public BSShapeHull()
|
public static BSShape GetReference() { return new BSShapeNull(); }
|
||||||
{
|
public override void Dereference(BSScene physicsScene) { }
|
||||||
base.Initialize();
|
}
|
||||||
}
|
|
||||||
public static BSShape GetReference() { return new BSShapeNull(); }
|
public class BSShapeCompound : BSShape
|
||||||
public override void Dereference(BSScene physicsScene) { }
|
{
|
||||||
}
|
private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
|
||||||
|
public BSShapeCompound() : base()
|
||||||
public class BSShapeCompound : BSShape
|
{
|
||||||
{
|
}
|
||||||
private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
|
public static BSShape GetReference(BSPhysObject prim)
|
||||||
public BSShapeCompound()
|
{
|
||||||
{
|
return new BSShapeNull();
|
||||||
base.Initialize();
|
}
|
||||||
}
|
public override void Dereference(BSScene physicsScene) { }
|
||||||
public static BSShape GetReference(BSPhysObject prim)
|
}
|
||||||
{
|
}
|
||||||
return new BSShapeNull();
|
|
||||||
}
|
|
||||||
public override void Dereference(BSScene physicsScene) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyrightD
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Framework;
|
||||||
|
using OpenSim.Region.CoreModules;
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
using Nini.Config;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
|
using OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||||
|
{
|
||||||
|
static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
|
||||||
|
|
||||||
|
BulletHeightMapInfo m_mapInfo = null;
|
||||||
|
|
||||||
|
// Constructor to build a default, flat heightmap terrain.
|
||||||
|
public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
|
||||||
|
: base(physicsScene, regionBase, id)
|
||||||
|
{
|
||||||
|
Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
|
||||||
|
Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
|
||||||
|
int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
|
||||||
|
float[] initialMap = new float[totalHeights];
|
||||||
|
for (int ii = 0; ii < totalHeights; ii++)
|
||||||
|
{
|
||||||
|
initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
|
||||||
|
}
|
||||||
|
m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
|
||||||
|
m_mapInfo.minCoords = minTerrainCoords;
|
||||||
|
m_mapInfo.maxCoords = maxTerrainCoords;
|
||||||
|
m_mapInfo.terrainRegionBase = TerrainBase;
|
||||||
|
// Don't have to free any previous since we just got here.
|
||||||
|
BuildHeightmapTerrain();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This minCoords and maxCoords passed in give the size of the terrain (min and max Z
|
||||||
|
// are the high and low points of the heightmap).
|
||||||
|
public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
|
||||||
|
Vector3 minCoords, Vector3 maxCoords)
|
||||||
|
: base(physicsScene, regionBase, id)
|
||||||
|
{
|
||||||
|
m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
|
||||||
|
m_mapInfo.minCoords = minCoords;
|
||||||
|
m_mapInfo.maxCoords = maxCoords;
|
||||||
|
m_mapInfo.minZ = minCoords.Z;
|
||||||
|
m_mapInfo.maxZ = maxCoords.Z;
|
||||||
|
m_mapInfo.terrainRegionBase = TerrainBase;
|
||||||
|
|
||||||
|
// Don't have to free any previous since we just got here.
|
||||||
|
BuildHeightmapTerrain();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
ReleaseHeightMapTerrain();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using the information in m_mapInfo, create the physical representation of the heightmap.
|
||||||
|
private void BuildHeightmapTerrain()
|
||||||
|
{
|
||||||
|
m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
|
||||||
|
m_mapInfo.minCoords, m_mapInfo.maxCoords,
|
||||||
|
m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
|
||||||
|
|
||||||
|
// Create the terrain shape from the mapInfo
|
||||||
|
m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
|
||||||
|
BSPhysicsShapeType.SHAPE_TERRAIN);
|
||||||
|
|
||||||
|
// The terrain object initial position is at the center of the object
|
||||||
|
Vector3 centerPos;
|
||||||
|
centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
|
||||||
|
centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
|
||||||
|
centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
|
||||||
|
|
||||||
|
m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID,
|
||||||
|
BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr,
|
||||||
|
m_mapInfo.ID, centerPos, Quaternion.Identity));
|
||||||
|
|
||||||
|
// Set current terrain attributes
|
||||||
|
BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
|
||||||
|
BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
|
||||||
|
BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
|
||||||
|
BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
|
||||||
|
|
||||||
|
// Return the new terrain to the world of physical objects
|
||||||
|
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
|
||||||
|
|
||||||
|
// redo its bounding box now that it is in the world
|
||||||
|
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
|
||||||
|
|
||||||
|
BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr,
|
||||||
|
(uint)CollisionFilterGroups.TerrainFilter,
|
||||||
|
(uint)CollisionFilterGroups.TerrainMask);
|
||||||
|
|
||||||
|
// Make it so the terrain will not move or be considered for movement.
|
||||||
|
BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is information in m_mapInfo pointing to physical structures, release same.
|
||||||
|
private void ReleaseHeightMapTerrain()
|
||||||
|
{
|
||||||
|
if (m_mapInfo != null)
|
||||||
|
{
|
||||||
|
if (m_mapInfo.terrainBody.ptr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
|
||||||
|
// Frees both the body and the shape.
|
||||||
|
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
|
||||||
|
BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_mapInfo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The passed position is relative to the base of the region.
|
||||||
|
public override float GetHeightAtXYZ(Vector3 pos)
|
||||||
|
{
|
||||||
|
float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
|
||||||
|
|
||||||
|
int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ret = m_mapInfo.heightMap[mapIndex];
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
||||||
|
PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
|
||||||
|
LogHeader, m_mapInfo.terrainRegionBase, pos);
|
||||||
|
ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,32 @@ using OpenMetaverse;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// The physical implementation of the terrain is wrapped in this class.
|
||||||
|
public abstract class BSTerrainPhys : IDisposable
|
||||||
|
{
|
||||||
|
public enum TerrainImplementation
|
||||||
|
{
|
||||||
|
Heightmap = 0,
|
||||||
|
Mesh = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public BSScene PhysicsScene { get; private set; }
|
||||||
|
// Base of the region in world coordinates. Coordinates inside the region are relative to this.
|
||||||
|
public Vector3 TerrainBase { get; private set; }
|
||||||
|
public uint ID { get; private set; }
|
||||||
|
|
||||||
|
public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
|
||||||
|
{
|
||||||
|
PhysicsScene = physicsScene;
|
||||||
|
TerrainBase = regionBase;
|
||||||
|
ID = id;
|
||||||
|
}
|
||||||
|
public abstract void Dispose();
|
||||||
|
public abstract float GetHeightAtXYZ(Vector3 pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================================
|
||||||
public sealed class BSTerrainManager
|
public sealed class BSTerrainManager
|
||||||
{
|
{
|
||||||
static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
|
static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
|
||||||
|
@ -54,8 +80,6 @@ public sealed class BSTerrainManager
|
||||||
// amount to make sure that a bounding box is built for the terrain.
|
// amount to make sure that a bounding box is built for the terrain.
|
||||||
public const float HEIGHT_EQUAL_FUDGE = 0.2f;
|
public const float HEIGHT_EQUAL_FUDGE = 0.2f;
|
||||||
|
|
||||||
public const float TERRAIN_COLLISION_MARGIN = 0.0f;
|
|
||||||
|
|
||||||
// Until the whole simulator is changed to pass us the region size, we rely on constants.
|
// Until the whole simulator is changed to pass us the region size, we rely on constants.
|
||||||
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||||
|
|
||||||
|
@ -67,11 +91,10 @@ public sealed class BSTerrainManager
|
||||||
|
|
||||||
// If doing mega-regions, if we're region zero we will be managing multiple
|
// If doing mega-regions, if we're region zero we will be managing multiple
|
||||||
// region terrains since region zero does the physics for the whole mega-region.
|
// region terrains since region zero does the physics for the whole mega-region.
|
||||||
private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
|
private Dictionary<Vector3, BSTerrainPhys> m_terrains;
|
||||||
|
|
||||||
// True of the terrain has been modified.
|
// Flags used to know when to recalculate the height.
|
||||||
// Used to force recalculation of terrain height after terrain has been modified
|
private bool m_terrainModified = false;
|
||||||
private bool m_terrainModified;
|
|
||||||
|
|
||||||
// If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
|
// If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
|
||||||
// This is incremented before assigning to new region so it is the last ID allocated.
|
// This is incremented before assigning to new region so it is the last ID allocated.
|
||||||
|
@ -89,8 +112,7 @@ public sealed class BSTerrainManager
|
||||||
public BSTerrainManager(BSScene physicsScene)
|
public BSTerrainManager(BSScene physicsScene)
|
||||||
{
|
{
|
||||||
PhysicsScene = physicsScene;
|
PhysicsScene = physicsScene;
|
||||||
m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
|
m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
|
||||||
m_terrainModified = false;
|
|
||||||
|
|
||||||
// Assume one region of default size
|
// Assume one region of default size
|
||||||
m_worldOffset = Vector3.Zero;
|
m_worldOffset = Vector3.Zero;
|
||||||
|
@ -99,17 +121,15 @@ public sealed class BSTerrainManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the initial instance of terrain and the underlying ground plane.
|
// Create the initial instance of terrain and the underlying ground plane.
|
||||||
// The objects are allocated in the unmanaged space and the pointers are tracked
|
|
||||||
// by the managed code.
|
|
||||||
// The terrains and the groundPlane are not added to the list of PhysObjects.
|
|
||||||
// This is called from the initialization routine so we presume it is
|
// This is called from the initialization routine so we presume it is
|
||||||
// safe to call Bullet in real time. We hope no one is moving prims around yet.
|
// safe to call Bullet in real time. We hope no one is moving prims around yet.
|
||||||
public void CreateInitialGroundPlaneAndTerrain()
|
public void CreateInitialGroundPlaneAndTerrain()
|
||||||
{
|
{
|
||||||
// The ground plane is here to catch things that are trying to drop to negative infinity
|
// The ground plane is here to catch things that are trying to drop to negative infinity
|
||||||
BulletShape groundPlaneShape = new BulletShape(
|
BulletShape groundPlaneShape = new BulletShape(
|
||||||
BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
|
BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
|
||||||
ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE);
|
PhysicsScene.Params.terrainCollisionMargin),
|
||||||
|
BSPhysicsShapeType.SHAPE_GROUNDPLANE);
|
||||||
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
|
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
|
||||||
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
|
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
|
||||||
Vector3.Zero, Quaternion.Identity));
|
Vector3.Zero, Quaternion.Identity));
|
||||||
|
@ -121,15 +141,9 @@ public sealed class BSTerrainManager
|
||||||
BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
|
BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
|
||||||
(uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
|
(uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
|
||||||
|
|
||||||
Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
|
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
|
||||||
Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
|
BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
|
||||||
int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
|
m_terrains.Add(Vector3.Zero, initialTerrain);
|
||||||
float[] initialMap = new float[totalHeights];
|
|
||||||
for (int ii = 0; ii < totalHeights; ii++)
|
|
||||||
{
|
|
||||||
initialMap[ii] = HEIGHT_INITIALIZATION;
|
|
||||||
}
|
|
||||||
UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release all the terrain structures we might have allocated
|
// Release all the terrain structures we might have allocated
|
||||||
|
@ -150,21 +164,22 @@ public sealed class BSTerrainManager
|
||||||
// Release all the terrain we have allocated
|
// Release all the terrain we have allocated
|
||||||
public void ReleaseTerrain()
|
public void ReleaseTerrain()
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
|
lock (m_terrains)
|
||||||
{
|
{
|
||||||
if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr))
|
foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
|
||||||
{
|
{
|
||||||
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
|
kvp.Value.Dispose();
|
||||||
BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
|
|
||||||
}
|
}
|
||||||
|
m_terrains.Clear();
|
||||||
}
|
}
|
||||||
m_heightMaps.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The simulator wants to set a new heightmap for the terrain.
|
// The simulator wants to set a new heightmap for the terrain.
|
||||||
public void SetTerrain(float[] heightMap) {
|
public void SetTerrain(float[] heightMap) {
|
||||||
float[] localHeightMap = heightMap;
|
float[] localHeightMap = heightMap;
|
||||||
PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
|
// If there are multiple requests for changes to the same terrain between ticks,
|
||||||
|
// only do that last one.
|
||||||
|
PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
|
||||||
{
|
{
|
||||||
if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
|
if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
|
||||||
{
|
{
|
||||||
|
@ -176,8 +191,9 @@ public sealed class BSTerrainManager
|
||||||
{
|
{
|
||||||
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
|
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
|
||||||
BSScene.DetailLogZero, m_worldOffset, m_worldMax);
|
BSScene.DetailLogZero, m_worldOffset, m_worldMax);
|
||||||
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
|
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
|
||||||
localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
BSScene.CHILDTERRAIN_ID, localHeightMap,
|
||||||
|
m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -185,7 +201,7 @@ public sealed class BSTerrainManager
|
||||||
// If not doing the mega-prim thing, just change the terrain
|
// If not doing the mega-prim thing, just change the terrain
|
||||||
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
|
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
|
||||||
|
|
||||||
UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
|
UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
|
||||||
m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
m_worldOffset, m_worldOffset + DefaultRegionSize, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -195,56 +211,64 @@ public sealed class BSTerrainManager
|
||||||
// based on the passed information. The 'id' should be either the terrain id or
|
// based on the passed information. The 'id' should be either the terrain id or
|
||||||
// BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
|
// BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
|
||||||
// The latter feature is for creating child terrains for mega-regions.
|
// The latter feature is for creating child terrains for mega-regions.
|
||||||
// If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
|
|
||||||
// then a new body and shape is created and the mapInfo is filled.
|
|
||||||
// This call is used for doing the initial terrain creation.
|
|
||||||
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
|
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
|
||||||
// terrain shape is created and added to the body.
|
// terrain shape is created and added to the body.
|
||||||
// This call is most often used to update the heightMap and parameters of the terrain.
|
// This call is most often used to update the heightMap and parameters of the terrain.
|
||||||
// (The above does suggest that some simplification/refactoring is in order.)
|
// (The above does suggest that some simplification/refactoring is in order.)
|
||||||
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
|
// Called during taint-time.
|
||||||
|
private void UpdateTerrain(uint id, float[] heightMap,
|
||||||
|
Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
|
DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
|
||||||
BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
|
BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
|
||||||
|
|
||||||
|
// Find high and low points of passed heightmap.
|
||||||
|
// The min and max passed in is usually the area objects can be in (maximum
|
||||||
|
// object height, for instance). The terrain wants the bounding box for the
|
||||||
|
// terrain so replace passed min and max Z with the actual terrain min/max Z.
|
||||||
float minZ = float.MaxValue;
|
float minZ = float.MaxValue;
|
||||||
float maxZ = float.MinValue;
|
float maxZ = float.MinValue;
|
||||||
Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
|
foreach (float height in heightMap)
|
||||||
|
|
||||||
int heightMapSize = heightMap.Length;
|
|
||||||
for (int ii = 0; ii < heightMapSize; ii++)
|
|
||||||
{
|
{
|
||||||
float height = heightMap[ii];
|
|
||||||
if (height < minZ) minZ = height;
|
if (height < minZ) minZ = height;
|
||||||
if (height > maxZ) maxZ = height;
|
if (height > maxZ) maxZ = height;
|
||||||
}
|
}
|
||||||
|
if (minZ == maxZ)
|
||||||
// The shape of the terrain is from its base to its extents.
|
{
|
||||||
|
// If min and max are the same, reduce min a little bit so a good bounding box is created.
|
||||||
|
minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
|
||||||
|
}
|
||||||
minCoords.Z = minZ;
|
minCoords.Z = minZ;
|
||||||
maxCoords.Z = maxZ;
|
maxCoords.Z = maxZ;
|
||||||
|
|
||||||
BulletHeightMapInfo mapInfo;
|
Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
|
||||||
if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
|
|
||||||
|
lock (m_terrains)
|
||||||
{
|
{
|
||||||
// If this is terrain we know about, it's easy to update
|
BSTerrainPhys terrainPhys;
|
||||||
|
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
|
||||||
mapInfo.heightMap = heightMap;
|
|
||||||
mapInfo.minCoords = minCoords;
|
|
||||||
mapInfo.maxCoords = maxCoords;
|
|
||||||
mapInfo.minZ = minZ;
|
|
||||||
mapInfo.maxZ = maxZ;
|
|
||||||
mapInfo.sizeX = maxCoords.X - minCoords.X;
|
|
||||||
mapInfo.sizeY = maxCoords.Y - minCoords.Y;
|
|
||||||
DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
|
|
||||||
BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
|
|
||||||
|
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate()
|
|
||||||
{
|
{
|
||||||
if (MegaRegionParentPhysicsScene != null)
|
// There is already a terrain in this spot. Free the old and build the new.
|
||||||
|
DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
|
||||||
|
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
|
||||||
|
|
||||||
|
// Remove old terrain from the collection
|
||||||
|
m_terrains.Remove(terrainRegionBase);
|
||||||
|
// Release any physical memory it may be using.
|
||||||
|
terrainPhys.Dispose();
|
||||||
|
|
||||||
|
if (MegaRegionParentPhysicsScene == null)
|
||||||
|
{
|
||||||
|
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
|
||||||
|
m_terrains.Add(terrainRegionBase, newTerrainPhys);
|
||||||
|
|
||||||
|
m_terrainModified = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// It's possible that Combine() was called after this code was queued.
|
// It's possible that Combine() was called after this code was queued.
|
||||||
// If we are a child of combined regions, we don't create any terrain for us.
|
// If we are a child of combined regions, we don't create any terrain for us.
|
||||||
DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
|
DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
|
||||||
|
|
||||||
// Get rid of any terrain that may have been allocated for us.
|
// Get rid of any terrain that may have been allocated for us.
|
||||||
ReleaseGroundPlaneAndTerrain();
|
ReleaseGroundPlaneAndTerrain();
|
||||||
|
@ -252,135 +276,56 @@ public sealed class BSTerrainManager
|
||||||
// I hate doing this, but just bail
|
// I hate doing this, but just bail
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (mapInfo.terrainBody.ptr != IntPtr.Zero)
|
else
|
||||||
{
|
|
||||||
// Updating an existing terrain.
|
|
||||||
DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
|
|
||||||
BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
|
|
||||||
|
|
||||||
// Remove from the dynamics world because we're going to mangle this object
|
|
||||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
|
|
||||||
|
|
||||||
// Get rid of the old terrain
|
|
||||||
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
|
|
||||||
BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
|
|
||||||
mapInfo.Ptr = IntPtr.Zero;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// NOTE: This routine is half here because I can't get the terrain shape replacement
|
|
||||||
// to work. In the short term, the above three lines completely delete the old
|
|
||||||
// terrain and the code below recreates one from scratch.
|
|
||||||
// Hopefully the Bullet community will help me out on this one.
|
|
||||||
|
|
||||||
// First, release the old collision shape (there is only one terrain)
|
|
||||||
BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
|
|
||||||
|
|
||||||
// Fill the existing height map info with the new location and size information
|
|
||||||
BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
|
|
||||||
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
|
|
||||||
|
|
||||||
// Create a terrain shape based on the new info
|
|
||||||
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
|
|
||||||
|
|
||||||
// Stuff the shape into the existing terrain body
|
|
||||||
BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
// else
|
|
||||||
{
|
|
||||||
// Creating a new terrain.
|
|
||||||
DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
|
|
||||||
BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
|
|
||||||
|
|
||||||
mapInfo.ID = id;
|
|
||||||
mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
|
|
||||||
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
|
|
||||||
|
|
||||||
// Create the terrain shape from the mapInfo
|
|
||||||
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
|
|
||||||
ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
|
|
||||||
|
|
||||||
// The terrain object initial position is at the center of the object
|
|
||||||
Vector3 centerPos;
|
|
||||||
centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
|
|
||||||
centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
|
|
||||||
centerPos.Z = minZ + ((maxZ - minZ) / 2f);
|
|
||||||
|
|
||||||
mapInfo.terrainBody = new BulletBody(mapInfo.ID,
|
|
||||||
BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
|
|
||||||
id, centerPos, Quaternion.Identity));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the entry is in the heightmap table
|
|
||||||
m_heightMaps[terrainRegionBase] = mapInfo;
|
|
||||||
|
|
||||||
// Set current terrain attributes
|
|
||||||
BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
|
|
||||||
BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
|
|
||||||
BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
|
|
||||||
BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
|
|
||||||
|
|
||||||
// Return the new terrain to the world of physical objects
|
|
||||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
|
|
||||||
|
|
||||||
// redo its bounding box now that it is in the world
|
|
||||||
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
|
|
||||||
|
|
||||||
BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
|
|
||||||
(uint)CollisionFilterGroups.TerrainFilter,
|
|
||||||
(uint)CollisionFilterGroups.TerrainMask);
|
|
||||||
|
|
||||||
// Make sure the new shape is processed.
|
|
||||||
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
|
|
||||||
// BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
|
|
||||||
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
|
||||||
|
|
||||||
m_terrainModified = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We don't know about this terrain so either we are creating a new terrain or
|
|
||||||
// our mega-prim child is giving us a new terrain to add to the phys world
|
|
||||||
|
|
||||||
// if this is a child terrain, calculate a unique terrain id
|
|
||||||
uint newTerrainID = id;
|
|
||||||
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
|
|
||||||
newTerrainID = ++m_terrainCount;
|
|
||||||
|
|
||||||
float[] heightMapX = heightMap;
|
|
||||||
Vector3 minCoordsX = minCoords;
|
|
||||||
Vector3 maxCoordsX = maxCoords;
|
|
||||||
|
|
||||||
DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
|
|
||||||
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
|
|
||||||
|
|
||||||
// Code that must happen at taint-time
|
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:NewTerrain", delegate()
|
|
||||||
{
|
{
|
||||||
DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
|
// We don't know about this terrain so either we are creating a new terrain or
|
||||||
// Create a new mapInfo that will be filled with the new info
|
// our mega-prim child is giving us a new terrain to add to the phys world
|
||||||
mapInfo = new BulletHeightMapInfo(id, heightMapX,
|
|
||||||
BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
|
// if this is a child terrain, calculate a unique terrain id
|
||||||
minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
|
uint newTerrainID = id;
|
||||||
// Put the unfilled heightmap info into the collection of same
|
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
|
||||||
m_heightMaps.Add(terrainRegionBase, mapInfo);
|
newTerrainID = ++m_terrainCount;
|
||||||
// Build the terrain
|
|
||||||
UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
|
DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
|
||||||
|
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
|
||||||
|
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
|
||||||
|
m_terrains.Add(terrainRegionBase, newTerrainPhys);
|
||||||
|
|
||||||
m_terrainModified = true;
|
m_terrainModified = true;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Someday we will have complex terrain with caves and tunnels
|
// TODO: redo terrain implementation selection to allow other base types than heightMap.
|
||||||
public float GetTerrainHeightAtXYZ(Vector3 loc)
|
private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
|
||||||
{
|
{
|
||||||
// For the moment, it's flat and convex
|
PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
|
||||||
return GetTerrainHeightAtXY(loc.X, loc.Y);
|
LogHeader, PhysicsScene.RegionName, terrainRegionBase,
|
||||||
|
(BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation);
|
||||||
|
BSTerrainPhys newTerrainPhys = null;
|
||||||
|
switch ((int)PhysicsScene.Params.terrainImplementation)
|
||||||
|
{
|
||||||
|
case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
|
||||||
|
newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
|
||||||
|
heightMap, minCoords, maxCoords);
|
||||||
|
break;
|
||||||
|
case (int)BSTerrainPhys.TerrainImplementation.Mesh:
|
||||||
|
newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id,
|
||||||
|
heightMap, minCoords, maxCoords);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
|
||||||
|
LogHeader,
|
||||||
|
(int)PhysicsScene.Params.terrainImplementation,
|
||||||
|
PhysicsScene.Params.terrainImplementation,
|
||||||
|
PhysicsScene.RegionName, terrainRegionBase);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return newTerrainPhys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Given an X and Y, find the height of the terrain.
|
// Given an X and Y, find the height of the terrain.
|
||||||
// Since we could be handling multiple terrains for a mega-region,
|
// Since we could be handling multiple terrains for a mega-region,
|
||||||
// the base of the region is calcuated assuming all regions are
|
// the base of the region is calcuated assuming all regions are
|
||||||
|
@ -390,12 +335,15 @@ public sealed class BSTerrainManager
|
||||||
private float lastHeightTX = 999999f;
|
private float lastHeightTX = 999999f;
|
||||||
private float lastHeightTY = 999999f;
|
private float lastHeightTY = 999999f;
|
||||||
private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
|
private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
|
||||||
private float GetTerrainHeightAtXY(float tX, float tY)
|
public float GetTerrainHeightAtXYZ(Vector3 loc)
|
||||||
{
|
{
|
||||||
|
float tX = loc.X;
|
||||||
|
float tY = loc.Y;
|
||||||
// You'd be surprized at the number of times this routine is called
|
// You'd be surprized at the number of times this routine is called
|
||||||
// with the same parameters as last time.
|
// with the same parameters as last time.
|
||||||
if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
|
if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
|
||||||
return lastHeight;
|
return lastHeight;
|
||||||
|
m_terrainModified = false;
|
||||||
|
|
||||||
lastHeightTX = tX;
|
lastHeightTX = tX;
|
||||||
lastHeightTY = tY;
|
lastHeightTY = tY;
|
||||||
|
@ -403,34 +351,21 @@ public sealed class BSTerrainManager
|
||||||
|
|
||||||
int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
|
int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
|
||||||
int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
|
int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
|
||||||
Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
|
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
|
||||||
|
|
||||||
BulletHeightMapInfo mapInfo;
|
lock (m_terrains)
|
||||||
if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
|
|
||||||
{
|
{
|
||||||
float regionX = tX - offsetX;
|
BSTerrainPhys physTerrain;
|
||||||
float regionY = tY - offsetY;
|
if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
|
||||||
int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
ret = mapInfo.heightMap[mapIndex];
|
ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
|
||||||
}
|
}
|
||||||
catch
|
else
|
||||||
{
|
{
|
||||||
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
|
||||||
PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
|
LogHeader, PhysicsScene.RegionName, tX, tY);
|
||||||
LogHeader, terrainBaseXY, regionX, regionY);
|
|
||||||
ret = HEIGHT_GETHEIGHT_RET;
|
|
||||||
}
|
}
|
||||||
// DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
|
|
||||||
// BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
|
|
||||||
LogHeader, PhysicsScene.RegionName, tX, tY);
|
|
||||||
}
|
|
||||||
m_terrainModified = false;
|
|
||||||
lastHeight = ret;
|
lastHeight = ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -466,7 +401,7 @@ public sealed class BSTerrainManager
|
||||||
// Unhook all the combining that I know about.
|
// Unhook all the combining that I know about.
|
||||||
public void UnCombine(PhysicsScene pScene)
|
public void UnCombine(PhysicsScene pScene)
|
||||||
{
|
{
|
||||||
// Just like ODE, for the moment a NOP
|
// Just like ODE, we don't do anything yet.
|
||||||
DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
|
DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,262 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Contributors, http://opensimulator.org/
|
||||||
|
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyrightD
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the OpenSimulator Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Framework;
|
||||||
|
using OpenSim.Region.CoreModules;
|
||||||
|
using OpenSim.Region.Physics.Manager;
|
||||||
|
|
||||||
|
using Nini.Config;
|
||||||
|
using log4net;
|
||||||
|
|
||||||
|
using OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
|
{
|
||||||
|
public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
|
{
|
||||||
|
static string LogHeader = "[BULLETSIM TERRAIN MESH]";
|
||||||
|
|
||||||
|
private float[] m_savedHeightMap;
|
||||||
|
int m_sizeX;
|
||||||
|
int m_sizeY;
|
||||||
|
|
||||||
|
BulletShape m_terrainShape;
|
||||||
|
BulletBody m_terrainBody;
|
||||||
|
|
||||||
|
public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
|
||||||
|
: base(physicsScene, regionBase, id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
|
||||||
|
: base(physicsScene, regionBase, id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create terrain mesh from a heightmap.
|
||||||
|
public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
|
||||||
|
Vector3 minCoords, Vector3 maxCoords)
|
||||||
|
: base(physicsScene, regionBase, id)
|
||||||
|
{
|
||||||
|
int indicesCount;
|
||||||
|
int[] indices;
|
||||||
|
int verticesCount;
|
||||||
|
float[] vertices;
|
||||||
|
|
||||||
|
m_savedHeightMap = initialMap;
|
||||||
|
|
||||||
|
m_sizeX = (int)(maxCoords.X - minCoords.X);
|
||||||
|
m_sizeY = (int)(maxCoords.Y - minCoords.Y);
|
||||||
|
|
||||||
|
if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
|
||||||
|
m_sizeX, m_sizeY,
|
||||||
|
(float)m_sizeX, (float)m_sizeY,
|
||||||
|
Vector3.Zero, 1.0f,
|
||||||
|
out indicesCount, out indices, out verticesCount, out vertices))
|
||||||
|
{
|
||||||
|
// DISASTER!!
|
||||||
|
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
|
||||||
|
PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
|
||||||
|
// Something is very messed up and a crash is in our future.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
|
||||||
|
ID, indicesCount, indices.Length, verticesCount, vertices.Length);
|
||||||
|
|
||||||
|
m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
||||||
|
indicesCount, indices, verticesCount, vertices),
|
||||||
|
BSPhysicsShapeType.SHAPE_MESH);
|
||||||
|
if (m_terrainShape.ptr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
// DISASTER!!
|
||||||
|
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
|
||||||
|
physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
|
||||||
|
// Something is very messed up and a crash is in our future.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 pos = regionBase;
|
||||||
|
Quaternion rot = Quaternion.Identity;
|
||||||
|
|
||||||
|
m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
|
||||||
|
if (m_terrainBody.ptr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
// DISASTER!!
|
||||||
|
physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
|
||||||
|
// Something is very messed up and a crash is in our future.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set current terrain attributes
|
||||||
|
BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction);
|
||||||
|
BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
|
||||||
|
BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
|
||||||
|
BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
|
||||||
|
|
||||||
|
// Static objects are not very massive.
|
||||||
|
BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
|
||||||
|
|
||||||
|
// Put the new terrain to the world of physical objects
|
||||||
|
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
|
||||||
|
|
||||||
|
// Redo its bounding box now that it is in the world
|
||||||
|
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
|
||||||
|
|
||||||
|
BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
|
||||||
|
(uint)CollisionFilterGroups.TerrainFilter,
|
||||||
|
(uint)CollisionFilterGroups.TerrainMask);
|
||||||
|
|
||||||
|
// Make it so the terrain will not move or be considered for movement.
|
||||||
|
BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
if (m_terrainBody.ptr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
|
||||||
|
// Frees both the body and the shape.
|
||||||
|
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetHeightAtXYZ(Vector3 pos)
|
||||||
|
{
|
||||||
|
// For the moment use the saved heightmap to get the terrain height.
|
||||||
|
// TODO: raycast downward to find the true terrain below the position.
|
||||||
|
float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
|
||||||
|
|
||||||
|
int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ret = m_savedHeightMap[mapIndex];
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Sometimes they give us wonky values of X and Y. Give a warning and return something.
|
||||||
|
PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
|
||||||
|
LogHeader, TerrainBase, pos);
|
||||||
|
ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
|
||||||
|
// Return 'true' if successfully created.
|
||||||
|
public static bool ConvertHeightmapToMesh(
|
||||||
|
BSScene physicsScene,
|
||||||
|
float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
|
||||||
|
float extentX, float extentY, // zero based range for output vertices
|
||||||
|
Vector3 extentBase, // base to be added to all vertices
|
||||||
|
float magnification, // number of vertices to create between heightMap coords
|
||||||
|
out int indicesCountO, out int[] indicesO,
|
||||||
|
out int verticesCountO, out float[] verticesO)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
int indicesCount = 0;
|
||||||
|
int verticesCount = 0;
|
||||||
|
int[] indices = new int[0];
|
||||||
|
float[] vertices = new float[0];
|
||||||
|
|
||||||
|
// Simple mesh creation which assumes magnification == 1.
|
||||||
|
// TODO: do a more general solution that scales, adds new vertices and smoothes the result.
|
||||||
|
|
||||||
|
// Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
|
||||||
|
// from zero to <= sizeX). The triangle indices are then generated as two triangles
|
||||||
|
// per heightmap point. There are sizeX by sizeY of these squares. The extra row and
|
||||||
|
// column of vertices are used to complete the triangles of the last row and column
|
||||||
|
// of the heightmap.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// One vertice per heightmap value plus the vertices off the top and bottom edge.
|
||||||
|
int totalVertices = (sizeX + 1) * (sizeY + 1);
|
||||||
|
vertices = new float[totalVertices * 3];
|
||||||
|
int totalIndices = sizeX * sizeY * 6;
|
||||||
|
indices = new int[totalIndices];
|
||||||
|
|
||||||
|
float magX = (float)sizeX / extentX;
|
||||||
|
float magY = (float)sizeY / extentY;
|
||||||
|
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
|
||||||
|
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
|
||||||
|
float minHeight = float.MaxValue;
|
||||||
|
// Note that sizeX+1 vertices are created since there is land between this and the next region.
|
||||||
|
for (int yy = 0; yy <= sizeY; yy++)
|
||||||
|
{
|
||||||
|
for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
|
||||||
|
{
|
||||||
|
int offset = yy * sizeX + xx;
|
||||||
|
// Extend the height with the height from the last row or column
|
||||||
|
if (yy == sizeY) offset -= sizeX;
|
||||||
|
if (xx == sizeX) offset -= 1;
|
||||||
|
float height = heightMap[offset];
|
||||||
|
minHeight = Math.Min(minHeight, height);
|
||||||
|
vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
|
||||||
|
vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
|
||||||
|
vertices[verticesCount + 2] = height + extentBase.Z;
|
||||||
|
verticesCount += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verticesCount = verticesCount / 3;
|
||||||
|
|
||||||
|
for (int yy = 0; yy < sizeY; yy++)
|
||||||
|
{
|
||||||
|
for (int xx = 0; xx < sizeX; xx++)
|
||||||
|
{
|
||||||
|
int offset = yy * (sizeX + 1) + xx;
|
||||||
|
// Each vertices is presumed to be the upper left corner of a box of two triangles
|
||||||
|
indices[indicesCount + 0] = offset;
|
||||||
|
indices[indicesCount + 1] = offset + 1;
|
||||||
|
indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
|
||||||
|
indices[indicesCount + 3] = offset + 1;
|
||||||
|
indices[indicesCount + 4] = offset + sizeX + 2;
|
||||||
|
indices[indicesCount + 5] = offset + sizeX + 1;
|
||||||
|
indicesCount += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
|
||||||
|
LogHeader, physicsScene.RegionName, extentBase, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
indicesCountO = indicesCount;
|
||||||
|
indicesO = indices;
|
||||||
|
verticesCountO = verticesCount;
|
||||||
|
verticesO = vertices;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -88,11 +88,11 @@ public struct BulletShape
|
||||||
public BulletShape(IntPtr xx)
|
public BulletShape(IntPtr xx)
|
||||||
{
|
{
|
||||||
ptr = xx;
|
ptr = xx;
|
||||||
type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
|
type=BSPhysicsShapeType.SHAPE_UNKNOWN;
|
||||||
shapeKey = 0;
|
shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
|
||||||
isNativeShape = false;
|
isNativeShape = false;
|
||||||
}
|
}
|
||||||
public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
|
public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
|
||||||
{
|
{
|
||||||
ptr = xx;
|
ptr = xx;
|
||||||
type = typ;
|
type = typ;
|
||||||
|
@ -100,7 +100,7 @@ public struct BulletShape
|
||||||
isNativeShape = false;
|
isNativeShape = false;
|
||||||
}
|
}
|
||||||
public IntPtr ptr;
|
public IntPtr ptr;
|
||||||
public ShapeData.PhysicsShapeType type;
|
public BSPhysicsShapeType type;
|
||||||
public System.UInt64 shapeKey;
|
public System.UInt64 shapeKey;
|
||||||
public bool isNativeShape;
|
public bool isNativeShape;
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -152,7 +152,7 @@ public class BulletHeightMapInfo
|
||||||
ID = id;
|
ID = id;
|
||||||
Ptr = xx;
|
Ptr = xx;
|
||||||
heightMap = hm;
|
heightMap = hm;
|
||||||
terrainRegionBase = new Vector2(0f, 0f);
|
terrainRegionBase = Vector3.Zero;
|
||||||
minCoords = new Vector3(100f, 100f, 25f);
|
minCoords = new Vector3(100f, 100f, 25f);
|
||||||
maxCoords = new Vector3(101f, 101f, 26f);
|
maxCoords = new Vector3(101f, 101f, 26f);
|
||||||
minZ = maxZ = 0f;
|
minZ = maxZ = 0f;
|
||||||
|
@ -161,7 +161,7 @@ public class BulletHeightMapInfo
|
||||||
public uint ID;
|
public uint ID;
|
||||||
public IntPtr Ptr;
|
public IntPtr Ptr;
|
||||||
public float[] heightMap;
|
public float[] heightMap;
|
||||||
public Vector2 terrainRegionBase;
|
public Vector3 terrainRegionBase;
|
||||||
public Vector3 minCoords;
|
public Vector3 minCoords;
|
||||||
public Vector3 maxCoords;
|
public Vector3 maxCoords;
|
||||||
public float sizeX, sizeY;
|
public float sizeX, sizeY;
|
||||||
|
@ -178,26 +178,39 @@ public struct ConvexHull
|
||||||
int VertexCount;
|
int VertexCount;
|
||||||
Vector3[] Vertices;
|
Vector3[] Vertices;
|
||||||
}
|
}
|
||||||
|
public enum BSPhysicsShapeType
|
||||||
|
{
|
||||||
|
SHAPE_UNKNOWN = 0,
|
||||||
|
SHAPE_CAPSULE = 1,
|
||||||
|
SHAPE_BOX = 2,
|
||||||
|
SHAPE_CONE = 3,
|
||||||
|
SHAPE_CYLINDER = 4,
|
||||||
|
SHAPE_SPHERE = 5,
|
||||||
|
SHAPE_MESH = 6,
|
||||||
|
SHAPE_HULL = 7,
|
||||||
|
// following defined by BulletSim
|
||||||
|
SHAPE_GROUNDPLANE = 20,
|
||||||
|
SHAPE_TERRAIN = 21,
|
||||||
|
SHAPE_COMPOUND = 22,
|
||||||
|
SHAPE_HEIGHTMAP = 23,
|
||||||
|
};
|
||||||
|
|
||||||
|
// The native shapes have predefined shape hash keys
|
||||||
|
public enum FixedShapeKey : ulong
|
||||||
|
{
|
||||||
|
KEY_NONE = 0,
|
||||||
|
KEY_BOX = 1,
|
||||||
|
KEY_SPHERE = 2,
|
||||||
|
KEY_CONE = 3,
|
||||||
|
KEY_CYLINDER = 4,
|
||||||
|
KEY_CAPSULE = 5,
|
||||||
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct ShapeData
|
public struct ShapeData
|
||||||
{
|
{
|
||||||
public enum PhysicsShapeType
|
|
||||||
{
|
|
||||||
SHAPE_UNKNOWN = 0,
|
|
||||||
SHAPE_AVATAR = 1,
|
|
||||||
SHAPE_BOX = 2,
|
|
||||||
SHAPE_CONE = 3,
|
|
||||||
SHAPE_CYLINDER = 4,
|
|
||||||
SHAPE_SPHERE = 5,
|
|
||||||
SHAPE_MESH = 6,
|
|
||||||
SHAPE_HULL = 7,
|
|
||||||
// following defined by BulletSim
|
|
||||||
SHAPE_GROUNDPLANE = 20,
|
|
||||||
SHAPE_TERRAIN = 21,
|
|
||||||
SHAPE_COMPOUND = 22,
|
|
||||||
};
|
|
||||||
public uint ID;
|
public uint ID;
|
||||||
public PhysicsShapeType Type;
|
public BSPhysicsShapeType Type;
|
||||||
public Vector3 Position;
|
public Vector3 Position;
|
||||||
public Quaternion Rotation;
|
public Quaternion Rotation;
|
||||||
public Vector3 Velocity;
|
public Vector3 Velocity;
|
||||||
|
@ -216,16 +229,6 @@ public struct ShapeData
|
||||||
// note that bools are passed as floats since bool size changes by language and architecture
|
// note that bools are passed as floats since bool size changes by language and architecture
|
||||||
public const float numericTrue = 1f;
|
public const float numericTrue = 1f;
|
||||||
public const float numericFalse = 0f;
|
public const float numericFalse = 0f;
|
||||||
|
|
||||||
// The native shapes have predefined shape hash keys
|
|
||||||
public enum FixedShapeKey : ulong
|
|
||||||
{
|
|
||||||
KEY_BOX = 1,
|
|
||||||
KEY_SPHERE = 2,
|
|
||||||
KEY_CONE = 3,
|
|
||||||
KEY_CYLINDER = 4,
|
|
||||||
KEY_CAPSULE = 5,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct SweepHit
|
public struct SweepHit
|
||||||
|
@ -280,17 +283,23 @@ public struct ConfigurationParameters
|
||||||
public float ccdSweptSphereRadius;
|
public float ccdSweptSphereRadius;
|
||||||
public float contactProcessingThreshold;
|
public float contactProcessingThreshold;
|
||||||
|
|
||||||
|
public float terrainImplementation;
|
||||||
public float terrainFriction;
|
public float terrainFriction;
|
||||||
public float terrainHitFraction;
|
public float terrainHitFraction;
|
||||||
public float terrainRestitution;
|
public float terrainRestitution;
|
||||||
|
public float terrainCollisionMargin;
|
||||||
|
|
||||||
public float avatarFriction;
|
public float avatarFriction;
|
||||||
public float avatarStandingFriction;
|
public float avatarStandingFriction;
|
||||||
public float avatarDensity;
|
public float avatarDensity;
|
||||||
public float avatarRestitution;
|
public float avatarRestitution;
|
||||||
public float avatarCapsuleRadius;
|
public float avatarCapsuleWidth;
|
||||||
|
public float avatarCapsuleDepth;
|
||||||
public float avatarCapsuleHeight;
|
public float avatarCapsuleHeight;
|
||||||
public float avatarContactProcessingThreshold;
|
public float avatarContactProcessingThreshold;
|
||||||
|
|
||||||
|
public float vehicleAngularDamping;
|
||||||
|
|
||||||
public float maxPersistantManifoldPoolSize;
|
public float maxPersistantManifoldPoolSize;
|
||||||
public float maxCollisionAlgorithmPoolSize;
|
public float maxCollisionAlgorithmPoolSize;
|
||||||
public float shouldDisableContactPoolDynamicAllocation;
|
public float shouldDisableContactPoolDynamicAllocation;
|
||||||
|
@ -348,7 +357,7 @@ public enum CollisionFlags : uint
|
||||||
CF_CHARACTER_OBJECT = 1 << 4,
|
CF_CHARACTER_OBJECT = 1 << 4,
|
||||||
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
|
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
|
||||||
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
|
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
|
||||||
// Following used by BulletSim to control collisions
|
// 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_NONE = 0,
|
BS_NONE = 0,
|
||||||
|
@ -388,13 +397,13 @@ public enum CollisionFilterGroups : uint
|
||||||
ObjectFilter = BSolidFilter,
|
ObjectFilter = BSolidFilter,
|
||||||
ObjectMask = BAllFilter,
|
ObjectMask = BAllFilter,
|
||||||
StaticObjectFilter = BStaticFilter,
|
StaticObjectFilter = BStaticFilter,
|
||||||
StaticObjectMask = BAllFilter,
|
StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other
|
||||||
LinksetFilter = BLinksetFilter,
|
LinksetFilter = BLinksetFilter,
|
||||||
LinksetMask = BAllFilter & ~BLinksetFilter,
|
LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other
|
||||||
VolumeDetectFilter = BSensorTrigger,
|
VolumeDetectFilter = BSensorTrigger,
|
||||||
VolumeDetectMask = ~BSensorTrigger,
|
VolumeDetectMask = ~BSensorTrigger,
|
||||||
TerrainFilter = BTerrainFilter,
|
TerrainFilter = BTerrainFilter,
|
||||||
TerrainMask = BAllFilter & ~BStaticFilter,
|
TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide
|
||||||
GroundPlaneFilter = BGroundPlaneFilter,
|
GroundPlaneFilter = BGroundPlaneFilter,
|
||||||
GroundPlaneMask = BAllFilter
|
GroundPlaneMask = BAllFilter
|
||||||
|
|
||||||
|
@ -429,140 +438,6 @@ static class BulletSimAPI {
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
|
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
[return: MarshalAs(UnmanagedType.LPStr)]
|
|
||||||
public static extern string GetVersion();
|
|
||||||
|
|
||||||
/* Remove the linkage to the old api methods
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
|
|
||||||
int maxCollisions, IntPtr collisionArray,
|
|
||||||
int maxUpdates, IntPtr updateArray,
|
|
||||||
DebugLogCallback logRoutine);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern void Shutdown(uint worldID);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool UpdateParameter(uint worldID, uint localID,
|
|
||||||
[MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
|
|
||||||
|
|
||||||
// ===============================================================================
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
|
|
||||||
out int updatedEntityCount,
|
|
||||||
out IntPtr updatedEntitiesPtr,
|
|
||||||
out int collidersCount,
|
|
||||||
out IntPtr collidersPtr);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
|
|
||||||
int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
|
|
||||||
);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
|
|
||||||
int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
|
|
||||||
int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
|
|
||||||
);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool CreateObject(uint worldID, ShapeData shapeData);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern Quaternion GetObjectOrientation(uint WorldID, uint id);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
|
|
||||||
|
|
||||||
// Set the current force acting on the object
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool HasObject(uint worldID, uint id);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern bool DestroyObject(uint worldID, uint id);
|
|
||||||
|
|
||||||
// ===============================================================================
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
|
|
||||||
|
|
||||||
// ===============================================================================
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern void DumpBulletStatistics();
|
|
||||||
*/
|
|
||||||
// Log a debug message
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern void SetDebugLogCallback(DebugLogCallback callback);
|
|
||||||
|
|
||||||
// ===============================================================================
|
|
||||||
// ===============================================================================
|
|
||||||
// ===============================================================================
|
|
||||||
// A new version of the API that enables moving all the logic out of the C++ code and into
|
|
||||||
// the C# code. This will make modifications easier for the next person.
|
|
||||||
// This interface passes the actual pointers to the objects in the unmanaged
|
|
||||||
// address space. All the management (calls for creation/destruction/lookup)
|
|
||||||
// is done in the C# code.
|
|
||||||
// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
|
|
||||||
// and the old code is removed.
|
|
||||||
|
|
||||||
// Functions use while converting from API1 to API2. Can be removed when totally converted.
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern IntPtr GetSimHandle2(uint worldID);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
|
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
|
||||||
public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
|
|
||||||
|
|
||||||
// ===============================================================================
|
// ===============================================================================
|
||||||
// Initialization and simulation
|
// Initialization and simulation
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
@ -610,6 +485,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern bool IsNativeShape2(IntPtr shape);
|
public static extern bool IsNativeShape2(IntPtr shape);
|
||||||
|
|
||||||
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
|
public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
|
||||||
|
|
||||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||||
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
|
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,14 @@ using OpenMetaverse;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Region.Physics.Manager;
|
using OpenSim.Region.Physics.Manager;
|
||||||
using OpenSim.Region.Physics.OdePlugin;
|
using OpenSim.Region.Physics.OdePlugin;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
using log4net;
|
using log4net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace OpenSim.Region.Physics.OdePlugin.Tests
|
namespace OpenSim.Region.Physics.OdePlugin.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ODETestClass
|
public class ODETestClass : OpenSimTestCase
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue