Merge branch 'master' into careminster

Conflicts:
	OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
	OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
	OpenSim/Region/Framework/Scenes/Scene.cs
avinationmerge
Melanie 2012-10-12 19:05:06 +01:00
commit 6ce93b22d1
50 changed files with 1315 additions and 674 deletions

View File

@ -85,21 +85,6 @@ namespace OpenSim.Data
List<RegionData> GetHyperlinks(UUID scopeID); List<RegionData> GetHyperlinks(UUID scopeID);
} }
[Flags]
public enum RegionFlags : int
{
DefaultRegion = 1, // Used for new Rez. Random if multiple defined
FallbackRegion = 2, // Regions we redirect to when the destination is down
RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
NoDirectLogin = 8, // Region unavailable for direct logins (by name)
Persistent = 16, // Don't remove on unregister
LockedOut = 32, // Don't allow registration
NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation
Authenticate = 256, // Require authentication
Hyperlink = 512 // Record represents a HG link
}
public class RegionDataDistanceCompare : IComparer<RegionData> public class RegionDataDistanceCompare : IComparer<RegionData>
{ {
private Vector2 m_origin; private Vector2 m_origin;

View File

@ -37,6 +37,7 @@ using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.MSSQL namespace OpenSim.Data.MSSQL
{ {

View File

@ -30,11 +30,11 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Reflection; using System.Reflection;
using MySql.Data.MySqlClient;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Data; using OpenSim.Data;
using MySql.Data.MySqlClient; using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.MySQL namespace OpenSim.Data.MySQL
{ {

View File

@ -33,6 +33,7 @@ using OpenSim.Framework;
using OpenSim.Data; using OpenSim.Data;
using System.Reflection; using System.Reflection;
using log4net; using log4net;
using RegionFlags = OpenSim.Framework.RegionFlags;
namespace OpenSim.Data.Null namespace OpenSim.Data.Null
{ {

View File

@ -34,7 +34,7 @@ using OpenMetaverse;
public class ConsoleUtil public class ConsoleUtil
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public const string MinRawConsoleVectorValue = "-~"; public const string MinRawConsoleVectorValue = "-~";
public const string MaxRawConsoleVectorValue = "~"; public const string MaxRawConsoleVectorValue = "~";
@ -107,7 +107,7 @@ public class ConsoleUtil
string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray()); string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector); // m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
return Vector3.TryParse(semiDigestedConsoleVector, out vector); return Vector3.TryParse(semiDigestedConsoleVector, out vector);
} }

View File

@ -359,13 +359,19 @@ Asset service request failures: {3}" + Environment.NewLine,
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
foreach (KeyValuePair<string, Stat> kvp in StatsManager.RegisteredStats) Dictionary<string, Dictionary<string, Stat>> sceneStats;
{
Stat stat = kvp.Value;
if (stat.Category == "scene" && stat.Verbosity == StatVerbosity.Info) if (StatsManager.TryGetStats("scene", out sceneStats))
{ {
sb.AppendFormat("Slow frames ({0}): {1}\n", stat.Container, stat.Value); foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
{
foreach (Stat stat in kvp.Value.Values)
{
if (stat.Verbosity == StatVerbosity.Info)
{
sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
}
}
} }
} }

View File

@ -35,13 +35,23 @@ namespace OpenSim.Framework.Monitoring
/// </summary> /// </summary>
public class StatsManager public class StatsManager
{ {
// Subcommand used to list other stats.
public const string AllSubCommand = "all";
// Subcommand used to list other stats.
public const string ListSubCommand = "list";
// All subcommands
public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
/// <summary> /// <summary>
/// Registered stats. /// Registered stats categorized by category/container/shortname
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Do not add or remove from this dictionary. /// Do not add or remove directly from this dictionary.
/// </remarks> /// </remarks>
public static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>(); public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
= new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
private static AssetStatsCollector assetStats; private static AssetStatsCollector assetStats;
private static UserStatsCollector userStats; private static UserStatsCollector userStats;
@ -51,6 +61,75 @@ namespace OpenSim.Framework.Monitoring
public static UserStatsCollector UserStats { get { return userStats; } } public static UserStatsCollector UserStats { get { return userStats; } }
public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
public static void RegisterConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"General",
false,
"show stats",
"show stats [list|all|<category>]",
"Show statistical information for this server",
"If no final argument is specified then legacy statistics information is currently shown.\n"
+ "If list is specified then statistic categories are shown.\n"
+ "If all is specified then all registered statistics are shown.\n"
+ "If a category name is specified then only statistics from that category are shown.\n"
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
HandleShowStatsCommand);
}
public static void HandleShowStatsCommand(string module, string[] cmd)
{
ICommandConsole con = MainConsole.Instance;
if (cmd.Length > 2)
{
var categoryName = cmd[2];
if (categoryName == AllSubCommand)
{
foreach (var category in RegisteredStats.Values)
{
OutputCategoryStatsToConsole(con, category);
}
}
else if (categoryName == ListSubCommand)
{
con.Output("Statistic categories available are:");
foreach (string category in RegisteredStats.Keys)
con.OutputFormat(" {0}", category);
}
else
{
Dictionary<string, Dictionary<string, Stat>> category;
if (!RegisteredStats.TryGetValue(categoryName, out category))
{
con.OutputFormat("No such category as {0}", categoryName);
}
else
{
OutputCategoryStatsToConsole(con, category);
}
}
}
else
{
// Legacy
con.Output(SimExtraStats.Report());
}
}
private static void OutputCategoryStatsToConsole(
ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
{
foreach (var container in category.Values)
{
foreach (Stat stat in container.Values)
{
con.Output(stat.ToConsoleString());
}
}
}
/// <summary> /// <summary>
/// Start collecting statistics related to assets. /// Start collecting statistics related to assets.
/// Should only be called once. /// Should only be called once.
@ -73,43 +152,100 @@ namespace OpenSim.Framework.Monitoring
return userStats; return userStats;
} }
/// <summary>
/// Registers a statistic.
/// </summary>
/// <param name='stat'></param>
/// <returns></returns>
public static bool RegisterStat(Stat stat) public static bool RegisterStat(Stat stat)
{ {
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats) lock (RegisteredStats)
{ {
if (RegisteredStats.ContainsKey(stat.UniqueName)) // Stat name is not unique across category/container/shortname key.
{
// XXX: For now just return false. This is to avoid problems in regression tests where all tests // XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM. // in a class are run in the same instance of the VM.
if (TryGetStat(stat, out category, out container))
return false; return false;
// throw new Exception( // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
// "StatsManager already contains stat with ShortName {0} in Category {1}", stat.ShortName, stat.Category); // This means that we don't need to lock or copy them on iteration, which will be a much more
} // common operation after startup.
if (container != null)
newContainer = new Dictionary<string, Stat>(container);
else
newContainer = new Dictionary<string, Stat>();
// We take a replace-on-write approach here so that we don't need to generate a new Dictionary if (category != null)
Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats); newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
newRegisteredStats[stat.UniqueName] = stat; else
RegisteredStats = newRegisteredStats; newCategory = new Dictionary<string, Dictionary<string, Stat>>();
newContainer[stat.ShortName] = stat;
newCategory[stat.Container] = newContainer;
RegisteredStats[stat.Category] = newCategory;
} }
return true; return true;
} }
/// <summary>
/// Deregister a statistic
/// </summary>>
/// <param name='stat'></param>
/// <returns></returns
public static bool DeregisterStat(Stat stat) public static bool DeregisterStat(Stat stat)
{ {
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
Dictionary<string, Stat> container = null, newContainer;
lock (RegisteredStats) lock (RegisteredStats)
{ {
if (!RegisteredStats.ContainsKey(stat.UniqueName)) if (!TryGetStat(stat, out category, out container))
return false; return false;
Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats); newContainer = new Dictionary<string, Stat>(container);
newRegisteredStats.Remove(stat.UniqueName); newContainer.Remove(stat.UniqueName);
RegisteredStats = newRegisteredStats;
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
newCategory.Remove(stat.Container);
newCategory[stat.Container] = newContainer;
RegisteredStats[stat.Category] = newCategory;
return true; return true;
} }
} }
public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
{
return RegisteredStats.TryGetValue(category, out stats);
}
public static bool TryGetStat(
Stat stat,
out Dictionary<string, Dictionary<string, Stat>> category,
out Dictionary<string, Stat> container)
{
category = null;
container = null;
lock (RegisteredStats)
{
if (RegisteredStats.TryGetValue(stat.Category, out category))
{
if (category.TryGetValue(stat.Container, out container))
{
if (container.ContainsKey(stat.ShortName))
return true;
}
}
}
return false;
}
} }
/// <summary> /// <summary>
@ -157,9 +293,26 @@ namespace OpenSim.Framework.Monitoring
public virtual double Value { get; set; } public virtual double Value { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
/// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
/// <param name='unitName'>
/// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
/// e.g. " frames"
/// </param>
/// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
/// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
/// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
/// <param name='description'>Description of stat</param>
public Stat( public Stat(
string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description) string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
{ {
if (StatsManager.SubCommands.Contains(category))
throw new Exception(
string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
ShortName = shortName; ShortName = shortName;
Name = name; Name = name;
UnitName = unitName; UnitName = unitName;
@ -175,6 +328,12 @@ namespace OpenSim.Framework.Monitoring
{ {
return string.Format("{0}+{1}+{2}", container, category, shortName); return string.Format("{0}+{1}+{2}", container, category, shortName);
} }
public virtual string ToConsoleString()
{
return string.Format(
"{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
}
} }
public class PercentageStat : Stat public class PercentageStat : Stat
@ -192,7 +351,7 @@ namespace OpenSim.Framework.Monitoring
if (c == 0) if (c == 0)
return 0; return 0;
return (double)Antecedent / c; return (double)Antecedent / c * 100;
} }
set set
@ -203,8 +362,13 @@ namespace OpenSim.Framework.Monitoring
public PercentageStat( public PercentageStat(
string shortName, string name, string category, string container, StatVerbosity verbosity, string description) string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
: base(shortName, name, " %", category, container, verbosity, description) : base(shortName, name, "%", category, container, verbosity, description) {}
public override string ToConsoleString()
{ {
return string.Format(
"{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
} }
} }
} }

View File

@ -231,7 +231,25 @@ namespace OpenSim.Framework.Monitoring
private static bool RemoveThread(int threadID) private static bool RemoveThread(int threadID)
{ {
lock (m_threads) lock (m_threads)
return m_threads.Remove(threadID); {
ThreadWatchdogInfo twi;
if (m_threads.TryGetValue(threadID, out twi))
{
m_log.DebugFormat(
"[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
m_threads.Remove(threadID);
return true;
}
else
{
m_log.WarnFormat(
"[WATCHDOG]: Requested to remove thread with ID {0} but this is not being monitored", threadID);
return false;
}
}
} }
public static bool AbortThread(int threadID) public static bool AbortThread(int threadID)

View File

@ -0,0 +1,53 @@
/*
* 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;
namespace OpenSim.Framework
{
/// <summary>
/// Region flags used internally by OpenSimulator to store installation specific information about regions.
/// </summary>
/// <remarks>
/// Don't confuse with OpenMetaverse.RegionFlags which are client facing flags (i.e. they go over the wire).
/// Returned by IGridService.GetRegionFlags()
/// </remarks>
[Flags]
public enum RegionFlags : int
{
DefaultRegion = 1, // Used for new Rez. Random if multiple defined
FallbackRegion = 2, // Regions we redirect to when the destination is down
RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
NoDirectLogin = 8, // Region unavailable for direct logins (by name)
Persistent = 16, // Don't remove on unregister
LockedOut = 32, // Don't allow registration
NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation
Authenticate = 256, // Require authentication
Hyperlink = 512 // Record represents a HG link
}
}

View File

@ -96,11 +96,6 @@ namespace OpenSim.Framework.Servers
get { return m_httpServer; } get { return m_httpServer; }
} }
/// <summary>
/// Holds the non-viewer statistics collection object for this service/server
/// </summary>
protected IStatsCollector m_stats;
public BaseOpenSimServer() public BaseOpenSimServer()
{ {
m_startuptime = DateTime.Now; m_startuptime = DateTime.Now;
@ -177,10 +172,6 @@ namespace OpenSim.Framework.Servers
"show info", "show info",
"Show general information about the server", HandleShow); "Show general information about the server", HandleShow);
m_console.Commands.AddCommand("General", false, "show stats",
"show stats",
"Show statistics", HandleShow);
m_console.Commands.AddCommand("General", false, "show threads", m_console.Commands.AddCommand("General", false, "show threads",
"show threads", "show threads",
"Show thread status", HandleShow); "Show thread status", HandleShow);
@ -226,12 +217,7 @@ namespace OpenSim.Framework.Servers
{ {
StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n"); StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
sb.Append(GetUptimeReport()); sb.Append(GetUptimeReport());
sb.Append(StatsManager.SimExtraStats.Report());
if (m_stats != null)
{
sb.Append(m_stats.Report());
}
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append(GetThreadsReport()); sb.Append(GetThreadsReport());
@ -382,10 +368,6 @@ namespace OpenSim.Framework.Servers
{ {
Notice("set log level [level] - change the console logging level only. For example, off or debug."); 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 info - show server information (e.g. startup path).");
if (m_stats != null)
Notice("show stats - show statistical information for this server");
Notice("show threads - list tracked threads"); Notice("show threads - list tracked threads");
Notice("show uptime - show server startup time and uptime."); Notice("show uptime - show server startup time and uptime.");
Notice("show version - show server version."); Notice("show version - show server version.");
@ -409,11 +391,6 @@ namespace OpenSim.Framework.Servers
ShowInfo(); ShowInfo();
break; break;
case "stats":
if (m_stats != null)
Notice(m_stats.Report());
break;
case "threads": case "threads":
Notice(GetThreadsReport()); Notice(GetThreadsReport());
break; break;
@ -605,7 +582,6 @@ namespace OpenSim.Framework.Servers
public string osSecret { public string osSecret {
// Secret uuid for the simulator // Secret uuid for the simulator
get { return m_osSecret; } get { return m_osSecret; }
} }
public string StatReport(IOSHttpRequest httpRequest) public string StatReport(IOSHttpRequest httpRequest)
@ -613,11 +589,11 @@ namespace OpenSim.Framework.Servers
// If we catch a request for "callback", wrap the response in the value for jsonp // If we catch a request for "callback", wrap the response in the value for jsonp
if (httpRequest.Query.ContainsKey("callback")) if (httpRequest.Query.ContainsKey("callback"))
{ {
return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");"; return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
} }
else else
{ {
return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version); return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
} }
} }

View File

@ -254,8 +254,14 @@ namespace OpenSim
m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug); m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
m_console.Commands.AddCommand("Debug", false, "debug scene", m_console.Commands.AddCommand("Debug", false, "debug scene",
"debug scene <scripting> <collisions> <physics>", "debug scene active|collisions|physics|scripting|teleport true|false",
"Turn on scene debugging", Debug); "Turn on scene debugging.",
"If active is false then main scene update and maintenance loops are suspended.\n"
+ "If collisions is false then collisions with other objects are turned off.\n"
+ "If physics is false then all physics objects are non-physical.\n"
+ "If scripting is false then no scripting operations happen.\n"
+ "If teleport is true then some extra teleport debug information is logged.",
Debug);
m_console.Commands.AddCommand("General", false, "change region", m_console.Commands.AddCommand("General", false, "change region",
"change region <region name>", "change region <region name>",
@ -930,7 +936,8 @@ namespace OpenSim
} }
else else
{ {
MainConsole.Instance.Output("Usage: debug scene scripting|collisions|physics|teleport true|false"); MainConsole.Instance.Output(
"Usage: debug scene active|scripting|collisions|physics|teleport true|false");
} }
break; break;

View File

@ -232,8 +232,6 @@ namespace OpenSim
base.StartupSpecific(); base.StartupSpecific();
m_stats = StatsManager.SimExtraStats;
// Create a ModuleLoader instance // Create a ModuleLoader instance
m_moduleLoader = new ModuleLoader(m_config.Source); m_moduleLoader = new ModuleLoader(m_config.Source);
@ -249,13 +247,14 @@ namespace OpenSim
plugin.PostInitialise(); plugin.PostInitialise();
} }
AddPluginCommands(); if (m_console != null)
{
StatsManager.RegisterConsoleCommands(m_console);
AddPluginCommands(m_console);
}
} }
protected virtual void AddPluginCommands() protected virtual void AddPluginCommands(CommandConsole console)
{
// If console exists add plugin commands.
if (m_console != null)
{ {
List<string> topics = GetHelpTopics(); List<string> topics = GetHelpTopics();
@ -265,11 +264,11 @@ namespace OpenSim
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go // This is a hack to allow the user to enter the help command in upper or lowercase. This will go
// away at some point. // away at some point.
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic, console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
"help " + capitalizedTopic, "help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'", "Get help on plugin command '" + topic + "'",
HandleCommanderHelp); HandleCommanderHelp);
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic, console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
"help " + capitalizedTopic, "help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'", "Get help on plugin command '" + topic + "'",
HandleCommanderHelp); HandleCommanderHelp);
@ -289,14 +288,13 @@ namespace OpenSim
foreach (string command in commander.Commands.Keys) foreach (string command in commander.Commands.Keys)
{ {
m_console.Commands.AddCommand(capitalizedTopic, false, console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command, topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(), topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand); String.Empty, HandleCommanderCommand);
} }
} }
} }
}
private void HandleCommanderCommand(string module, string[] cmd) private void HandleCommanderCommand(string module, string[] cmd)
{ {

View File

@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
//scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
scene.EventManager.OnNewClient += OnNewClient; // scene.EventManager.OnNewClient += OnNewClient;
// TODO: Leaving these open, or closing them when we // TODO: Leaving these open, or closing them when we
// become a child is incorrect. It messes up TP in a big // become a child is incorrect. It messes up TP in a big
@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden
// circuit is there. // circuit is there.
scene.EventManager.OnClientClosed += ClientClosed; scene.EventManager.OnClientClosed += ClientClosed;
scene.EventManager.OnMakeChildAgent += MakeChildAgent; scene.EventManager.OnMakeChildAgent += MakeChildAgent;
scene.EventManager.OnRegisterCaps += OnRegisterCaps; scene.EventManager.OnRegisterCaps += OnRegisterCaps;
@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden
#endregion #endregion
private void OnNewClient(IClientAPI client)
{
//client.OnLogout += ClientClosed;
}
// private void ClientClosed(IClientAPI client)
// {
// ClientClosed(client.AgentId);
// }
private void ClientClosed(UUID agentID, Scene scene) private void ClientClosed(UUID agentID, Scene scene)
{ {
// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); // m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);

View File

@ -47,6 +47,7 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
using AssetLandmark = OpenSim.Framework.AssetLandmark; using AssetLandmark = OpenSim.Framework.AssetLandmark;
using RegionFlags = OpenMetaverse.RegionFlags;
using Nini.Config; using Nini.Config;
using System.IO; using System.IO;
@ -3983,7 +3984,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation; packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@ -4028,7 +4030,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation; packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@ -4036,7 +4040,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < blocks.Count; i++) for (int i = 0; i < blocks.Count; i++)
packet.ObjectData[i] = blocks[i]; packet.ObjectData[i] = blocks[i];
OutPacket(packet, ThrottleOutPacketType.Task, true); OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
} }
#endregion Packet Sending #endregion Packet Sending
@ -5037,7 +5041,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
= PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
block.Data = data; block.Data = data;
if (textureEntry != null && textureEntry.Length > 0) if (textureEntry != null && textureEntry.Length > 0)
@ -11949,7 +11955,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
logPacket = false; logPacket = false;
if (DebugPacketLevel <= 50 if (DebugPacketLevel <= 50
& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
logPacket = false; logPacket = false;
if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily) if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@ -12481,7 +12487,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation; packet.RegionData.TimeDilation = timeDilation;
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];

View File

@ -100,9 +100,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>The measured resolution of Environment.TickCount</summary> /// <summary>The measured resolution of Environment.TickCount</summary>
public readonly float TickCountResolution; public readonly float TickCountResolution;
/// <summary>Number of prim updates to put on the queue each time the /// <summary>Number of prim updates to put on the queue each time the
/// OnQueueEmpty event is triggered for updates</summary> /// OnQueueEmpty event is triggered for updates</summary>
public readonly int PrimUpdatesPerCallback; public readonly int PrimUpdatesPerCallback;
/// <summary>Number of texture packets to put on the queue each time the /// <summary>Number of texture packets to put on the queue each time the
/// OnQueueEmpty event is triggered for textures</summary> /// OnQueueEmpty event is triggered for textures</summary>
public readonly int TextureSendLimit; public readonly int TextureSendLimit;
@ -124,28 +126,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Manages authentication for agent circuits</summary> /// <summary>Manages authentication for agent circuits</summary>
private AgentCircuitManager m_circuitManager; private AgentCircuitManager m_circuitManager;
/// <summary>Reference to the scene this UDP server is attached to</summary> /// <summary>Reference to the scene this UDP server is attached to</summary>
protected Scene m_scene; protected Scene m_scene;
/// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
private Location m_location; private Location m_location;
/// <summary>The size of the receive buffer for the UDP socket. This value /// <summary>The size of the receive buffer for the UDP socket. This value
/// is passed up to the operating system and used in the system networking /// is passed up to the operating system and used in the system networking
/// stack. Use zero to leave this value as the default</summary> /// stack. Use zero to leave this value as the default</summary>
private int m_recvBufferSize; private int m_recvBufferSize;
/// <summary>Flag to process packets asynchronously or synchronously</summary> /// <summary>Flag to process packets asynchronously or synchronously</summary>
private bool m_asyncPacketHandling; private bool m_asyncPacketHandling;
/// <summary>Tracks whether or not a packet was sent each round so we know /// <summary>Tracks whether or not a packet was sent each round so we know
/// whether or not to sleep</summary> /// whether or not to sleep</summary>
private bool m_packetSent; private bool m_packetSent;
/// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
private int m_elapsedMSSinceLastStatReport = 0; private int m_elapsedMSSinceLastStatReport = 0;
/// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
private int m_tickLastOutgoingPacketHandler; private int m_tickLastOutgoingPacketHandler;
/// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
private int m_elapsedMSOutgoingPacketHandler; private int m_elapsedMSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed100MSOutgoingPacketHandler; private int m_elapsed100MSOutgoingPacketHandler;
/// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
private int m_elapsed500MSOutgoingPacketHandler; private int m_elapsed500MSOutgoingPacketHandler;
@ -425,6 +436,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
byte[] data = packet.ToBytes(); byte[] data = packet.ToBytes();
SendPacketData(udpClient, data, packet.Type, category, method); SendPacketData(udpClient, data, packet.Type, category, method);
} }
PacketPool.Instance.ReturnPacket(packet);
} }
/// <summary> /// <summary>
@ -742,7 +755,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
try try
{ {
packet = Packet.BuildPacket(buffer.Data, ref packetEnd, // packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
// // Only allocate a buffer for zerodecoding if the packet is zerocoded
// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
// Only allocate a buffer for zerodecoding if the packet is zerocoded // Only allocate a buffer for zerodecoding if the packet is zerocoded
((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
} }
@ -761,7 +777,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
if (m_malformedCount < 100) if (m_malformedCount < 100)
m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
m_malformedCount++; m_malformedCount++;
if ((m_malformedCount % 100000) == 0) if ((m_malformedCount % 100000) == 0)
m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
} }
@ -1169,9 +1187,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
IClientAPI client = null; IClientAPI client = null;
// In priciple there shouldn't be more than one thread here, ever. // We currently synchronize this code across the whole scene to avoid issues such as
// But in case that happens, we need to synchronize this piece of code // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
// because it's too important // consistently, this lock could probably be removed.
lock (this) lock (this)
{ {
if (!m_scene.TryGetClient(agentID, out client)) if (!m_scene.TryGetClient(agentID, out client))

View File

@ -31,6 +31,7 @@ using System.Reflection;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.Packets; using OpenMetaverse.Packets;
using log4net; using log4net;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Region.ClientStack.LindenUDP namespace OpenSim.Region.ClientStack.LindenUDP
{ {
@ -43,17 +44,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private bool packetPoolEnabled = true; private bool packetPoolEnabled = true;
private bool dataBlockPoolEnabled = true; private bool dataBlockPoolEnabled = true;
private PercentageStat m_packetsReusedStat = new PercentageStat(
"PacketsReused",
"Packets reused",
"clientstack",
"packetpool",
StatVerbosity.Debug,
"Number of packets reused out of all requests to the packet pool");
private PercentageStat m_blocksReusedStat = new PercentageStat(
"BlocksReused",
"Blocks reused",
"clientstack",
"packetpool",
StatVerbosity.Debug,
"Number of data blocks reused out of all requests to the packet pool");
/// <summary> /// <summary>
/// Pool of packets available for reuse. /// Pool of packets available for reuse.
/// </summary> /// </summary>
private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>(); private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
private static Dictionary<Type, Stack<Object>> DataBlocks = private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
new Dictionary<Type, Stack<Object>>();
static PacketPool()
{
}
public static PacketPool Instance public static PacketPool Instance
{ {
@ -72,8 +84,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
get { return dataBlockPoolEnabled; } get { return dataBlockPoolEnabled; }
} }
private PacketPool()
{
StatsManager.RegisterStat(m_packetsReusedStat);
StatsManager.RegisterStat(m_blocksReusedStat);
}
/// <summary>
/// Gets a packet of the given type.
/// </summary>
/// <param name='type'></param>
/// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
public Packet GetPacket(PacketType type) public Packet GetPacket(PacketType type)
{ {
m_packetsReusedStat.Consequent++;
Packet packet; Packet packet;
if (!packetPoolEnabled) if (!packetPoolEnabled)
@ -89,6 +114,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
else else
{ {
// Recycle old packages // Recycle old packages
m_packetsReusedStat.Antecedent++;
packet = (pool[type]).Pop(); packet = (pool[type]).Pop();
} }
} }
@ -138,7 +165,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
PacketType type = GetType(bytes); PacketType type = GetType(bytes);
Array.Clear(zeroBuffer, 0, zeroBuffer.Length); // Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
int i = 0; int i = 0;
Packet packet = GetPacket(type); Packet packet = GetPacket(type);
@ -185,6 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
switch (packet.Type) switch (packet.Type)
{ {
// List pooling packets here // List pooling packets here
case PacketType.AgentUpdate:
case PacketType.PacketAck: case PacketType.PacketAck:
case PacketType.ObjectUpdate: case PacketType.ObjectUpdate:
case PacketType.ImprovedTerseObjectUpdate: case PacketType.ImprovedTerseObjectUpdate:
@ -211,17 +239,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
} }
public static T GetDataBlock<T>() where T: new() public T GetDataBlock<T>() where T: new()
{ {
lock (DataBlocks) lock (DataBlocks)
{ {
m_blocksReusedStat.Consequent++;
Stack<Object> s; Stack<Object> s;
if (DataBlocks.TryGetValue(typeof(T), out s)) if (DataBlocks.TryGetValue(typeof(T), out s))
{ {
if (s.Count > 0) if (s.Count > 0)
{
m_blocksReusedStat.Antecedent++;
return (T)s.Pop(); return (T)s.Pop();
} }
}
else else
{ {
DataBlocks[typeof(T)] = new Stack<Object>(); DataBlocks[typeof(T)] = new Stack<Object>();
@ -231,7 +264,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
} }
public static void ReturnDataBlock<T>(T block) where T: new() public void ReturnDataBlock<T>(T block) where T: new()
{ {
if (block == null) if (block == null)
return; return;

View File

@ -43,7 +43,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
/// This will contain basic tests for the LindenUDP client stack /// This will contain basic tests for the LindenUDP client stack
/// </summary> /// </summary>
[TestFixture] [TestFixture]
public class BasicCircuitTests public class BasicCircuitTests : OpenSimTestCase
{ {
private Scene m_scene; private Scene m_scene;
private TestLLUDPServer m_udpServer; private TestLLUDPServer m_udpServer;
@ -143,7 +143,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public void TestAddClient() public void TestAddClient()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// XmlConfigurator.Configure(); // TestHelpers.EnableLogging();
AddUdpServer(); AddUdpServer();

View File

@ -212,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{ {
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID);
GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID); GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
@ -232,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return true; return true;
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
return true; return true;
return false; return false;
@ -256,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
reason = string.Empty; reason = string.Empty;
logout = false; logout = false;
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{ {
// this user is going to another grid // this user is going to another grid
// check if HyperGrid teleport is allowed, based on user level // check if HyperGrid teleport is allowed, based on user level
@ -303,7 +303,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// The rest is only needed for controlling appearance // The rest is only needed for controlling appearance
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{ {
// this user is going to another grid // this user is going to another grid
if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID)) if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID))

View File

@ -40,6 +40,7 @@ using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using RegionFlags = OpenMetaverse.RegionFlags;
namespace OpenSim.Region.CoreModules.World.Estate namespace OpenSim.Region.CoreModules.World.Estate
{ {

View File

@ -33,6 +33,7 @@ using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using RegionFlags = OpenMetaverse.RegionFlags;
namespace OpenSim.Region.CoreModules.World.Land namespace OpenSim.Region.CoreModules.World.Land
{ {

View File

@ -27,6 +27,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -83,29 +84,56 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"Objects", false, "delete object owner", "Objects", false, "delete object owner",
"delete object owner <UUID>", "delete object owner <UUID>",
"Delete a scene object by owner", HandleDeleteObject); "Delete scene objects by owner",
"Command will ask for confirmation before proceeding.",
HandleDeleteObject);
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"Objects", false, "delete object creator", "Objects", false, "delete object creator",
"delete object creator <UUID>", "delete object creator <UUID>",
"Delete a scene object by creator", HandleDeleteObject); "Delete scene objects by creator",
"Command will ask for confirmation before proceeding.",
HandleDeleteObject);
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"Objects", false, "delete object uuid", "Objects", false, "delete object uuid",
"delete object uuid <UUID>", "delete object uuid <UUID>",
"Delete a scene object by uuid", HandleDeleteObject); "Delete a scene object by uuid",
HandleDeleteObject);
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"Objects", false, "delete object name", "Objects", false, "delete object name",
"delete object name [--regex] <name>", "delete object name [--regex] <name>",
"Delete a scene object by name.", "Delete a scene object by name.",
"If --regex is specified then the name is treatead as a regular expression", "Command will ask for confirmation before proceeding.\n"
+ "If --regex is specified then the name is treatead as a regular expression",
HandleDeleteObject); HandleDeleteObject);
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"Objects", false, "delete object outside", "Objects", false, "delete object outside",
"delete object outside", "delete object outside",
"Delete all scene objects outside region boundaries", HandleDeleteObject); "Delete all scene objects outside region boundaries",
"Command will ask for confirmation before proceeding.",
HandleDeleteObject);
m_console.Commands.AddCommand(
"Objects",
false,
"delete object pos",
"delete object pos <start-coord> to <end-coord>",
"Delete scene objects within the given area.",
"Each component of the coord is comma separated. There must be no spaces between the commas.\n"
+ "If you don't care about the z component you can simply omit it.\n"
+ "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
+ "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
+ "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
+ "e.g.\n"
+ "delete object pos 20,20,20 to 40,40,40\n"
+ "delete object pos 20,20 to 40,40\n"
+ "delete object pos ,20,20 to ,40,40\n"
+ "delete object pos ,,30 to ,,~\n"
+ "delete object pos ,,-~ to ,,30",
HandleDeleteObject);
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"Objects", "Objects",
@ -301,23 +329,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
return; return;
} }
string rawConsoleStartVector = cmdparams[3]; Vector3 startVector, endVector;
Vector3 startVector;
if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector)) if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
{
m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
return; return;
}
string rawConsoleEndVector = cmdparams[5];
Vector3 endVector;
if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
{
m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
return;
}
Predicate<SceneObjectGroup> searchPredicate Predicate<SceneObjectGroup> searchPredicate
= so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector); = so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector);
@ -557,6 +572,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
break; break;
case "pos":
deletes = GetDeleteCandidatesByPos(module, cmd);
break;
default: default:
m_console.OutputFormat("Unrecognized mode {0}", mode); m_console.OutputFormat("Unrecognized mode {0}", mode);
return; return;
@ -571,7 +590,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
string.Format( string.Format(
"Are you sure that you want to delete {0} objects from {1}", "Are you sure that you want to delete {0} objects from {1}",
deletes.Count, m_scene.RegionInfo.RegionName), deletes.Count, m_scene.RegionInfo.RegionName),
"n"); "y/N");
if (response.ToLower() != "y") if (response.ToLower() != "y")
{ {
@ -593,9 +612,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams) private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams)
{ {
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
return null;
bool useRegex = false; bool useRegex = false;
OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
@ -629,5 +645,52 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
return sceneObjects; return sceneObjects;
} }
/// <summary>
/// Get scene object delete candidates by position
/// </summary>
/// <param name='module'></param>
/// <param name='cmdparams'></param>
/// <returns>null if parsing failed on one of the arguments, otherwise a list of objects to delete. If there
/// are no objects to delete then the list will be empty./returns>
private List<SceneObjectGroup> GetDeleteCandidatesByPos(string module, string[] cmdparams)
{
if (cmdparams.Length < 5)
{
m_console.OutputFormat("Usage: delete object pos <start-coord> to <end-coord>");
return null;
}
Vector3 startVector, endVector;
if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
return null;
return m_scene.GetSceneObjectGroups().FindAll(
so => !so.IsAttachment && Util.IsInsideBox(so.AbsolutePosition, startVector, endVector));
}
private bool TryParseVectorRange(IEnumerable<string> rawComponents, out Vector3 startVector, out Vector3 endVector)
{
string rawConsoleStartVector = rawComponents.Take(1).Single();
if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
{
m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
endVector = Vector3.Zero;
return false;
}
string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single();
if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
{
m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
return false;
}
return true;
}
} }
} }

View File

@ -125,13 +125,21 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This is triggered for both child and root agent client connections. /// This is triggered for both child and root agent client connections.
///
/// Triggered before OnClientLogin. /// Triggered before OnClientLogin.
///
/// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
/// do this on a separate thread.
/// </remarks> /// </remarks>
public event OnNewClientDelegate OnNewClient; public event OnNewClientDelegate OnNewClient;
/// <summary> /// <summary>
/// Fired if the client entering this sim is doing so as a new login /// Fired if the client entering this sim is doing so as a new login
/// </summary> /// </summary>
/// <remarks>
/// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
/// do this on a separate thread.
/// </remarks>
public event Action<IClientAPI> OnClientLogin; public event Action<IClientAPI> OnClientLogin;
public delegate void OnNewPresenceDelegate(ScenePresence presence); public delegate void OnNewPresenceDelegate(ScenePresence presence);
@ -153,6 +161,9 @@ namespace OpenSim.Region.Framework.Scenes
/// <remarks> /// <remarks>
/// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both
/// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see> /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
///
/// Triggered under per-agent lock. So if you want to perform any long-running operations, please
/// do this on a separate thread.
/// </remarks> /// </remarks>
public event OnRemovePresenceDelegate OnRemovePresence; public event OnRemovePresenceDelegate OnRemovePresence;
@ -429,6 +440,9 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// At the point of firing, the scene still contains the client's scene presence. /// At the point of firing, the scene still contains the client's scene presence.
///
/// This is triggered under per-agent lock. So if you want to perform any long-running operations, please
/// do this on a separate thread.
/// </remarks> /// </remarks>
public event ClientClosed OnClientClosed; public event ClientClosed OnClientClosed;
@ -917,7 +931,7 @@ namespace OpenSim.Region.Framework.Scenes
public event SceneObjectPartCopyDelegate OnSceneObjectPartCopy; public event SceneObjectPartCopyDelegate OnSceneObjectPartCopy;
public delegate void SceneObjectPartCopyDelegate(SceneObjectPart copy, SceneObjectPart original, bool userExposed); public delegate void SceneObjectPartCopyDelegate(SceneObjectPart copy, SceneObjectPart original, bool userExposed);
public delegate void SceneObjectPartUpdated(SceneObjectPart sop); public delegate void SceneObjectPartUpdated(SceneObjectPart sop, bool full);
public event SceneObjectPartUpdated OnSceneObjectPartUpdated; public event SceneObjectPartUpdated OnSceneObjectPartUpdated;
public delegate void ScenePresenceUpdated(ScenePresence sp); public delegate void ScenePresenceUpdated(ScenePresence sp);
@ -2862,7 +2876,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
public void TriggerSceneObjectPartUpdated(SceneObjectPart sop) public void TriggerSceneObjectPartUpdated(SceneObjectPart sop, bool full)
{ {
SceneObjectPartUpdated handler = OnSceneObjectPartUpdated; SceneObjectPartUpdated handler = OnSceneObjectPartUpdated;
if (handler != null) if (handler != null)
@ -2871,7 +2885,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
try try
{ {
d(sop); d(sop, full);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -79,6 +79,11 @@ namespace OpenSim.Region.Framework.Scenes
public SynchronizeSceneHandler SynchronizeScene; public SynchronizeSceneHandler SynchronizeScene;
/// <summary>
/// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other.
/// </summary>
private object m_removeClientLock = new object();
/// <summary> /// <summary>
/// Statistical information for this scene. /// Statistical information for this scene.
/// </summary> /// </summary>
@ -308,6 +313,31 @@ namespace OpenSim.Region.Framework.Scenes
} }
private volatile bool m_shuttingDown; private volatile bool m_shuttingDown;
/// <summary>
/// Is the scene active?
/// </summary>
/// <remarks>
/// If false, maintenance and update loops are not being run. Updates can still be triggered manually if
/// the scene is not active.
/// </remarks>
public bool Active
{
get { return m_active; }
set
{
if (value)
{
if (!m_active)
Start();
}
else
{
m_active = false;
}
}
}
private volatile bool m_active;
// private int m_lastUpdate; // private int m_lastUpdate;
private bool m_firstHeartbeat = true; private bool m_firstHeartbeat = true;
@ -1187,6 +1217,14 @@ namespace OpenSim.Region.Framework.Scenes
public void SetSceneCoreDebug(Dictionary<string, string> options) public void SetSceneCoreDebug(Dictionary<string, string> options)
{ {
if (options.ContainsKey("active"))
{
bool active;
if (bool.TryParse(options["active"], out active))
Active = active;
}
if (options.ContainsKey("scripting")) if (options.ContainsKey("scripting"))
{ {
bool enableScripts = true; bool enableScripts = true;
@ -1326,6 +1364,8 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
public void Start() public void Start()
{ {
m_active = true;
// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName); // m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName);
//m_heartbeatTimer.Enabled = true; //m_heartbeatTimer.Enabled = true;
@ -1382,7 +1422,7 @@ namespace OpenSim.Region.Framework.Scenes
#region Update Methods #region Update Methods
/// <summary> /// <summary>
/// Performs per-frame updates regularly /// Activate the various loops necessary to continually update the scene.
/// </summary> /// </summary>
private void Heartbeat() private void Heartbeat()
{ {
@ -1439,7 +1479,7 @@ namespace OpenSim.Region.Framework.Scenes
List<Vector3> coarseLocations; List<Vector3> coarseLocations;
List<UUID> avatarUUIDs; List<UUID> avatarUUIDs;
while (!m_shuttingDown && (endRun == null || MaintenanceRun < endRun)) while (!m_shuttingDown && ((endRun == null && Active) || MaintenanceRun < endRun))
{ {
runtc = Util.EnvironmentTickCount(); runtc = Util.EnvironmentTickCount();
++MaintenanceRun; ++MaintenanceRun;
@ -1501,7 +1541,7 @@ namespace OpenSim.Region.Framework.Scenes
int sleepMS; int sleepMS;
int framestart; int framestart;
while (!m_shuttingDown && (endFrame == null || Frame < endFrame)) while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame))
{ {
framestart = Util.EnvironmentTickCount(); framestart = Util.EnvironmentTickCount();
++Frame; ++Frame;
@ -2218,10 +2258,14 @@ namespace OpenSim.Region.Framework.Scenes
public bool AddRestoredSceneObject( public bool AddRestoredSceneObject(
SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
{ {
bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); if (m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates))
if (result) {
sceneObject.IsDeleted = false; sceneObject.IsDeleted = false;
return result; EventManager.TriggerObjectAddedToScene(sceneObject);
return true;
}
return false;
} }
/// <summary> /// <summary>
@ -2862,16 +2906,35 @@ namespace OpenSim.Region.Framework.Scenes
public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
{ {
ScenePresence sp;
bool vialogin;
// Validation occurs in LLUDPServer // Validation occurs in LLUDPServer
//
// XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with
// each other. In practice, this does not currently occur in the code.
AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
bool vialogin // We lock here on AgentCircuitData to prevent a race condition between the thread adding a new connection
// and a simultaneous one that removes it (as can happen if the client is closed at a particular point
// whilst connecting).
//
// It would be easier to lock across all NewUserConnection(), AddNewClient() and
// RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
// response in some module listening to AddNewClient()) from holding up unrelated agent calls.
//
// In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
// AddNewClient() operations (though not other ops).
// In the future this can be relieved once locking per agent (not necessarily on AgentCircuitData) is improved.
lock (aCircuit)
{
vialogin
= (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
|| (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
CheckHeartbeat(); CheckHeartbeat();
ScenePresence sp = GetScenePresence(client.AgentId); sp = GetScenePresence(client.AgentId);
// XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
// could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
@ -2916,23 +2979,16 @@ namespace OpenSim.Region.Framework.Scenes
// client is for a root or child agent. // client is for a root or child agent.
client.SceneAgent = sp; client.SceneAgent = sp;
m_LastLogin = Util.EnvironmentTickCount();
// Cache the user's name // Cache the user's name
CacheUserName(sp, aCircuit); CacheUserName(sp, aCircuit);
EventManager.TriggerOnNewClient(client); EventManager.TriggerOnNewClient(client);
if (vialogin) if (vialogin)
{
EventManager.TriggerOnClientLogin(client); EventManager.TriggerOnClientLogin(client);
// Send initial parcel data
/* this is done on TriggerOnNewClient by landmanegement respective event handler
Vector3 pos = sp.AbsolutePosition;
ILandObject land = LandChannel.GetLandObject(pos.X, pos.Y);
land.SendLandUpdateToClient(client);
*/
} }
m_LastLogin = Util.EnvironmentTickCount();
return sp; return sp;
} }
@ -3472,6 +3528,27 @@ namespace OpenSim.Region.Framework.Scenes
{ {
// CheckHeartbeat(); // CheckHeartbeat();
bool isChildAgent = false; bool isChildAgent = false;
AgentCircuitData acd;
lock (m_removeClientLock)
{
acd = m_authenticateHandler.GetAgentCircuitData(agentID);
if (acd == null)
{
m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
return;
}
else
{
// We remove the acd up here to avoid later raec conditions if two RemoveClient() calls occurred
// simultaneously.
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
}
}
lock (acd)
{
ScenePresence avatar = GetScenePresence(agentID); ScenePresence avatar = GetScenePresence(agentID);
if (avatar == null) if (avatar == null)
@ -3551,8 +3628,6 @@ namespace OpenSim.Region.Framework.Scenes
// It's possible for child agents to have transactions if changes are being made cross-border. // It's possible for child agents to have transactions if changes are being made cross-border.
if (AgentTransactionsModule != null) if (AgentTransactionsModule != null)
AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
m_log.Debug("[Scene] The avatar has left the building"); m_log.Debug("[Scene] The avatar has left the building");
} }
catch (Exception e) catch (Exception e)
@ -3578,6 +3653,7 @@ namespace OpenSim.Region.Framework.Scenes
string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e); string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
} }
} }
}
//m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
//m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
@ -3634,11 +3710,9 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// Do the work necessary to initiate a new user connection for a particular scene. /// Do the work necessary to initiate a new user connection for a particular scene.
/// At the moment, this consists of setting up the caps infrastructure
/// The return bool should allow for connections to be refused, but as not all calling paths
/// take proper notice of it let, we allowed banned users in still.
/// </summary> /// </summary>
/// <param name="agent">CircuitData of the agent who is connecting</param> /// <param name="agent">CircuitData of the agent who is connecting</param>
/// <param name="teleportFlags"></param>
/// <param name="reason">Outputs the reason for the false response on this string</param> /// <param name="reason">Outputs the reason for the false response on this string</param>
/// <returns>True if the region accepts this agent. False if it does not. False will /// <returns>True if the region accepts this agent. False if it does not. False will
/// also return a reason.</returns> /// also return a reason.</returns>
@ -3649,10 +3723,20 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// Do the work necessary to initiate a new user connection for a particular scene. /// Do the work necessary to initiate a new user connection for a particular scene.
/// At the moment, this consists of setting up the caps infrastructure /// </summary>
/// <remarks>
/// The return bool should allow for connections to be refused, but as not all calling paths
/// take proper notice of it yet, we still allowed banned users in.
///
/// At the moment this method consists of setting up the caps infrastructure
/// The return bool should allow for connections to be refused, but as not all calling paths /// The return bool should allow for connections to be refused, but as not all calling paths
/// take proper notice of it let, we allowed banned users in still. /// take proper notice of it let, we allowed banned users in still.
/// </summary> ///
/// This method is called by the login service (in the case of login) or another simulator (in the case of region
/// cross or teleport) to initiate the connection. It is not triggered by the viewer itself - the connection
/// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
/// the LLUDP stack).
/// </remarks>
/// <param name="agent">CircuitData of the agent who is connecting</param> /// <param name="agent">CircuitData of the agent who is connecting</param>
/// <param name="reason">Outputs the reason for the false response on this string</param> /// <param name="reason">Outputs the reason for the false response on this string</param>
/// <param name="requirePresenceLookup">True for normal presence. False for NPC /// <param name="requirePresenceLookup">True for normal presence. False for NPC
@ -3755,7 +3839,8 @@ namespace OpenSim.Region.Framework.Scenes
sp = null; sp = null;
} }
lock (agent)
{
//On login test land permisions //On login test land permisions
if (vialogin) if (vialogin)
{ {
@ -3812,7 +3897,8 @@ namespace OpenSim.Region.Framework.Scenes
CapsModule.SetAgentCapsSeeds(agent); CapsModule.SetAgentCapsSeeds(agent);
CapsModule.CreateCaps(agent.AgentID); CapsModule.CreateCaps(agent.AgentID);
} }
} else }
else
{ {
// Let the SP know how we got here. This has a lot of interesting // Let the SP know how we got here. This has a lot of interesting
// uses down the line. // uses down the line.
@ -3830,6 +3916,7 @@ namespace OpenSim.Region.Framework.Scenes
CapsModule.SetAgentCapsSeeds(agent); CapsModule.SetAgentCapsSeeds(agent);
} }
} }
}
// In all cases, add or update the circuit data with the new agent circuit data and teleport flags // In all cases, add or update the circuit data with the new agent circuit data and teleport flags
agent.teleportFlags = teleportFlags; agent.teleportFlags = teleportFlags;

View File

@ -3082,7 +3082,7 @@ namespace OpenSim.Region.Framework.Scenes
// UUID, Name, TimeStampFull); // UUID, Name, TimeStampFull);
if (ParentGroup.Scene != null) if (ParentGroup.Scene != null)
ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this); ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, true);
} }
/// <summary> /// <summary>
@ -3116,7 +3116,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
if (ParentGroup.Scene != null) if (ParentGroup.Scene != null)
ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this); ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, false);
} }
public void ScriptSetPhysicsStatus(bool UsePhysics) public void ScriptSetPhysicsStatus(bool UsePhysics)

View File

@ -263,7 +263,7 @@ public class BSCharacter : BSPhysObject
// A version of the sanity check that also makes sure a new position value is // A version of the sanity check that also makes sure a new position value is
// pushed back to the physics engine. This routine would be used by anyone // pushed back to the physics engine. This routine would be used by anyone
// who is not already pushing the value. // who is not already pushing the value.
private bool PositionSanityCheck2(bool atTaintTime) private bool PositionSanityCheck2(bool inTaintTime)
{ {
bool ret = false; bool ret = false;
if (PositionSanityCheck()) if (PositionSanityCheck())
@ -275,7 +275,7 @@ public class BSCharacter : BSPhysObject
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
}; };
if (atTaintTime) if (inTaintTime)
sanityOperation(); sanityOperation();
else else
PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation); PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
@ -332,6 +332,13 @@ public class BSCharacter : BSPhysObject
}); });
} }
} }
public override OMV.Vector3 ForceVelocity {
get { return _velocity; }
set {
_velocity = value;
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
}
}
public override OMV.Vector3 Torque { public override OMV.Vector3 Torque {
get { return _torque; } get { return _torque; }
set { _torque = value; set { _torque = value;
@ -432,6 +439,10 @@ public class BSCharacter : BSPhysObject
get { return _rotationalVelocity; } get { return _rotationalVelocity; }
set { _rotationalVelocity = value; } set { _rotationalVelocity = value; }
} }
public override OMV.Vector3 ForceRotationalVelocity {
get { return _rotationalVelocity; }
set { _rotationalVelocity = value; }
}
public override bool Kinematic { public override bool Kinematic {
get { return _kinematic; } get { return _kinematic; }
set { _kinematic = value; } set { _kinematic = value; }

View File

@ -49,11 +49,18 @@ public abstract class BSConstraint : IDisposable
if (m_enabled) if (m_enabled)
{ {
m_enabled = false; m_enabled = false;
if (m_constraint.ptr != IntPtr.Zero)
{
bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
BSScene.DetailLogZero,
m_body1.ID, m_body1.ptr.ToString("X"),
m_body2.ID, m_body2.ptr.ToString("X"),
success);
m_constraint.ptr = System.IntPtr.Zero; m_constraint.ptr = System.IntPtr.Zero;
} }
} }
}
public BulletBody Body1 { get { return m_body1; } } public BulletBody Body1 { get { return m_body1; } }
public BulletBody Body2 { get { return m_body2; } } public BulletBody Body2 { get { return m_body2; } }

View File

@ -462,7 +462,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
return; return;
// Set the prim's inertia to zero. The vehicle code handles that and this // Set the prim's inertia to zero. The vehicle code handles that and this
// removes the torque action introduced by Bullet. // removes the motion and torque actions introduced by Bullet.
Vector3 inertia = Vector3.Zero; Vector3 inertia = Vector3.Zero;
BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
@ -481,7 +481,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_lastPositionVector = Prim.ForcePosition; m_lastPositionVector = Prim.ForcePosition;
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.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity); Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
}// end Step }// end Step
// Apply the effect of the linear motor. // Apply the effect of the linear motor.
@ -540,7 +540,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// add Gravity and Buoyancy // add 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 * (Prim.Mass * (1f - m_VehicleBuoyancy)); Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy));
/* /*
* RA: Not sure why one would do this * RA: Not sure why one would do this
@ -678,10 +678,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_newVelocity.Z = 0; m_newVelocity.Z = 0;
// Apply velocity // Apply velocity
Prim.Velocity = m_newVelocity; Prim.ForceVelocity = m_newVelocity;
// apply gravity force // apply gravity force
// Why is this set here? The physics engine already does gravity. // Why is this set here? The physics engine already does gravity.
// m_prim.AddForce(grav, false); Prim.AddForce(grav, false, true);
// Apply friction // Apply friction
Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep));
@ -704,7 +704,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// m_lastAngularVelocity // what was last applied to body // m_lastAngularVelocity // what was last applied to body
// Get what the body is doing, this includes 'external' influences // Get what the body is doing, this includes 'external' influences
Vector3 angularVelocity = Prim.RotationalVelocity; Vector3 angularVelocity = Prim.ForceRotationalVelocity;
if (m_angularMotorApply > 0) if (m_angularMotorApply > 0)
{ {
@ -810,7 +810,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
// Apply to the body // Apply to the body
Prim.RotationalVelocity = m_lastAngularVelocity; Prim.ForceRotationalVelocity = m_lastAngularVelocity;
VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity); VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
} //end MoveAngular } //end MoveAngular
@ -862,7 +862,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
private void VDetailLog(string msg, params Object[] args) private void VDetailLog(string msg, params Object[] args)
{ {
if (Prim.PhysicsScene.VehicleLoggingEnabled) if (Prim.PhysicsScene.VehicleLoggingEnabled)
Prim.PhysicsScene.PhysicsLogging.Write(msg, args); Prim.PhysicsScene.DetailLog(msg, args);
} }
} }
} }

View File

@ -52,8 +52,8 @@ public class BSLinkset
// the physical 'taint' children separately. // the physical 'taint' children separately.
// After taint processing and before the simulation step, these // After taint processing and before the simulation step, these
// two lists must be the same. // two lists must be the same.
private List<BSPhysObject> m_children; private HashSet<BSPhysObject> m_children;
private List<BSPhysObject> m_taintChildren; private HashSet<BSPhysObject> m_taintChildren;
// We lock the diddling of linkset classes to prevent any badness. // We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes // This locks the modification of the instances of this class. Changes
@ -90,8 +90,8 @@ public class BSLinkset
m_nextLinksetID = 1; m_nextLinksetID = 1;
PhysicsScene = scene; PhysicsScene = scene;
LinksetRoot = parent; LinksetRoot = parent;
m_children = new List<BSPhysObject>(); m_children = new HashSet<BSPhysObject>();
m_taintChildren = new List<BSPhysObject>(); m_taintChildren = new HashSet<BSPhysObject>();
m_mass = parent.MassRaw; m_mass = parent.MassRaw;
} }
@ -160,6 +160,28 @@ public class BSLinkset
return ret; return ret;
} }
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// May be called at runtime or taint-time (just pass the appropriate flag).
public void Refresh(BSPhysObject requestor, bool inTaintTime)
{
// If there are no children, not physical or not root, I am not the one that recomputes the constraints
// (For the moment, static linksets do create constraints so remove the test for physical.)
if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
return;
BSScene.TaintCallback refreshOperation = delegate()
{
RecomputeLinksetConstraintVariables();
DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
};
if (inTaintTime)
refreshOperation();
else
PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
}
// The object is going dynamic (physical). Do any setup necessary // The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset. // for a dynamic linkset.
// Only the state of the passed object can be modified. The rest of the linkset // Only the state of the passed object can be modified. The rest of the linkset
@ -182,22 +204,19 @@ public class BSLinkset
return false; return false;
} }
// When physical properties are changed the linkset needs to recalculate // If the software is handling the movement of all the objects in a linkset
// its internal properties. // (like if one doesn't use constraints for static linksets), this is called
// Called at runtime. // when an update for the root of the linkset is received.
public void Refresh(BSPhysObject requestor) // Called at taint-time!!
public void UpdateProperties(BSPhysObject physObject)
{ {
// If there are no children, there can't be any constraints to recompute // The root local properties have been updated. Apply to the children if appropriate.
if (!HasAnyChildren) if (IsRoot(physObject) && HasAnyChildren)
return;
// Only the root does the recomputation
if (IsRoot(requestor))
{ {
PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() if (!physObject.IsPhysical)
{ {
RecomputeLinksetConstraintVariables(); // TODO: implement software linkset update for static object linksets
}); }
} }
} }
@ -215,13 +234,10 @@ public class BSLinkset
if (IsRoot(child)) if (IsRoot(child))
{ {
// If the one with the dependency is root, must undo all children // If the one with the dependency is root, must undo all children
DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}", DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
foreach (BSPhysObject bpo in m_taintChildren)
{ ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
ret = true;
}
} }
else else
{ {
@ -229,20 +245,16 @@ public class BSLinkset
child.LocalID, child.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X")); child.LocalID, child.BSBody.ptr.ToString("X"));
// Remove the dependency on the body of this one // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
if (m_taintChildren.Contains(child)) // Despite the function name, this removes any link to the specified object.
{ ret = PhysicallyUnlinkAllChildrenFromRoot(child);
PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
ret = true;
}
} }
} }
return ret; return ret;
} }
// Routine used when rebuilding the body of the root of the linkset // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
// This is called after RemoveAllLinksToRoot() to restore all the constraints. // this routine will restore the removed constraints.
// This is called when the root body has been changed.
// Called at taint-time!! // Called at taint-time!!
public void RestoreBodyDependencies(BSPrim child) public void RestoreBodyDependencies(BSPrim child)
{ {
@ -254,7 +266,7 @@ public class BSLinkset
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
foreach (BSPhysObject bpo in m_taintChildren) foreach (BSPhysObject bpo in m_taintChildren)
{ {
PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody); PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
} }
} }
else else
@ -263,7 +275,7 @@ public class BSLinkset
LinksetRoot.LocalID, LinksetRoot.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X")); child.LocalID, child.BSBody.ptr.ToString("X"));
PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody); PhysicallyLinkAChildToRoot(LinksetRoot, child);
} }
} }
} }
@ -330,22 +342,22 @@ public class BSLinkset
{ {
m_children.Add(child); m_children.Add(child);
BSPhysObject rootx = LinksetRoot; // capture the root and body as of now BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child; BSPhysObject childx = child;
DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
rootx.LocalID,
rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
PhysicsScene.TaintedObject("AddChildToLinkset", delegate() PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
{ {
DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
// build the physical binding between me and the child rootx.LocalID,
m_taintChildren.Add(childx); rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
childx.LocalID, childx.BSBody.ptr.ToString("X"));
// Since this is taint-time, the body and shape could have changed for the child // Since this is taint-time, the body and shape could have changed for the child
PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody); rootx.ForcePosition = rootx.Position; // DEBUG
childx.ForcePosition = childx.Position; // DEBUG
PhysicallyLinkAChildToRoot(rootx, childx);
m_taintChildren.Add(child);
}); });
} }
return; return;
@ -378,10 +390,8 @@ public class BSLinkset
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
{ {
if (m_taintChildren.Contains(childx)) m_taintChildren.Remove(child);
m_taintChildren.Remove(childx); PhysicallyUnlinkAChildFromRoot(rootx, childx);
PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody);
RecomputeLinksetConstraintVariables(); RecomputeLinksetConstraintVariables();
}); });
@ -396,8 +406,7 @@ public class BSLinkset
// Create a constraint between me (root of linkset) and the passed prim (the child). // Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time! // Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody, private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
BSPhysObject childPrim, BulletBody childBody)
{ {
// Zero motion for children so they don't interpolate // Zero motion for children so they don't interpolate
childPrim.ZeroMotion(); childPrim.ZeroMotion();
@ -409,33 +418,17 @@ public class BSLinkset
// real world coordinate of midpoint between the two objects // real world coordinate of midpoint between the two objects
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID, rootPrim.LocalID,
rootPrim.LocalID, rootBody.ptr.ToString("X"), rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childBody.ptr.ToString("X"), childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
rootPrim.Position, childPrim.Position, midPoint); rootPrim.Position, childPrim.Position, midPoint);
// create a constraint that allows no freedom of movement between the two objects // create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
// There is great subtlty in these paramters. Notice the check for a ptr of zero.
// We pass the BulletBody structure into the taint in order to capture the pointer
// of the body at the time of constraint creation. This doesn't work for the very first
// construction because there is no body yet. The body
// is constructed later at taint time. Thus we use the body address at time of the
// taint creation but, if it is zero, use what's in the prim at the moment.
// There is a possible race condition since shape can change without a taint call
// (like changing to a mesh that is already constructed). The fix for that would be
// to only change BSShape at taint time thus syncronizing these operations at
// the cost of efficiency and lag.
BS6DofConstraint constrain = new BS6DofConstraint( BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
midPoint,
true,
true
);
/* NOTE: below is an attempt to build constraint with full frame computation, etc. /* NOTE: below is an attempt to build constraint with full frame computation, etc.
* Using the midpoint is easier since it lets the Bullet code manipulate the transforms * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
@ -452,7 +445,7 @@ public class BSLinkset
// create a constraint that allows no freedom of movement between the two objects // create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
BS6DofConstraint constrain = new BS6DofConstraint( BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.Body, childPrim.Body, PhysicsScene.World, rootPrim.Body, childPrim.Body,
OMV.Vector3.Zero, OMV.Vector3.Zero,
@ -486,39 +479,44 @@ public class BSLinkset
{ {
constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
} }
RecomputeLinksetConstraintVariables();
} }
// Remove linkage between myself and a particular child // Remove linkage between myself and a particular child
// The root and child bodies are passed in because we need to remove the constraint between // The root and child bodies are passed in because we need to remove the constraint between
// the bodies that were at unlink time. // the bodies that were at unlink time.
// Called at taint time! // Called at taint time!
private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody, private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
BSPhysObject childPrim, BulletBody childBody)
{ {
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", bool ret = false;
DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
rootPrim.LocalID, rootPrim.LocalID,
rootPrim.LocalID, rootBody.ptr.ToString("X"), rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
childPrim.LocalID, childBody.ptr.ToString("X")); childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
// Find the constraint for this link and get rid of it from the overall collection and from my list // Find the constraint for this link and get rid of it from the overall collection and from my list
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody); if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
{
// Make the child refresh its location // Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr); BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
ret = true;
}
return ret;
} }
/*
// Remove linkage between myself and any possible children I might have. // Remove linkage between myself and any possible children I might have.
// Called at taint time! // Called at taint time!
private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
{ {
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
bool ret = false;
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
{
ret = true;
}
return ret;
} }
*/
// Call each of the constraints that make up this linkset and recompute the // Call each of the constraints that make up this linkset and recompute the
// various transforms and variables. Used when objects are added or removed // various transforms and variables. Used when objects are added or removed
@ -550,11 +548,17 @@ public class BSLinkset
{ {
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
foreach (BSPhysObject child in m_taintChildren) foreach (BSPhysObject child in m_taintChildren)
{ {
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
centerOfMass, OMV.Quaternion.Identity);
} }
// BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
} }
return; return;
} }
@ -563,7 +567,8 @@ public class BSLinkset
// Invoke the detailed logger and output something if it's enabled. // Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args) private void DetailLog(string msg, params Object[] args)
{ {
PhysicsScene.PhysicsLogging.Write(msg, args); if (PhysicsScene.PhysicsLogging.Enabled)
PhysicsScene.DetailLog(msg, args);
} }
} }

View File

@ -85,6 +85,10 @@ public abstract class BSPhysObject : PhysicsActor
public abstract OMV.Quaternion ForceOrientation { get; set; } public abstract OMV.Quaternion ForceOrientation { get; set; }
public abstract OMV.Vector3 ForceVelocity { get; set; }
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
#region Collisions #region Collisions
// Requested number of milliseconds between collision events. Zero means disabled. // Requested number of milliseconds between collision events. Zero means disabled.
@ -207,7 +211,8 @@ public abstract class BSPhysObject : PhysicsActor
// High performance detailed logging routine used by the physical objects. // High performance detailed logging routine used by the physical objects.
protected void DetailLog(string msg, params Object[] args) protected void DetailLog(string msg, params Object[] args)
{ {
PhysicsScene.PhysicsLogging.Write(msg, args); if (PhysicsScene.PhysicsLogging.Enabled)
PhysicsScene.DetailLog(msg, args);
} }
} }
} }

View File

@ -196,7 +196,7 @@ public sealed class BSPrim : BSPhysObject
_isSelected = value; _isSelected = value;
PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
{ {
// DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
SetObjectDynamic(false); SetObjectDynamic(false);
}); });
} }
@ -265,6 +265,11 @@ public sealed class BSPrim : BSPhysObject
return _position; return _position;
} }
set { set {
// If you must push the position into the physics engine, use ForcePosition.
if (_position == value)
{
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();
@ -322,7 +327,7 @@ public sealed class BSPrim : BSPhysObject
// A version of the sanity check that also makes sure a new position value is // A version of the sanity check that also makes sure a new position value is
// pushed back to the physics engine. This routine would be used by anyone // pushed back to the physics engine. This routine would be used by anyone
// who is not already pushing the value. // who is not already pushing the value.
private bool PositionSanityCheck2(bool atTaintTime) private bool PositionSanityCheck2(bool inTaintTime)
{ {
bool ret = false; bool ret = false;
if (PositionSanityCheck()) if (PositionSanityCheck())
@ -334,7 +339,7 @@ public sealed class BSPrim : BSPhysObject
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
}; };
if (atTaintTime) if (inTaintTime)
sanityOperation(); sanityOperation();
else else
PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation); PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
@ -453,7 +458,6 @@ public sealed class BSPrim : BSPhysObject
} }
return; return;
} }
public override OMV.Vector3 Velocity { public override OMV.Vector3 Velocity {
get { return _velocity; } get { return _velocity; }
set { set {
@ -465,6 +469,13 @@ public sealed class BSPrim : BSPhysObject
}); });
} }
} }
public override OMV.Vector3 ForceVelocity {
get { return _velocity; }
set {
_velocity = value;
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
}
}
public override OMV.Vector3 Torque { public override OMV.Vector3 Torque {
get { return _torque; } get { return _torque; }
set { _torque = value; set { _torque = value;
@ -490,6 +501,8 @@ public sealed class BSPrim : BSPhysObject
return _orientation; return _orientation;
} }
set { set {
if (_orientation == value)
return;
_orientation = value; _orientation = value;
// TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
@ -570,7 +583,7 @@ public sealed class BSPrim : BSPhysObject
// Set up the object physicalness (does gravity and collisions move this object) // Set up the object physicalness (does gravity and collisions move this object)
MakeDynamic(IsStatic); MakeDynamic(IsStatic);
// Update vehicle specific parameters // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
_vehicle.Refresh(); _vehicle.Refresh();
// Arrange for collision events if the simulator wants them // Arrange for collision events if the simulator wants them
@ -593,7 +606,7 @@ public sealed class BSPrim : BSPhysObject
// Recompute any linkset parameters. // Recompute any linkset parameters.
// When going from non-physical to physical, this re-enables the constraints that // When going from non-physical to physical, this re-enables the constraints that
// had been automatically disabled when the mass was set to zero. // had been automatically disabled when the mass was set to zero.
Linkset.Refresh(this); Linkset.Refresh(this, true);
DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
@ -620,8 +633,10 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
// There can be special things needed for implementing linksets // There can be special things needed for implementing linksets
Linkset.MakeStatic(this); Linkset.MakeStatic(this);
// The activation state is 'disabled' so Bullet will not try to act on it // The activation state is 'disabled' so Bullet will not try to act on it.
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
// Start it out sleeping and physical actions could wake it up.
// BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
@ -638,6 +653,9 @@ public sealed class BSPrim : BSPhysObject
// per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
BulletSimAPI.ClearAllForces2(BSBody.ptr); BulletSimAPI.ClearAllForces2(BSBody.ptr);
// For good measure, make sure the transform is set through to the motion state
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
// A dynamic object has mass // A dynamic object has mass
IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass); OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
@ -655,8 +673,8 @@ public sealed class BSPrim : BSPhysObject
// Force activation of the object so Bullet will act on it. // Force activation of the object so Bullet will act on it.
// Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
BulletSimAPI.Activate2(BSBody.ptr, true); // BulletSimAPI.Activate2(BSBody.ptr, true);
BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
BSBody.collisionMask = CollisionFilterGroups.ObjectMask; BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
@ -774,6 +792,15 @@ public sealed class BSPrim : BSPhysObject
}); });
} }
} }
public override OMV.Vector3 ForceRotationalVelocity {
get {
return _rotationalVelocity;
}
set {
_rotationalVelocity = value;
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
}
}
public override bool Kinematic { public override bool Kinematic {
get { return _kinematic; } get { return _kinematic; }
set { _kinematic = value; set { _kinematic = value;
@ -828,6 +855,9 @@ public sealed class BSPrim : BSPhysObject
private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
public override void AddForce(OMV.Vector3 force, bool pushforce) { public override void AddForce(OMV.Vector3 force, bool pushforce) {
AddForce(force, pushforce, false);
}
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())
{ {
@ -840,11 +870,12 @@ public sealed class BSPrim : BSPhysObject
m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
return; return;
} }
PhysicsScene.TaintedObject("BSPrim.AddForce", delegate() BSScene.TaintCallback addForceOperation = delegate()
{ {
OMV.Vector3 fSum = OMV.Vector3.Zero; OMV.Vector3 fSum = OMV.Vector3.Zero;
lock (m_accumulatedForces) lock (m_accumulatedForces)
{ {
// Sum the accumulated additional forces for one big force to apply once.
foreach (OMV.Vector3 v in m_accumulatedForces) foreach (OMV.Vector3 v in m_accumulatedForces)
{ {
fSum += v; fSum += v;
@ -854,7 +885,11 @@ public sealed class BSPrim : BSPhysObject
// DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
// For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
}); };
if (inTaintTime)
addForceOperation();
else
PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
} }
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@ -1204,6 +1239,7 @@ public sealed class BSPrim : BSPhysObject
{ {
// Called if the current prim body is about to be destroyed. // Called if the current prim body is about to be destroyed.
// Remove all the physical dependencies on the old body. // Remove all the physical dependencies on the old body.
// (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
}); });
@ -1294,6 +1330,8 @@ public sealed class BSPrim : BSPhysObject
PositionSanityCheck2(true); PositionSanityCheck2(true);
Linkset.UpdateProperties(this);
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
@ -1304,7 +1342,7 @@ public sealed class BSPrim : BSPhysObject
/* /*
else else
{ {
// For debugging, we can also report the movement of children // For debugging, report the movement of children
DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity); entprop.Acceleration, entprop.RotationalVelocity);

View File

@ -39,7 +39,6 @@ using log4net;
using OpenMetaverse; using OpenMetaverse;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
// Move all logic out of the C++ code and into the C# code for easier future modifications.
// Test sculpties (verified that they don't work) // Test sculpties (verified that they don't work)
// Compute physics FPS reasonably // Compute physics FPS reasonably
// Based on material, set density and friction // Based on material, set density and friction
@ -90,10 +89,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// let my minuions use my logger // let my minuions use my logger
public ILog Logger { get { return m_log; } } public ILog Logger { get { return m_log; } }
// If non-zero, the number of simulation steps between calls to the physics
// engine to output detailed physics stats. Debug logging level must be on also.
private int m_detailedStatsStep = 0;
public IMesher mesher; public IMesher mesher;
// Level of Detail values kept as float because that's what the Meshmerizer wants // Level of Detail values kept as float because that's what the Meshmerizer wants
public float MeshLOD { get; private set; } public float MeshLOD { get; private set; }
@ -112,6 +107,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private float m_fixedTimeStep; private float m_fixedTimeStep;
private long m_simulationStep = 0; private long m_simulationStep = 0;
public long SimulationStep { get { return m_simulationStep; } } public long SimulationStep { get { return m_simulationStep; } }
private int m_taintsToProcessPerStep;
// A value of the time now so all the collision and update routines do not have to get their own // A value of the time now so all the collision and update routines do not have to get their own
// Set to 'now' just before all the prims and actors are called for collisions and updates // Set to 'now' just before all the prims and actors are called for collisions and updates
@ -131,6 +127,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
public float PID_D { get; private set; } // derivative public float PID_D { get; private set; } // derivative
public float PID_P { get; private set; } // proportional public float PID_P { get; private set; } // proportional
@ -254,7 +251,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// The bounding box for the simulated world. The origin is 0,0,0 unless we're // The bounding box for the simulated world. The origin is 0,0,0 unless we're
// a child in a mega-region. // a child in a mega-region.
// Turns out that Bullet really doesn't care about the extents of the simulated // Bullet actually doesn't care about the extents of the simulated
// area. It tracks active objects no matter where they are. // area. It tracks active objects no matter where they are.
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
@ -331,7 +328,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Called directly from unmanaged code so don't do much // Called directly from unmanaged code so don't do much
private void BulletLoggerPhysLog(string msg) private void BulletLoggerPhysLog(string msg)
{ {
PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); DetailLog("[BULLETS UNMANAGED]:" + msg);
} }
public override void Dispose() public override void Dispose()
@ -494,8 +491,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_simulationStep++; m_simulationStep++;
int numSubSteps = 0; int numSubSteps = 0;
// Sometimes needed for debugging to find out what happened before the step // DEBUG
// PhysicsLogging.Flush(); // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
try try
{ {
@ -505,8 +502,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}", DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
} }
catch (Exception e) catch (Exception e)
{ {
@ -582,19 +579,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
} }
// If enabled, call into the physics engine to dump statistics
if (m_detailedStatsStep > 0)
{
if ((m_simulationStep % m_detailedStatsStep) == 0)
{
BulletSimAPI.DumpBulletStatistics();
}
}
// 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.
// Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS. // We multiply by 45 to give a recognizable running rate (45 or less).
return numSubSteps * m_fixedTimeStep * 1000; return numSubSteps * m_fixedTimeStep * 1000 * 45;
// return timeStep * 1000 * 45;
} }
// Something has collided // Something has collided
@ -617,7 +606,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
BSPhysObject collidee = null; BSPhysObject collidee = null;
PhysObjects.TryGetValue(collidingWith, out collidee); PhysObjects.TryGetValue(collidingWith, out collidee);
DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
{ {
@ -703,6 +692,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{ {
if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
{ {
// swizzle a new list into the list location so we can process what's there
int taintCount = m_taintsToProcessPerStep;
TaintCallbackEntry oneCallback = new TaintCallbackEntry();
while (_taintedObjects.Count > 0 && taintCount-- > 0)
{
bool gotOne = false;
lock (_taintLock)
{
if (_taintedObjects.Count > 0)
{
oneCallback = _taintedObjects[0];
_taintedObjects.RemoveAt(0);
gotOne = true;
}
}
if (gotOne)
{
try
{
DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
oneCallback.callback();
}
catch (Exception e)
{
m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
}
}
}
/*
// 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)
@ -715,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{ {
try try
{ {
DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
tcbe.callback(); tcbe.callback();
} }
catch (Exception e) catch (Exception e)
@ -723,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
} }
oldList.Clear(); oldList.Clear();
*/
} }
} }
@ -834,6 +854,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
(s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
(s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
8f, 8f,
@ -876,6 +901,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxUpdatesPerFrame; }, (s) => { return (float)s.m_maxUpdatesPerFrame; },
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
100f,
(s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_taintsToProcessPerStep; },
(s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f, 10000.01f,
(s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
@ -1070,12 +1100,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
0.1f, 0.001f,
(s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintCFM; }, (s) => { return s.m_params[0].linkConstraintCFM; },
(s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
0.2f, 0.8f,
(s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintERP; }, (s) => { return s.m_params[0].linkConstraintERP; },
(s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
@ -1085,11 +1115,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].linkConstraintSolverIterations; }, (s) => { return s.m_params[0].linkConstraintSolverIterations; },
(s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
0f, 0f,
(s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_detailedStatsStep; }, (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
(s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
}; };
// Convert a boolean to our numeric true and false values // Convert a boolean to our numeric true and false values
@ -1270,6 +1300,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public void DetailLog(string msg, params Object[] args) public void DetailLog(string msg, params Object[] args)
{ {
PhysicsLogging.Write(msg, args); PhysicsLogging.Write(msg, args);
// Add the Flush() if debugging crashes to get all the messages written out.
// PhysicsLogging.Flush();
} }
// used to fill in the LocalID when there isn't one // used to fill in the LocalID when there isn't one
public const string DetailLogZero = "0000000000"; public const string DetailLogZero = "0000000000";

View File

@ -67,8 +67,8 @@ public class BSShapeCollection : IDisposable
public DateTime lastReferenced; public DateTime lastReferenced;
} }
private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>(); private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>(); private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>(); private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
public BSShapeCollection(BSScene physScene) public BSShapeCollection(BSScene physScene)
@ -121,7 +121,7 @@ public class BSShapeCollection : IDisposable
// Track another user of a body // Track another user of a body
// We presume the caller has allocated the body. // We presume the caller has allocated the body.
// Bodies only have one user so the reference count is either 1 or 0. // Bodies only have one user so the reference count is either 1 or 0.
public void ReferenceBody(BulletBody body, bool atTaintTime) public void ReferenceBody(BulletBody body, bool inTaintTime)
{ {
lock (m_collectionActivityLock) lock (m_collectionActivityLock)
{ {
@ -136,7 +136,21 @@ public class BSShapeCollection : IDisposable
// New entry // New entry
bodyDesc.ptr = body.ptr; bodyDesc.ptr = body.ptr;
bodyDesc.referenceCount = 1; bodyDesc.referenceCount = 1;
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount); DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
body.ID, body, bodyDesc.referenceCount);
BSScene.TaintCallback createOperation = delegate()
{
if (!BulletSimAPI.IsInWorld2(body.ptr))
{
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}",
body.ID, body);
}
};
if (inTaintTime)
createOperation();
else
PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
} }
bodyDesc.lastReferenced = System.DateTime.Now; bodyDesc.lastReferenced = System.DateTime.Now;
Bodies[body.ID] = bodyDesc; Bodies[body.ID] = bodyDesc;
@ -160,21 +174,22 @@ public class BSShapeCollection : IDisposable
Bodies[body.ID] = bodyDesc; Bodies[body.ID] = bodyDesc;
DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount); DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
// If body is no longer being used, free it -- bodies are never shared. // If body is no longer being used, free it -- bodies can never be shared.
if (bodyDesc.referenceCount == 0) if (bodyDesc.referenceCount == 0)
{ {
Bodies.Remove(body.ID); Bodies.Remove(body.ID);
BSScene.TaintCallback removeOperation = delegate() BSScene.TaintCallback removeOperation = delegate()
{ {
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}", DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
body.ID, body.ptr.ToString("X")); body.ID, body.ptr.ToString("X"), inTaintTime);
// If the caller needs to know the old body is going away, pass the event up. // If the caller needs to know the old body is going away, pass the event up.
if (bodyCallback != null) bodyCallback(body); if (bodyCallback != null) bodyCallback(body);
// Zero any reference to the shape so it is not freed when the body is deleted.
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
// It may have already been removed from the world in which case the next is a NOOP. // It may have already been removed from the world in which case the next is a NOOP.
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
// Zero any reference to the shape so it is not freed when the body is deleted.
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
}; };
// If already in taint-time, do the operations now. Otherwise queue for later. // If already in taint-time, do the operations now. Otherwise queue for later.
@ -208,7 +223,7 @@ public class BSShapeCollection : IDisposable
{ {
// There is an existing instance of this mesh. // There is an existing instance of this mesh.
meshDesc.referenceCount++; meshDesc.referenceCount++;
DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}", DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
} }
else else
@ -217,7 +232,7 @@ public class BSShapeCollection : IDisposable
meshDesc.ptr = shape.ptr; meshDesc.ptr = shape.ptr;
// We keep a reference to the underlying IMesh data so a hull can be built // We keep a reference to the underlying IMesh data so a hull can be built
meshDesc.referenceCount = 1; meshDesc.referenceCount = 1;
DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}", DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
ret = true; ret = true;
} }
@ -230,7 +245,7 @@ public class BSShapeCollection : IDisposable
{ {
// There is an existing instance of this hull. // There is an existing instance of this hull.
hullDesc.referenceCount++; hullDesc.referenceCount++;
DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}", DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
} }
else else
@ -238,7 +253,7 @@ public class BSShapeCollection : IDisposable
// This is a new reference to a hull // This is a new reference to a hull
hullDesc.ptr = shape.ptr; hullDesc.ptr = shape.ptr;
hullDesc.referenceCount = 1; hullDesc.referenceCount = 1;
DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}", DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
ret = true; ret = true;
@ -257,7 +272,7 @@ public class BSShapeCollection : IDisposable
// Release the usage of a shape. // Release the usage of a shape.
// The collisionObject is released since it is a copy of the real collision shape. // The collisionObject is released since it is a copy of the real collision shape.
public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback) public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
{ {
if (shape.ptr == IntPtr.Zero) if (shape.ptr == IntPtr.Zero)
return; return;
@ -279,14 +294,14 @@ public class BSShapeCollection : IDisposable
if (shape.ptr != IntPtr.Zero & shape.isNativeShape) if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
{ {
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime); BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
if (shapeCallback != null) shapeCallback(shape); if (shapeCallback != null) shapeCallback(shape);
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
} }
break; break;
} }
}; };
if (atTaintTime) if (inTaintTime)
{ {
lock (m_collectionActivityLock) lock (m_collectionActivityLock)
{ {
@ -358,7 +373,8 @@ public class BSShapeCollection : IDisposable
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
{ {
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
{ {
haveShape = true; haveShape = true;
if (forceRebuild if (forceRebuild
@ -372,7 +388,7 @@ public class BSShapeCollection : IDisposable
prim.LocalID, forceRebuild, prim.BSShape); prim.LocalID, forceRebuild, prim.BSShape);
} }
} }
else if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
{ {
haveShape = true; haveShape = true;
if (forceRebuild if (forceRebuild
@ -392,7 +408,7 @@ public class BSShapeCollection : IDisposable
// made. Native shapes are best used in either case. // made. Native shapes are best used in either case.
if (!haveShape) if (!haveShape)
{ {
if (prim.IsPhysical) if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
{ {
// Update prim.BSShape to reference a hull of this shape. // Update prim.BSShape to reference a hull of this shape.
ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
@ -426,7 +442,7 @@ public class BSShapeCollection : IDisposable
// Native shapes are always built independently. // Native shapes are always built independently.
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
newShape.shapeKey = (ulong)shapeKey; newShape.shapeKey = (System.UInt64)shapeKey;
newShape.isNativeShape = true; newShape.isNativeShape = true;
// Don't need to do a 'ReferenceShape()' here because native shapes are not tracked. // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
@ -446,7 +462,7 @@ public class BSShapeCollection : IDisposable
BulletShape newShape = new BulletShape(IntPtr.Zero); BulletShape newShape = new BulletShape(IntPtr.Zero);
float lod; float lod;
ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, 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.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
@ -469,7 +485,7 @@ public class BSShapeCollection : IDisposable
return true; // 'true' means a new shape has been added to this prim return true; // 'true' means a new shape has been added to this prim
} }
private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
{ {
IMesh meshData = null; IMesh meshData = null;
IntPtr meshPtr; IntPtr meshPtr;
@ -516,7 +532,7 @@ public class BSShapeCollection : IDisposable
BulletShape newShape; BulletShape newShape;
float lod; float lod;
ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod); System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, 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.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
@ -525,7 +541,7 @@ public class BSShapeCollection : IDisposable
DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
// Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull. // Remove usage of the previous shape.
DereferenceShape(prim.BSShape, true, shapeCallback); DereferenceShape(prim.BSShape, true, shapeCallback);
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
@ -539,7 +555,7 @@ public class BSShapeCollection : IDisposable
} }
List<ConvexResult> m_hulls; List<ConvexResult> m_hulls;
private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
{ {
IntPtr hullPtr; IntPtr hullPtr;
@ -652,22 +668,23 @@ public class BSShapeCollection : IDisposable
// Create a hash of all the shape parameters to be used as a key // Create a hash of all the shape parameters to be used as a key
// for this particular shape. // for this particular shape.
private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
{ {
// level of detail based on size and type of the object // level of detail based on size and type of the object
float lod = PhysicsScene.MeshLOD; float lod = PhysicsScene.MeshLOD;
if (pbs.SculptEntry) if (pbs.SculptEntry)
lod = PhysicsScene.SculptLOD; lod = PhysicsScene.SculptLOD;
// Mega prims usually get more detail because one can interact with shape approximations at this size.
float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
lod = PhysicsScene.MeshMegaPrimLOD; lod = PhysicsScene.MeshMegaPrimLOD;
retLod = lod; retLod = lod;
return (ulong)pbs.GetMeshKey(shapeData.Size, lod); return pbs.GetMeshKey(shapeData.Size, lod);
} }
// For those who don't want the LOD // For those who don't want the LOD
private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
{ {
float lod; float lod;
return ComputeShapeKey(shapeData, pbs, out lod); return ComputeShapeKey(shapeData, pbs, out lod);
@ -701,6 +718,7 @@ public class BSShapeCollection : IDisposable
if (mustRebuild || forceRebuild) if (mustRebuild || forceRebuild)
{ {
// Free any old body
DereferenceBody(prim.BSBody, true, bodyCallback); DereferenceBody(prim.BSBody, true, bodyCallback);
BulletBody aBody; BulletBody aBody;
@ -709,13 +727,13 @@ public class BSShapeCollection : IDisposable
{ {
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
shapeData.ID, shapeData.Position, shapeData.Rotation); shapeData.ID, shapeData.Position, shapeData.Rotation);
// DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
} }
else else
{ {
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
shapeData.ID, shapeData.Position, shapeData.Rotation); shapeData.ID, shapeData.Position, shapeData.Rotation);
// 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(shapeData.ID, bodyPtr); aBody = new BulletBody(shapeData.ID, bodyPtr);
@ -731,7 +749,8 @@ public class BSShapeCollection : IDisposable
private void DetailLog(string msg, params Object[] args) private void DetailLog(string msg, params Object[] args)
{ {
PhysicsScene.PhysicsLogging.Write(msg, args); if (PhysicsScene.PhysicsLogging.Enabled)
PhysicsScene.DetailLog(msg, args);
} }
} }
} }

View File

@ -114,6 +114,8 @@ public class BSTerrainManager
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
Vector3.Zero, Quaternion.Identity)); Vector3.Zero, Quaternion.Identity));
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
// Ground plane does not move
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
// Everything collides with the ground plane. // Everything collides with the ground plane.
BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
(uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
@ -201,10 +203,10 @@ public class BSTerrainManager
// The 'doNow' boolean says whether to do all the unmanaged activities right now (like when // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
// calling this routine from initialization or taint-time routines) or whether to delay // calling this routine from initialization or taint-time routines) or whether to delay
// all the unmanaged activities to taint-time. // all the unmanaged activities to taint-time.
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime) private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{ {
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}", DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime); BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
float minZ = float.MaxValue; float minZ = float.MaxValue;
float maxZ = float.MinValue; float maxZ = float.MinValue;
@ -296,16 +298,16 @@ public class BSTerrainManager
mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID, mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); 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 // The terrain object initial position is at the center of the object
Vector3 centerPos; Vector3 centerPos;
centerPos.X = minCoords.X + (mapInfo.sizeX / 2f); centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f); centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
centerPos.Z = minZ + ((maxZ - minZ) / 2f); centerPos.Z = minZ + ((maxZ - minZ) / 2f);
// Create the terrain shape from the mapInfo
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
mapInfo.terrainBody = new BulletBody(mapInfo.ID, mapInfo.terrainBody = new BulletBody(mapInfo.ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr, BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
id, centerPos, Quaternion.Identity)); id, centerPos, Quaternion.Identity));
@ -320,9 +322,6 @@ public class BSTerrainManager
BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
// Return the new terrain to the world of physical objects // Return the new terrain to the world of physical objects
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
@ -342,7 +341,7 @@ public class BSTerrainManager
// There is the option to do the changes now (we're already in 'taint time'), or // There is the option to do the changes now (we're already in 'taint time'), or
// to do the Bullet operations later. // to do the Bullet operations later.
if (atTaintTime) if (inTaintTime)
rebuildOperation(); rebuildOperation();
else else
PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation); PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
@ -381,7 +380,7 @@ public class BSTerrainManager
}; };
// If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time. // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
if (atTaintTime) if (inTaintTime)
createOperation(); createOperation();
else else
PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation); PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);

View File

@ -101,9 +101,8 @@ public struct BulletShape
} }
public IntPtr ptr; public IntPtr ptr;
public ShapeData.PhysicsShapeType type; public ShapeData.PhysicsShapeType type;
public ulong shapeKey; public System.UInt64 shapeKey;
public bool isNativeShape; public bool isNativeShape;
// Hulls have an underlying mesh. A pointer to it is hidden here.
public override string ToString() public override string ToString()
{ {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
@ -192,8 +191,9 @@ public struct ShapeData
SHAPE_SPHERE = 5, SHAPE_SPHERE = 5,
SHAPE_MESH = 6, SHAPE_MESH = 6,
SHAPE_HULL = 7, SHAPE_HULL = 7,
SHAPE_GROUNDPLANE = 8, // following defined by BulletSim
SHAPE_TERRAIN = 9, SHAPE_GROUNDPLANE = 20,
SHAPE_TERRAIN = 21,
}; };
public uint ID; public uint ID;
public PhysicsShapeType Type; public PhysicsShapeType Type;
@ -305,6 +305,8 @@ public struct ConfigurationParameters
public float linkConstraintCFM; public float linkConstraintCFM;
public float linkConstraintSolverIterations; public float linkConstraintSolverIterations;
public float physicsLoggingFrames;
public const float numericTrue = 1f; public const float numericTrue = 1f;
public const float numericFalse = 0f; public const float numericFalse = 0f;
} }
@ -1036,18 +1038,6 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern int GetNumConstraintRefs2(IntPtr obj); public static extern int GetNumConstraintRefs2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetDeltaLinearVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetDeltaAngularVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetPushVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetTurnVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
@ -1107,6 +1097,15 @@ public static extern float GetMargin2(IntPtr shape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpAllInfo2(IntPtr sim);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);

View File

@ -100,7 +100,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private bool m_hackSentFly = false; private bool m_hackSentFly = false;
private int m_requestedUpdateFrequency = 0; private int m_requestedUpdateFrequency = 0;
private Vector3 m_taintPosition; private Vector3 m_taintPosition;
internal bool m_avatarplanted = false;
/// <summary> /// <summary>
/// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force
/// while calculatios are going on /// while calculatios are going on
@ -413,7 +413,7 @@ namespace OpenSim.Region.Physics.OdePlugin
set set
{ {
m_iscollidingObj = value; m_iscollidingObj = value;
if (value) if (value && !m_avatarplanted)
m_pidControllerActive = false; m_pidControllerActive = false;
else else
m_pidControllerActive = true; m_pidControllerActive = true;

View File

@ -501,6 +501,8 @@ namespace OpenSim.Region.Physics.OdePlugin
public int physics_logging_interval = 0; public int physics_logging_interval = 0;
public bool physics_logging_append_existing_logfile = false; public bool physics_logging_append_existing_logfile = false;
private bool avplanted = false;
private bool av_av_collisions_off = false;
public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
@ -644,6 +646,9 @@ namespace OpenSim.Region.Physics.OdePlugin
avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
avplanted = physicsconfig.GetBoolean("av_planted", false);
av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
@ -664,6 +669,8 @@ namespace OpenSim.Region.Physics.OdePlugin
MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
if (Environment.OSVersion.Platform == PlatformID.Unix) if (Environment.OSVersion.Platform == PlatformID.Unix)
{ {
avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f); avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
@ -1309,6 +1316,10 @@ namespace OpenSim.Region.Physics.OdePlugin
if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
skipThisContact = true; // No collision on volume detect prims skipThisContact = true; // No collision on volume detect prims
if (av_av_collisions_off)
if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
skipThisContact = true;
if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
skipThisContact = true; // No collision on volume detect prims skipThisContact = true; // No collision on volume detect prims
@ -1972,6 +1983,7 @@ namespace OpenSim.Region.Physics.OdePlugin
newAv.Flying = isFlying; newAv.Flying = isFlying;
newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
newAv.m_avatarplanted = avplanted;
return newAv; return newAv;
} }
@ -1987,6 +1999,7 @@ namespace OpenSim.Region.Physics.OdePlugin
internal void AddCharacter(OdeCharacter chr) internal void AddCharacter(OdeCharacter chr)
{ {
chr.m_avatarplanted = avplanted;
if (!_characters.Contains(chr)) if (!_characters.Contains(chr))
{ {
_characters.Add(chr); _characters.Add(chr);

View File

@ -3600,7 +3600,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
/// <returns></returns> /// <returns></returns>
public void osSetContentType(LSL_Key id, string type) public void osSetContentType(LSL_Key id, string type)
{ {
CheckThreatLevel(ThreatLevel.High,"osSetResponseType"); CheckThreatLevel(ThreatLevel.High, "osSetContentType");
if (m_UrlModule != null) if (m_UrlModule != null)
m_UrlModule.HttpContentType(new UUID(id),type); m_UrlModule.HttpContentType(new UUID(id),type);
} }
@ -3611,7 +3612,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
/// <returns>boolean indicating whether an error was shouted.</returns> /// <returns>boolean indicating whether an error was shouted.</returns>
protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix) protected bool ShoutErrorOnLackingOwnerPerms(int perms, string errorPrefix)
{ {
CheckThreatLevel(ThreatLevel.Moderate, "osDropAttachment");
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
bool fail = false; bool fail = false;
if (m_item.PermsGranter != m_host.OwnerID) if (m_item.PermsGranter != m_host.OwnerID)

View File

@ -60,7 +60,25 @@ namespace OpenSim.Server
} }
string connList = serverConfig.GetString("ServiceConnectors", String.Empty); string connList = serverConfig.GetString("ServiceConnectors", String.Empty);
string[] conns = connList.Split(new char[] {',', ' '});
IConfig servicesConfig = m_Server.Config.Configs["ServiceList"];
if (servicesConfig != null)
{
List<string> servicesList = new List<string>();
if (connList != String.Empty)
servicesList.Add(connList);
foreach (string k in servicesConfig.GetKeys())
{
string v = servicesConfig.GetString(k);
if (v != String.Empty)
servicesList.Add(v);
}
connList = String.Join(",", servicesList.ToArray());
}
string[] conns = connList.Split(new char[] {',', ' ', '\n', '\r', '\t'});
// int i = 0; // int i = 0;
foreach (string c in conns) foreach (string c in conns)

View File

@ -395,8 +395,8 @@ namespace OpenSim.Services.Connectors.SimianGrid
if (response["Success"].AsBoolean()) if (response["Success"].AsBoolean())
{ {
OSDMap extraData = response["ExtraData"] as OSDMap; OSDMap extraData = response["ExtraData"] as OSDMap;
int enabled = response["Enabled"].AsBoolean() ? (int) OpenSim.Data.RegionFlags.RegionOnline : 0; int enabled = response["Enabled"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.RegionOnline : 0;
int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int) OpenSim.Data.RegionFlags.Hyperlink : 0; int hypergrid = extraData["HyperGrid"].AsBoolean() ? (int)OpenSim.Framework.RegionFlags.Hyperlink : 0;
int flags = enabled | hypergrid; int flags = enabled | hypergrid;
m_log.DebugFormat("[SGGC] enabled - {0} hg - {1} flags - {2}", enabled, hypergrid, flags); m_log.DebugFormat("[SGGC] enabled - {0} hg - {1} flags - {2}", enabled, hypergrid, flags);
return flags; return flags;

View File

@ -151,11 +151,11 @@ namespace OpenSim.Services.GridService
// //
// Get it's flags // Get it's flags
// //
OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(region.Data["flags"]); OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(region.Data["flags"]);
// Is this a reservation? // Is this a reservation?
// //
if ((rflags & OpenSim.Data.RegionFlags.Reservation) != 0) if ((rflags & OpenSim.Framework.RegionFlags.Reservation) != 0)
{ {
// Regions reserved for the null key cannot be taken. // Regions reserved for the null key cannot be taken.
if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString()) if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString())
@ -166,10 +166,10 @@ namespace OpenSim.Services.GridService
// NOTE: Fudging the flags value here, so these flags // NOTE: Fudging the flags value here, so these flags
// should not be used elsewhere. Don't optimize // should not be used elsewhere. Don't optimize
// this with the later retrieval of the same flags! // this with the later retrieval of the same flags!
rflags |= OpenSim.Data.RegionFlags.Authenticate; rflags |= OpenSim.Framework.RegionFlags.Authenticate;
} }
if ((rflags & OpenSim.Data.RegionFlags.Authenticate) != 0) if ((rflags & OpenSim.Framework.RegionFlags.Authenticate) != 0)
{ {
// Can we authenticate at all? // Can we authenticate at all?
// //
@ -205,10 +205,10 @@ namespace OpenSim.Services.GridService
if ((region != null) && (region.RegionID == regionInfos.RegionID) && if ((region != null) && (region.RegionID == regionInfos.RegionID) &&
((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY))) ((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY)))
{ {
if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Data.RegionFlags.NoMove) != 0) if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.NoMove) != 0)
return "Can't move this region"; return "Can't move this region";
if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Data.RegionFlags.LockedOut) != 0) if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.LockedOut) != 0)
return "Region locked out"; return "Region locked out";
// Region reregistering in other coordinates. Delete the old entry // Region reregistering in other coordinates. Delete the old entry
@ -233,7 +233,7 @@ namespace OpenSim.Services.GridService
{ {
int oldFlags = Convert.ToInt32(region.Data["flags"]); int oldFlags = Convert.ToInt32(region.Data["flags"]);
oldFlags &= ~(int)OpenSim.Data.RegionFlags.Reservation; oldFlags &= ~(int)OpenSim.Framework.RegionFlags.Reservation;
rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags
} }
@ -252,7 +252,7 @@ namespace OpenSim.Services.GridService
} }
int flags = Convert.ToInt32(rdata.Data["flags"]); int flags = Convert.ToInt32(rdata.Data["flags"]);
flags |= (int)OpenSim.Data.RegionFlags.RegionOnline; flags |= (int)OpenSim.Framework.RegionFlags.RegionOnline;
rdata.Data["flags"] = flags.ToString(); rdata.Data["flags"] = flags.ToString();
try try
@ -283,9 +283,9 @@ namespace OpenSim.Services.GridService
int flags = Convert.ToInt32(region.Data["flags"]); int flags = Convert.ToInt32(region.Data["flags"]);
if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Data.RegionFlags.Persistent) != 0) if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Framework.RegionFlags.Persistent) != 0)
{ {
flags &= ~(int)OpenSim.Data.RegionFlags.RegionOnline; flags &= ~(int)OpenSim.Framework.RegionFlags.RegionOnline;
region.Data["flags"] = flags.ToString(); region.Data["flags"] = flags.ToString();
region.Data["last_seen"] = Util.UnixTimeSinceEpoch(); region.Data["last_seen"] = Util.UnixTimeSinceEpoch();
try try
@ -320,7 +320,7 @@ namespace OpenSim.Services.GridService
if (rdata.RegionID != regionID) if (rdata.RegionID != regionID)
{ {
int flags = Convert.ToInt32(rdata.Data["flags"]); int flags = Convert.ToInt32(rdata.Data["flags"]);
if ((flags & (int)Data.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours if ((flags & (int)Framework.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours
rinfos.Add(RegionData2RegionInfo(rdata)); rinfos.Add(RegionData2RegionInfo(rdata));
} }
} }
@ -470,7 +470,7 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions) foreach (RegionData r in regions)
{ {
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
ret.Add(RegionData2RegionInfo(r)); ret.Add(RegionData2RegionInfo(r));
} }
@ -486,7 +486,7 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions) foreach (RegionData r in regions)
{ {
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
ret.Add(RegionData2RegionInfo(r)); ret.Add(RegionData2RegionInfo(r));
} }
@ -502,7 +502,7 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions) foreach (RegionData r in regions)
{ {
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
ret.Add(RegionData2RegionInfo(r)); ret.Add(RegionData2RegionInfo(r));
} }
@ -629,7 +629,7 @@ namespace OpenSim.Services.GridService
private void OutputRegionToConsole(RegionData r) private void OutputRegionToConsole(RegionData r)
{ {
OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
ConsoleDisplayList dispList = new ConsoleDisplayList(); ConsoleDisplayList dispList = new ConsoleDisplayList();
dispList.AddRow("Region Name", r.RegionName); dispList.AddRow("Region Name", r.RegionName);
@ -659,7 +659,7 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions) foreach (RegionData r in regions)
{ {
OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); OpenSim.Framework.RegionFlags flags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(r.Data["flags"]);
dispTable.AddRow( dispTable.AddRow(
r.RegionName, r.RegionName,
r.RegionID.ToString(), r.RegionID.ToString(),
@ -673,7 +673,7 @@ namespace OpenSim.Services.GridService
private int ParseFlags(int prev, string flags) private int ParseFlags(int prev, string flags)
{ {
OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)prev; OpenSim.Framework.RegionFlags f = (OpenSim.Framework.RegionFlags)prev;
string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries); string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries);
@ -685,18 +685,18 @@ namespace OpenSim.Services.GridService
{ {
if (p.StartsWith("+")) if (p.StartsWith("+"))
{ {
val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1)); val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
f |= (OpenSim.Data.RegionFlags)val; f |= (OpenSim.Framework.RegionFlags)val;
} }
else if (p.StartsWith("-")) else if (p.StartsWith("-"))
{ {
val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1)); val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p.Substring(1));
f &= ~(OpenSim.Data.RegionFlags)val; f &= ~(OpenSim.Framework.RegionFlags)val;
} }
else else
{ {
val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p); val = (int)Enum.Parse(typeof(OpenSim.Framework.RegionFlags), p);
f |= (OpenSim.Data.RegionFlags)val; f |= (OpenSim.Framework.RegionFlags)val;
} }
} }
catch (Exception) catch (Exception)
@ -728,7 +728,7 @@ namespace OpenSim.Services.GridService
int flags = Convert.ToInt32(r.Data["flags"]); int flags = Convert.ToInt32(r.Data["flags"]);
flags = ParseFlags(flags, cmd[4]); flags = ParseFlags(flags, cmd[4]);
r.Data["flags"] = flags.ToString(); r.Data["flags"] = flags.ToString();
OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)flags; OpenSim.Framework.RegionFlags f = (OpenSim.Framework.RegionFlags)flags;
MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f)); MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f));
m_Database.Store(r); m_Database.Store(r);

View File

@ -390,8 +390,8 @@ namespace OpenSim.Services.GridService
List<RegionData> regions = m_Database.Get(mapName, m_ScopeID); List<RegionData> regions = m_Database.Get(mapName, m_ScopeID);
if (regions != null && regions.Count > 0) if (regions != null && regions.Count > 0)
{ {
OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]); OpenSim.Framework.RegionFlags rflags = (OpenSim.Framework.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]);
if ((rflags & OpenSim.Data.RegionFlags.Hyperlink) != 0) if ((rflags & OpenSim.Framework.RegionFlags.Hyperlink) != 0)
{ {
regInfo = new GridRegion(); regInfo = new GridRegion();
regInfo.RegionID = regions[0].RegionID; regInfo.RegionID = regions[0].RegionID;
@ -460,7 +460,7 @@ namespace OpenSim.Services.GridService
private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle) private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle)
{ {
RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo); RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo);
int flags = (int)OpenSim.Data.RegionFlags.Hyperlink + (int)OpenSim.Data.RegionFlags.NoDirectLogin + (int)OpenSim.Data.RegionFlags.RegionOnline; int flags = (int)OpenSim.Framework.RegionFlags.Hyperlink + (int)OpenSim.Framework.RegionFlags.NoDirectLogin + (int)OpenSim.Framework.RegionFlags.RegionOnline;
rdata.Data["flags"] = flags.ToString(); rdata.Data["flags"] = flags.ToString();
m_Database.Store(rdata); m_Database.Store(rdata);

View File

@ -100,6 +100,19 @@ namespace OpenSim.Services.Interfaces
List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y); List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y);
List<GridRegion> GetHyperlinks(UUID scopeID); List<GridRegion> GetHyperlinks(UUID scopeID);
/// <summary>
/// Get internal OpenSimulator region flags.
/// </summary>
/// <remarks>
/// See OpenSimulator.Framework.RegionFlags. These are not returned in the GridRegion structure -
/// they currently need to be requested separately. Possibly this should change to avoid multiple service calls
/// in some situations.
/// </remarks>
/// <returns>
/// The region flags.
/// </returns>
/// <param name='scopeID'></param>
/// <param name='regionID'></param>
int GetRegionFlags(UUID scopeID, UUID regionID); int GetRegionFlags(UUID scopeID, UUID regionID);
} }

View File

@ -840,6 +840,15 @@
; When the avatar flies, it will be moved up by this amount off the ground (in meters) ; When the avatar flies, it will be moved up by this amount off the ground (in meters)
minimum_ground_flight_offset = 3.0 minimum_ground_flight_offset = 3.0
; Plant avatar. This reduces the effect of physical contacts with the avatar.
; If you have a group of unruly and rude visitors that bump each other, turn this on to make that less attractive.
; The avatar still allows a small movement based on the PID settings above. Stronger PID settings AND this active
; will lock the avatar in place
av_planted = false
; No Avatar Avatar Collissions. This causes avatar to be able to walk through each other as if they're ghosts but still interact with the environment
av_av_collisions_off = false
; ## ; ##
; ## Object options ; ## Object options
; ## ; ##

View File

@ -21,7 +21,38 @@
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>] ; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
; * ; *
[Startup] [Startup]
ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003/OpenSim.Server.Handlers.dll:XInventoryInConnector,8004/OpenSim.Server.Handlers.dll:FreeswitchServerConnector,8003/OpenSim.Server.Handlers.dll:GridServiceConnector,8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector,8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector,8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector,8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector,8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector,8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector,8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector,8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector,8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector,8002/OpenSim.Server.Handlers.dll:GatekeeperServiceInConnector,8002/OpenSim.Server.Handlers.dll:UserAgentServerConnector,HGInventoryService@8002/OpenSim.Server.Handlers.dll:XInventoryInConnector,HGAssetService@8002/OpenSim.Server.Handlers.dll:AssetServiceConnector,8002/OpenSim.Server.Handlers.dll:HeloServiceInConnector,8002/OpenSim.Server.Handlers.dll:HGFriendsServerConnector,8002/OpenSim.Server.Handlers.dll:InstantMessageServerConnector,8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector,8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
[ServiceList]
AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
InventoryInConnector = "8003/OpenSim.Server.Handlers.dll:XInventoryInConnector"
VoiceConnector = "8004/OpenSim.Server.Handlers.dll:FreeswitchServerConnector"
GridServiceConnector = "8003/OpenSim.Server.Handlers.dll:GridServiceConnector"
GridInfoServerInConnector = "8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector"
AuthenticationServiceConnector = "8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector"
OpenIdServerConnector = "8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector"
AvatarServiceConnector = "8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector"
LLLoginServiceInConnector = "8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector"
PresenceServiceConnector = "8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector"
UserAccountServiceConnector = "8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector"
GridUserServiceConnector = "8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector"
FriendsServiceConnector = "8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector"
MapAddServiceConnector = "8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector"
MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
;; Additions for Hypergrid
GatekeeperServiceInConnector = "8002/OpenSim.Server.Handlers.dll:GatekeeperServiceInConnector"
UserAgentServerConnector = "8002/OpenSim.Server.Handlers.dll:UserAgentServerConnector"
HeloServiceInConnector = "8002/OpenSim.Server.Handlers.dll:HeloServiceInConnector"
HGFriendsServerConnector = "8002/OpenSim.Server.Handlers.dll:HGFriendsServerConnector"
InstantMessageServerConnector = "8002/OpenSim.Server.Handlers.dll:InstantMessageServerConnector"
HGInventoryServiceConnector = "HGInventoryService@8002/OpenSim.Server.Handlers.dll:XInventoryInConnector"
HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:AssetServiceConnector"
;; Additions for other add-on modules. For example:
;; WifiServerConnector = "8002/Diva.Wifi.dll:WifiServerConnector"
; * This is common for all services, it's the network setup for the entire ; * This is common for all services, it's the network setup for the entire
; * server instance, if none is specified above ; * server instance, if none is specified above

View File

@ -13,7 +13,23 @@
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>] ; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
; * ; *
[Startup] [Startup]
ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003/OpenSim.Server.Handlers.dll:XInventoryInConnector,8004/OpenSim.Server.Handlers.dll:FreeswitchServerConnector,8003/OpenSim.Server.Handlers.dll:GridServiceConnector,8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector,8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector,8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector,8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector,8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector,8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector,8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector,8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector,8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector,8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector,8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
[ServiceList]
AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector"
InventoryInConnector = "8003/OpenSim.Server.Handlers.dll:XInventoryInConnector"
VoiceConnector = "8004/OpenSim.Server.Handlers.dll:FreeswitchServerConnector"
GridServiceConnector = "8003/OpenSim.Server.Handlers.dll:GridServiceConnector"
GridInfoServerInConnector = "8002/OpenSim.Server.Handlers.dll:GridInfoServerInConnector"
AuthenticationServiceConnector = "8003/OpenSim.Server.Handlers.dll:AuthenticationServiceConnector"
OpenIdServerConnector = "8002/OpenSim.Server.Handlers.dll:OpenIdServerConnector"
AvatarServiceConnector = "8003/OpenSim.Server.Handlers.dll:AvatarServiceConnector"
LLLoginServiceInConnector = "8002/OpenSim.Server.Handlers.dll:LLLoginServiceInConnector"
PresenceServiceConnector = "8003/OpenSim.Server.Handlers.dll:PresenceServiceConnector"
UserAccountServiceConnector = "8003/OpenSim.Server.Handlers.dll:UserAccountServiceConnector"
GridUserServiceConnector = "8003/OpenSim.Server.Handlers.dll:GridUserServiceConnector"
FriendsServiceConnector = "8003/OpenSim.Server.Handlers.dll:FriendsServiceConnector"
MapAddServiceConnector = "8003/OpenSim.Server.Handlers.dll:MapAddServiceConnector"
MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
; * This is common for all services, it's the network setup for the entire ; * This is common for all services, it's the network setup for the entire
; * server instance, if none is specified above ; * server instance, if none is specified above

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -112,6 +112,34 @@
</Files> </Files>
</Project> </Project>
<Project frameworkVersion="v3_5" name="OpenSim.Services.Interfaces" path="OpenSim/Services/Interfaces" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/>
<Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="Nini" path="../../../bin/"/>
<Reference name="log4net" path="../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Framework.Monitoring" path="OpenSim/Framework/Monitoring" type="Library"> <Project frameworkVersion="v3_5" name="OpenSim.Framework.Monitoring" path="OpenSim/Framework/Monitoring" type="Library">
<Configuration name="Debug"> <Configuration name="Debug">
<Options> <Options>
@ -206,34 +234,6 @@
</Files> </Files>
</Project> </Project>
<Project frameworkVersion="v3_5" name="OpenSim.Services.Interfaces" path="OpenSim/Services/Interfaces" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/>
<Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="Nini" path="../../../bin/"/>
<Reference name="log4net" path="../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Framework.Serialization" path="OpenSim/Framework/Serialization" type="Library"> <Project frameworkVersion="v3_5" name="OpenSim.Framework.Serialization" path="OpenSim/Framework/Serialization" type="Library">
<Configuration name="Debug"> <Configuration name="Debug">
<Options> <Options>