Merge branch 'master' into careminster
Conflicts: OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs OpenSim/Region/Framework/Scenes/Scene.Inventory.cs OpenSim/Region/Framework/Scenes/Scene.csavinationmerge
commit
005c69511d
|
@ -467,12 +467,12 @@ namespace OpenSim.Groups
|
|||
}
|
||||
|
||||
// Send notice out to everyone that wants notices
|
||||
// Build notice IIM
|
||||
GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
|
||||
foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID))
|
||||
{
|
||||
if (member.AcceptNotices)
|
||||
{
|
||||
// Build notice IIM, one of reach, because the sending may be async
|
||||
GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
|
||||
msg.toAgentID = member.AgentID.Guid;
|
||||
OutgoingInstantMessage(msg, member.AgentID);
|
||||
}
|
||||
|
|
|
@ -292,6 +292,12 @@ namespace OpenSim.Framework
|
|||
public Vector3 AtAxis;
|
||||
public Vector3 LeftAxis;
|
||||
public Vector3 UpAxis;
|
||||
|
||||
/// <summary>
|
||||
/// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the
|
||||
/// scene presence to become root (triggered when the viewer sends a CompleteAgentMovement UDP packet after
|
||||
/// establishing the connection triggered by it's receipt of a TeleportFinish EQ message).
|
||||
/// </summary>
|
||||
public bool SenderWantsToWaitForRoot;
|
||||
|
||||
public float Far;
|
||||
|
|
|
@ -156,7 +156,27 @@ namespace OpenSim.Framework.Console
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
|
||||
/// Convert a console integer to an int, automatically complaining if a console is given.
|
||||
/// </summary>
|
||||
/// <param name='console'>Can be null if no console is available.</param>
|
||||
/// <param name='rawConsoleVector'>/param>
|
||||
/// <param name='vector'></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b)
|
||||
{
|
||||
if (!bool.TryParse(rawConsoleString, out b))
|
||||
{
|
||||
if (console != null)
|
||||
console.OutputFormat("ERROR: {0} is not a true or false value", rawConsoleString);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a console integer to an int, automatically complaining if a console is given.
|
||||
/// </summary>
|
||||
/// <param name='console'>Can be null if no console is available.</param>
|
||||
/// <param name='rawConsoleVector'>/param>
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenSim.Framework.Monitoring
|
||||
{
|
||||
public class Check
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public static readonly char[] DisallowedShortNameCharacters = { '.' };
|
||||
|
||||
/// <summary>
|
||||
/// Category of this stat (e.g. cache, scene, etc).
|
||||
/// </summary>
|
||||
public string Category { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Containing name for this stat.
|
||||
/// FIXME: In the case of a scene, this is currently the scene name (though this leaves
|
||||
/// us with a to-be-resolved problem of non-unique region names).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The container.
|
||||
/// </value>
|
||||
public string Container { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action used to check whether alert should go off.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Should return true if check passes. False otherwise.
|
||||
/// </remarks>
|
||||
public Func<Check, bool> CheckFunc { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Message from the last failure, if any. If there is no message or no failure then will be null.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Should be set by the CheckFunc when applicable.
|
||||
/// </remarks>
|
||||
public string LastFailureMessage { get; set; }
|
||||
|
||||
public StatVerbosity Verbosity { get; private set; }
|
||||
public string ShortName { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string Description { get; private set; }
|
||||
|
||||
public Check(
|
||||
string shortName,
|
||||
string name,
|
||||
string description,
|
||||
string category,
|
||||
string container,
|
||||
Func<Check, bool> checkFunc,
|
||||
StatVerbosity verbosity)
|
||||
{
|
||||
if (ChecksManager.SubCommands.Contains(category))
|
||||
throw new Exception(
|
||||
string.Format("Alert cannot be in category '{0}' since this is reserved for a subcommand", category));
|
||||
|
||||
foreach (char c in DisallowedShortNameCharacters)
|
||||
{
|
||||
if (shortName.IndexOf(c) != -1)
|
||||
throw new Exception(string.Format("Alert name {0} cannot contain character {1}", shortName, c));
|
||||
}
|
||||
|
||||
ShortName = shortName;
|
||||
Name = name;
|
||||
Description = description;
|
||||
Category = category;
|
||||
Container = container;
|
||||
CheckFunc = checkFunc;
|
||||
Verbosity = verbosity;
|
||||
}
|
||||
|
||||
public bool CheckIt()
|
||||
{
|
||||
return CheckFunc(this);
|
||||
}
|
||||
|
||||
public virtual string ToConsoleString()
|
||||
{
|
||||
return string.Format(
|
||||
"{0}.{1}.{2} - {3}",
|
||||
Category,
|
||||
Container,
|
||||
ShortName,
|
||||
Description);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using log4net;
|
||||
|
||||
namespace OpenSim.Framework.Monitoring
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class used to register/deregister checks on runtime conditions.
|
||||
/// </summary>
|
||||
public static class ChecksManager
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
// Subcommand used to list other stats.
|
||||
public const string ListSubCommand = "list";
|
||||
|
||||
// All subcommands
|
||||
public static HashSet<string> SubCommands = new HashSet<string> { ListSubCommand };
|
||||
|
||||
/// <summary>
|
||||
/// Checks categorized by category/container/shortname
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Do not add or remove directly from this dictionary.
|
||||
/// </remarks>
|
||||
public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>> RegisteredChecks
|
||||
= new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>>();
|
||||
|
||||
public static void RegisterConsoleCommands(ICommandConsole console)
|
||||
{
|
||||
console.Commands.AddCommand(
|
||||
"General",
|
||||
false,
|
||||
"show checks",
|
||||
"show checks",
|
||||
"Show checks configured for this server",
|
||||
"If no argument is specified then info on all checks will be shown.\n"
|
||||
+ "'list' argument will show check categories.\n"
|
||||
+ "THIS FACILITY IS EXPERIMENTAL",
|
||||
HandleShowchecksCommand);
|
||||
}
|
||||
|
||||
public static void HandleShowchecksCommand(string module, string[] cmd)
|
||||
{
|
||||
ICommandConsole con = MainConsole.Instance;
|
||||
|
||||
if (cmd.Length > 2)
|
||||
{
|
||||
foreach (string name in cmd.Skip(2))
|
||||
{
|
||||
string[] components = name.Split('.');
|
||||
|
||||
string categoryName = components[0];
|
||||
// string containerName = components.Length > 1 ? components[1] : null;
|
||||
|
||||
if (categoryName == ListSubCommand)
|
||||
{
|
||||
con.Output("check categories available are:");
|
||||
|
||||
foreach (string category in RegisteredChecks.Keys)
|
||||
con.OutputFormat(" {0}", category);
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// SortedDictionary<string, SortedDictionary<string, Check>> category;
|
||||
// if (!Registeredchecks.TryGetValue(categoryName, out category))
|
||||
// {
|
||||
// con.OutputFormat("No such category as {0}", categoryName);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (String.IsNullOrEmpty(containerName))
|
||||
// {
|
||||
// OutputConfiguredToConsole(con, category);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// SortedDictionary<string, Check> container;
|
||||
// if (category.TryGetValue(containerName, out container))
|
||||
// {
|
||||
// OutputContainerChecksToConsole(con, container);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputAllChecksToConsole(con);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a statistic.
|
||||
/// </summary>
|
||||
/// <param name='stat'></param>
|
||||
/// <returns></returns>
|
||||
public static bool RegisterCheck(Check check)
|
||||
{
|
||||
SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
|
||||
SortedDictionary<string, Check> container = null, newContainer;
|
||||
|
||||
lock (RegisteredChecks)
|
||||
{
|
||||
// Check 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
|
||||
// in a class are run in the same instance of the VM.
|
||||
if (TryGetCheckParents(check, out category, out container))
|
||||
return false;
|
||||
|
||||
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
|
||||
// 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 SortedDictionary<string, Check>(container);
|
||||
else
|
||||
newContainer = new SortedDictionary<string, Check>();
|
||||
|
||||
if (category != null)
|
||||
newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
|
||||
else
|
||||
newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>();
|
||||
|
||||
newContainer[check.ShortName] = check;
|
||||
newCategory[check.Container] = newContainer;
|
||||
RegisteredChecks[check.Category] = newCategory;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deregister an check
|
||||
/// </summary>>
|
||||
/// <param name='stat'></param>
|
||||
/// <returns></returns>
|
||||
public static bool DeregisterCheck(Check check)
|
||||
{
|
||||
SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
|
||||
SortedDictionary<string, Check> container = null, newContainer;
|
||||
|
||||
lock (RegisteredChecks)
|
||||
{
|
||||
if (!TryGetCheckParents(check, out category, out container))
|
||||
return false;
|
||||
|
||||
newContainer = new SortedDictionary<string, Check>(container);
|
||||
newContainer.Remove(check.ShortName);
|
||||
|
||||
newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
|
||||
newCategory.Remove(check.Container);
|
||||
|
||||
newCategory[check.Container] = newContainer;
|
||||
RegisteredChecks[check.Category] = newCategory;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetCheckParents(
|
||||
Check check,
|
||||
out SortedDictionary<string, SortedDictionary<string, Check>> category,
|
||||
out SortedDictionary<string, Check> container)
|
||||
{
|
||||
category = null;
|
||||
container = null;
|
||||
|
||||
lock (RegisteredChecks)
|
||||
{
|
||||
if (RegisteredChecks.TryGetValue(check.Category, out category))
|
||||
{
|
||||
if (category.TryGetValue(check.Container, out container))
|
||||
{
|
||||
if (container.ContainsKey(check.ShortName))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void CheckChecks()
|
||||
{
|
||||
lock (RegisteredChecks)
|
||||
{
|
||||
foreach (SortedDictionary<string, SortedDictionary<string, Check>> category in RegisteredChecks.Values)
|
||||
{
|
||||
foreach (SortedDictionary<string, Check> container in category.Values)
|
||||
{
|
||||
foreach (Check check in container.Values)
|
||||
{
|
||||
if (!check.CheckIt())
|
||||
m_log.WarnFormat(
|
||||
"[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OutputAllChecksToConsole(ICommandConsole con)
|
||||
{
|
||||
foreach (var category in RegisteredChecks.Values)
|
||||
{
|
||||
OutputCategoryChecksToConsole(con, category);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OutputCategoryChecksToConsole(
|
||||
ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Check>> category)
|
||||
{
|
||||
foreach (var container in category.Values)
|
||||
{
|
||||
OutputContainerChecksToConsole(con, container);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary<string, Check> container)
|
||||
{
|
||||
foreach (Check check in container.Values)
|
||||
{
|
||||
con.Output(check.ToConsoleString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Timers;
|
||||
using log4net;
|
||||
|
||||
namespace OpenSim.Framework.Monitoring
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a means to continuously log stats for debugging purposes.
|
||||
/// </summary>
|
||||
public static class StatsLogger
|
||||
{
|
||||
private static readonly ILog m_statsLog = LogManager.GetLogger("special.StatsLogger");
|
||||
|
||||
private static Timer m_loggingTimer;
|
||||
private static int m_statsLogIntervalMs = 5000;
|
||||
|
||||
public static void RegisterConsoleCommands(ICommandConsole console)
|
||||
{
|
||||
console.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug stats record",
|
||||
"debug stats record start|stop",
|
||||
"Control whether stats are being regularly recorded to a separate file.",
|
||||
"For debug purposes. Experimental.",
|
||||
HandleStatsRecordCommand);
|
||||
}
|
||||
|
||||
public static void HandleStatsRecordCommand(string module, string[] cmd)
|
||||
{
|
||||
ICommandConsole con = MainConsole.Instance;
|
||||
|
||||
if (cmd.Length != 4)
|
||||
{
|
||||
con.Output("Usage: debug stats record start|stop");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd[3] == "start")
|
||||
{
|
||||
Start();
|
||||
con.OutputFormat("Now recording all stats very {0}ms to file", m_statsLogIntervalMs);
|
||||
}
|
||||
else if (cmd[3] == "stop")
|
||||
{
|
||||
Stop();
|
||||
con.Output("Stopped recording stats to file.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
if (m_loggingTimer != null)
|
||||
Stop();
|
||||
|
||||
m_loggingTimer = new Timer(m_statsLogIntervalMs);
|
||||
m_loggingTimer.AutoReset = false;
|
||||
m_loggingTimer.Elapsed += Log;
|
||||
m_loggingTimer.Start();
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
if (m_loggingTimer != null)
|
||||
{
|
||||
m_loggingTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private static void Log(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
m_statsLog.InfoFormat("*** STATS REPORT AT {0} ***", DateTime.Now);
|
||||
|
||||
foreach (string report in StatsManager.GetAllStatsReports())
|
||||
m_statsLog.Info(report);
|
||||
|
||||
m_loggingTimer.Start();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,9 +35,9 @@ using OpenMetaverse.StructuredData;
|
|||
namespace OpenSim.Framework.Monitoring
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton used to provide access to statistics reporters
|
||||
/// Static class used to register/deregister/fetch statistics
|
||||
/// </summary>
|
||||
public class StatsManager
|
||||
public static class StatsManager
|
||||
{
|
||||
// Subcommand used to list other stats.
|
||||
public const string AllSubCommand = "all";
|
||||
|
@ -81,6 +81,8 @@ namespace OpenSim.Framework.Monitoring
|
|||
+ "More than one name can be given separated by spaces.\n"
|
||||
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
|
||||
HandleShowStatsCommand);
|
||||
|
||||
StatsLogger.RegisterConsoleCommands(console);
|
||||
}
|
||||
|
||||
public static void HandleShowStatsCommand(string module, string[] cmd)
|
||||
|
@ -145,29 +147,55 @@ namespace OpenSim.Framework.Monitoring
|
|||
}
|
||||
}
|
||||
|
||||
public static List<string> GetAllStatsReports()
|
||||
{
|
||||
List<string> reports = new List<string>();
|
||||
|
||||
foreach (var category in RegisteredStats.Values)
|
||||
reports.AddRange(GetCategoryStatsReports(category));
|
||||
|
||||
return reports;
|
||||
}
|
||||
|
||||
private static void OutputAllStatsToConsole(ICommandConsole con)
|
||||
{
|
||||
foreach (var category in RegisteredStats.Values)
|
||||
{
|
||||
OutputCategoryStatsToConsole(con, category);
|
||||
}
|
||||
foreach (string report in GetAllStatsReports())
|
||||
con.Output(report);
|
||||
}
|
||||
|
||||
private static List<string> GetCategoryStatsReports(
|
||||
SortedDictionary<string, SortedDictionary<string, Stat>> category)
|
||||
{
|
||||
List<string> reports = new List<string>();
|
||||
|
||||
foreach (var container in category.Values)
|
||||
reports.AddRange(GetContainerStatsReports(container));
|
||||
|
||||
return reports;
|
||||
}
|
||||
|
||||
private static void OutputCategoryStatsToConsole(
|
||||
ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category)
|
||||
{
|
||||
foreach (var container in category.Values)
|
||||
{
|
||||
OutputContainerStatsToConsole(con, container);
|
||||
}
|
||||
foreach (string report in GetCategoryStatsReports(category))
|
||||
con.Output(report);
|
||||
}
|
||||
|
||||
private static void OutputContainerStatsToConsole( ICommandConsole con, SortedDictionary<string, Stat> container)
|
||||
private static List<string> GetContainerStatsReports(SortedDictionary<string, Stat> container)
|
||||
{
|
||||
List<string> reports = new List<string>();
|
||||
|
||||
foreach (Stat stat in container.Values)
|
||||
{
|
||||
con.Output(stat.ToConsoleString());
|
||||
}
|
||||
reports.Add(stat.ToConsoleString());
|
||||
|
||||
return reports;
|
||||
}
|
||||
|
||||
private static void OutputContainerStatsToConsole(
|
||||
ICommandConsole con, SortedDictionary<string, Stat> container)
|
||||
{
|
||||
foreach (string report in GetContainerStatsReports(container))
|
||||
con.Output(report);
|
||||
}
|
||||
|
||||
// Creates an OSDMap of the format:
|
||||
|
@ -257,7 +285,7 @@ namespace OpenSim.Framework.Monitoring
|
|||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Registers a statistic.
|
||||
/// Register a statistic.
|
||||
/// </summary>
|
||||
/// <param name='stat'></param>
|
||||
/// <returns></returns>
|
||||
|
|
|
@ -380,6 +380,7 @@ namespace OpenSim.Framework.Monitoring
|
|||
if (MemoryWatchdog.Enabled)
|
||||
MemoryWatchdog.Update();
|
||||
|
||||
ChecksManager.CheckChecks();
|
||||
StatsManager.RecordStats();
|
||||
|
||||
m_watchdogTimer.Start();
|
||||
|
|
|
@ -246,7 +246,7 @@ namespace OpenSim.Framework.Servers
|
|||
"Show thread status", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"General", false, "threads abort",
|
||||
"Debug", false, "threads abort",
|
||||
"threads abort <thread-id>",
|
||||
"Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
|
||||
|
||||
|
@ -256,8 +256,32 @@ namespace OpenSim.Framework.Servers
|
|||
"Show thread status. Synonym for \"show threads\"",
|
||||
(string module, string[] args) => Notice(GetThreadsReport()));
|
||||
|
||||
m_console.Commands.AddCommand (
|
||||
"Debug", false, "debug comms set",
|
||||
"debug comms set serialosdreq true|false",
|
||||
"Set comms parameters. For debug purposes.",
|
||||
HandleDebugCommsSet);
|
||||
|
||||
m_console.Commands.AddCommand (
|
||||
"Debug", false, "debug comms status",
|
||||
"debug comms status",
|
||||
"Show current debug comms parameters.",
|
||||
HandleDebugCommsStatus);
|
||||
|
||||
m_console.Commands.AddCommand (
|
||||
"Debug", false, "debug threadpool set",
|
||||
"debug threadpool set worker|iocp min|max <n>",
|
||||
"Set threadpool parameters. For debug purposes.",
|
||||
HandleDebugThreadpoolSet);
|
||||
|
||||
m_console.Commands.AddCommand (
|
||||
"Debug", false, "debug threadpool status",
|
||||
"debug threadpool status",
|
||||
"Show current debug threadpool parameters.",
|
||||
HandleDebugThreadpoolStatus);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"General", false, "force gc",
|
||||
"Debug", false, "force gc",
|
||||
"force gc",
|
||||
"Manually invoke runtime garbage collection. For debugging purposes",
|
||||
HandleForceGc);
|
||||
|
@ -272,16 +296,142 @@ namespace OpenSim.Framework.Servers
|
|||
"shutdown",
|
||||
"Quit the application", (mod, args) => Shutdown());
|
||||
|
||||
ChecksManager.RegisterConsoleCommands(m_console);
|
||||
StatsManager.RegisterConsoleCommands(m_console);
|
||||
}
|
||||
|
||||
public void RegisterCommonComponents(IConfigSource configSource)
|
||||
{
|
||||
IConfig networkConfig = configSource.Configs["Network"];
|
||||
|
||||
if (networkConfig != null)
|
||||
{
|
||||
WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false);
|
||||
}
|
||||
|
||||
m_serverStatsCollector = new ServerStatsCollector();
|
||||
m_serverStatsCollector.Initialise(configSource);
|
||||
m_serverStatsCollector.Start();
|
||||
}
|
||||
|
||||
private void HandleDebugCommsStatus(string module, string[] args)
|
||||
{
|
||||
Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint);
|
||||
}
|
||||
|
||||
private void HandleDebugCommsSet(string module, string[] args)
|
||||
{
|
||||
if (args.Length != 5)
|
||||
{
|
||||
Notice("Usage: debug comms set serialosdreq true|false");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[3] != "serialosdreq")
|
||||
{
|
||||
Notice("Usage: debug comms set serialosdreq true|false");
|
||||
return;
|
||||
}
|
||||
|
||||
bool setSerializeOsdRequests;
|
||||
|
||||
if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests))
|
||||
return;
|
||||
|
||||
WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests;
|
||||
|
||||
Notice("serialosdreq is now {0}", setSerializeOsdRequests);
|
||||
}
|
||||
|
||||
private void HandleDebugThreadpoolStatus(string module, string[] args)
|
||||
{
|
||||
int workerThreads, iocpThreads;
|
||||
|
||||
ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
|
||||
Notice("Min worker threads: {0}", workerThreads);
|
||||
Notice("Min IOCP threads: {0}", iocpThreads);
|
||||
|
||||
ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
|
||||
Notice("Max worker threads: {0}", workerThreads);
|
||||
Notice("Max IOCP threads: {0}", iocpThreads);
|
||||
|
||||
ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
|
||||
Notice("Available worker threads: {0}", workerThreads);
|
||||
Notice("Available IOCP threads: {0}", iocpThreads);
|
||||
}
|
||||
|
||||
private void HandleDebugThreadpoolSet(string module, string[] args)
|
||||
{
|
||||
if (args.Length != 6)
|
||||
{
|
||||
Notice("Usage: debug threadpool set worker|iocp min|max <n>");
|
||||
return;
|
||||
}
|
||||
|
||||
int newThreads;
|
||||
|
||||
if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads))
|
||||
return;
|
||||
|
||||
string poolType = args[3];
|
||||
string bound = args[4];
|
||||
|
||||
bool fail = false;
|
||||
int workerThreads, iocpThreads;
|
||||
|
||||
if (poolType == "worker")
|
||||
{
|
||||
if (bound == "min")
|
||||
{
|
||||
ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
|
||||
|
||||
if (!ThreadPool.SetMinThreads(newThreads, iocpThreads))
|
||||
fail = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
|
||||
|
||||
if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads))
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bound == "min")
|
||||
{
|
||||
ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
|
||||
|
||||
if (!ThreadPool.SetMinThreads(workerThreads, newThreads))
|
||||
fail = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
|
||||
|
||||
if (!ThreadPool.SetMaxThreads(workerThreads, newThreads))
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fail)
|
||||
{
|
||||
Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads);
|
||||
}
|
||||
else
|
||||
{
|
||||
int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads;
|
||||
|
||||
ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads);
|
||||
ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads);
|
||||
|
||||
Notice("Min worker threads now {0}", minWorkerThreads);
|
||||
Notice("Min IOCP threads now {0}", minIocpThreads);
|
||||
Notice("Max worker threads now {0}", maxWorkerThreads);
|
||||
Notice("Max IOCP threads now {0}", maxIocpThreads);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleForceGc(string module, string[] args)
|
||||
{
|
||||
Notice("Manually invoking runtime garbage collection");
|
||||
|
|
|
@ -66,6 +66,11 @@ namespace OpenSim.Framework
|
|||
/// </summary>
|
||||
public static int RequestNumber { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Control where OSD requests should be serialized per endpoint.
|
||||
/// </summary>
|
||||
public static bool SerializeOSDRequestsPerEndpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// this is the header field used to communicate the local request id
|
||||
/// used for performance and debugging
|
||||
|
@ -145,9 +150,16 @@ namespace OpenSim.Framework
|
|||
|
||||
public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed)
|
||||
{
|
||||
lock (EndPointLock(url))
|
||||
if (SerializeOSDRequestsPerEndpoint)
|
||||
{
|
||||
return ServiceOSDRequestWorker(url,data,method,timeout,compressed);
|
||||
lock (EndPointLock(url))
|
||||
{
|
||||
return ServiceOSDRequestWorker(url, data, method, timeout, compressed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ServiceOSDRequestWorker(url, data, method, timeout, compressed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,26 +103,38 @@ namespace OpenSim
|
|||
"[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset");
|
||||
|
||||
// Verify the Threadpool allocates or uses enough worker and IO completion threads
|
||||
// .NET 2.0 workerthreads default to 50 * numcores
|
||||
// .NET 3.0 workerthreads defaults to 250 * numcores
|
||||
// .NET 4.0 workerthreads are dynamic based on bitness and OS resources
|
||||
// Max IO Completion threads are 1000 on all 3 CLRs.
|
||||
// .NET 2.0, workerthreads default to 50 * numcores
|
||||
// .NET 3.0, workerthreads defaults to 250 * numcores
|
||||
// .NET 4.0, workerthreads are dynamic based on bitness and OS resources
|
||||
// Max IO Completion threads are 1000 on all 3 CLRs
|
||||
//
|
||||
// Mono 2.10.9 to at least Mono 3.1, workerthreads default to 100 * numcores, iocp threads to 4 * numcores
|
||||
int workerThreadsMin = 500;
|
||||
int workerThreadsMax = 1000; // may need further adjustment to match other CLR
|
||||
int iocpThreadsMin = 1000;
|
||||
int iocpThreadsMax = 2000; // may need further adjustment to match other CLR
|
||||
|
||||
{
|
||||
int currentMinWorkerThreads, currentMinIocpThreads;
|
||||
System.Threading.ThreadPool.GetMinThreads(out currentMinWorkerThreads, out currentMinIocpThreads);
|
||||
m_log.InfoFormat(
|
||||
"[OPENSIM MAIN]: Runtime gave us {0} min worker threads and {1} min IOCP threads",
|
||||
currentMinWorkerThreads, currentMinIocpThreads);
|
||||
}
|
||||
|
||||
int workerThreads, iocpThreads;
|
||||
System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads);
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} max worker threads and {1} max IOCP threads", workerThreads, iocpThreads);
|
||||
|
||||
if (workerThreads < workerThreadsMin)
|
||||
{
|
||||
workerThreads = workerThreadsMin;
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Bumping up to worker threads to {0}",workerThreads);
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Bumping up to max worker threads to {0}",workerThreads);
|
||||
}
|
||||
if (workerThreads > workerThreadsMax)
|
||||
{
|
||||
workerThreads = workerThreadsMax;
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Limiting worker threads to {0}",workerThreads);
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Limiting max worker threads to {0}",workerThreads);
|
||||
}
|
||||
|
||||
// Increase the number of IOCP threads available.
|
||||
|
@ -130,22 +142,24 @@ namespace OpenSim
|
|||
if (iocpThreads < iocpThreadsMin)
|
||||
{
|
||||
iocpThreads = iocpThreadsMin;
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Bumping up IO completion threads to {0}",iocpThreads);
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IO completion threads to {0}",iocpThreads);
|
||||
}
|
||||
// Make sure we don't overallocate IOCP threads and thrash system resources
|
||||
if ( iocpThreads > iocpThreadsMax )
|
||||
{
|
||||
iocpThreads = iocpThreadsMax;
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Limiting IO completion threads to {0}",iocpThreads);
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IO completion threads to {0}",iocpThreads);
|
||||
}
|
||||
// set the resulting worker and IO completion thread counts back to ThreadPool
|
||||
if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) )
|
||||
{
|
||||
m_log.InfoFormat("[OPENSIM MAIN]: Threadpool set to {0} worker threads and {1} IO completion threads", workerThreads, iocpThreads);
|
||||
m_log.InfoFormat(
|
||||
"[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IO completion threads",
|
||||
workerThreads, iocpThreads);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.Info("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect.");
|
||||
m_log.Warn("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect.");
|
||||
}
|
||||
|
||||
// Check if the system is compatible with OpenSimulator.
|
||||
|
@ -153,17 +167,16 @@ namespace OpenSim
|
|||
string supported = String.Empty;
|
||||
if (Util.IsEnvironmentSupported(ref supported))
|
||||
{
|
||||
m_log.Info("Environment is compatible.\n");
|
||||
m_log.Info("[OPENSIM MAIN]: Environment is supported by OpenSimulator.");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.Warn("Environment is unsupported (" + supported + ")\n");
|
||||
m_log.Warn("[OPENSIM MAIN]: Environment is not supported by OpenSimulator (" + supported + ")\n");
|
||||
}
|
||||
|
||||
// Configure nIni aliases and localles
|
||||
Culture.SetCurrentCulture();
|
||||
|
||||
|
||||
// Validate that the user has the most basic configuration done
|
||||
// If not, offer to do the most basic configuration for them warning them along the way of the importance of
|
||||
// reading these files.
|
||||
|
|
|
@ -337,7 +337,6 @@ namespace OpenSim
|
|||
config.Set("physics", "OpenDynamicsEngine");
|
||||
config.Set("meshing", "Meshmerizer");
|
||||
config.Set("physical_prim", true);
|
||||
config.Set("see_into_this_sim_from_neighbor", true);
|
||||
config.Set("serverside_object_permissions", true);
|
||||
config.Set("storage_plugin", "OpenSim.Data.SQLite.dll");
|
||||
config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3");
|
||||
|
|
|
@ -29,6 +29,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using log4net.Config;
|
||||
using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
|
@ -53,6 +54,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
|||
[TestFixtureSetUp]
|
||||
public void FixtureInit()
|
||||
{
|
||||
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
|
||||
Util.FireAndForgetMethod = FireAndForgetMethod.None;
|
||||
|
||||
using (
|
||||
Stream resource
|
||||
= GetType().Assembly.GetManifestResourceStream(
|
||||
|
@ -72,6 +76,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[TestFixtureTearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
|
||||
// threads. Possibly, later tests should be rewritten not to worry about such things.
|
||||
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public override void SetUp()
|
||||
{
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
|
|||
|
||||
// Do Decode!
|
||||
if (decode)
|
||||
Decode(assetID, j2kData);
|
||||
Util.FireAndForget(delegate { Decode(assetID, j2kData); });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,8 +54,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
|||
public int DebugLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in
|
||||
/// or many avatars with a medium levels of attachments login simultaneously.
|
||||
/// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in/changes
|
||||
/// outfit or many avatars with a medium levels of attachments login/change outfit simultaneously.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A value of 0 will apply no pause. The pause is specified in milliseconds.
|
||||
|
@ -1094,7 +1094,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
|||
}
|
||||
|
||||
if (tainted)
|
||||
objatt.HasGroupChanged = true;
|
||||
objatt.HasGroupChanged = true;
|
||||
|
||||
if (ThrottlePer100PrimsRezzed > 0)
|
||||
{
|
||||
int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed);
|
||||
|
||||
if (DebugLevel > 0)
|
||||
m_log.DebugFormat(
|
||||
"[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}",
|
||||
throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name);
|
||||
|
||||
Thread.Sleep(throttleMs);
|
||||
}
|
||||
|
||||
return objatt;
|
||||
}
|
||||
|
|
|
@ -693,8 +693,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
if (version.Equals("SIMULATION/0.2"))
|
||||
TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason);
|
||||
else
|
||||
TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason);
|
||||
|
||||
TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason);
|
||||
}
|
||||
|
||||
private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination,
|
||||
|
@ -703,7 +702,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
ulong destinationHandle = finalDestination.RegionHandle;
|
||||
AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode);
|
||||
|
||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Using TP V1");
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}",
|
||||
sp.Name, Scene.Name, finalDestination.RegionName);
|
||||
|
||||
// Let's create an agent there if one doesn't exist yet.
|
||||
// NOTE: logout will always be false for a non-HG teleport.
|
||||
bool logout = false;
|
||||
|
@ -961,6 +963,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
|
||||
{
|
||||
m_interRegionTeleportCancels.Value++;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
|
||||
{
|
||||
m_interRegionTeleportAborts.Value++;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Past this point we have to attempt clean up if the teleport fails, so update transfer state.
|
||||
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
||||
|
||||
|
@ -1063,20 +1086,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
if (!sp.DoNotCloseAfterTeleport)
|
||||
{
|
||||
// OK, it got this agent. Let's close everything
|
||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.RegionInfo.RegionName);
|
||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.Name);
|
||||
sp.CloseChildAgents(newRegionX, newRegionY);
|
||||
sp.Scene.IncomingCloseAgent(sp.UUID, false);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.RegionInfo.RegionName);
|
||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.Name);
|
||||
sp.DoNotCloseAfterTeleport = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// now we have a child agent in this region.
|
||||
sp.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -62,6 +62,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
|||
private string m_ThisGatekeeper;
|
||||
private bool m_RestrictInventoryAccessAbroad;
|
||||
|
||||
private bool m_bypassPermissions = true;
|
||||
|
||||
// private bool m_Initialized = false;
|
||||
|
||||
#region INonSharedRegionModule
|
||||
|
@ -100,6 +102,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
|||
}
|
||||
else
|
||||
m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!");
|
||||
|
||||
m_bypassPermissions = !Util.GetConfigVarFromSections<bool>(source, "serverside_object_permissions",
|
||||
new string[] { "Startup", "Permissions" }, true);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +120,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
|||
scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem;
|
||||
scene.EventManager.OnTeleportStart += TeleportStart;
|
||||
scene.EventManager.OnTeleportFail += TeleportFail;
|
||||
|
||||
// We're fgoing to enforce some stricter permissions if Outbound is false
|
||||
scene.Permissions.OnTakeObject += CanTakeObject;
|
||||
scene.Permissions.OnTakeCopyObject += CanTakeObject;
|
||||
scene.Permissions.OnTransferUserInventory += OnTransferUserInventory;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -416,6 +427,37 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
|||
// No-op for now
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Permissions
|
||||
|
||||
private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene)
|
||||
{
|
||||
if (m_bypassPermissions) return true;
|
||||
|
||||
if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(stealer))
|
||||
{
|
||||
SceneObjectGroup sog = null;
|
||||
if (m_Scene.TryGetSceneObjectGroup(objectID, out sog) && sog.OwnerID == stealer)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool OnTransferUserInventory(UUID itemID, UUID userID, UUID recipientID)
|
||||
{
|
||||
if (m_bypassPermissions) return true;
|
||||
|
||||
if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(recipientID))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -809,7 +809,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
|||
}
|
||||
|
||||
objlist.Add(g);
|
||||
veclist.Add(new Vector3(0, 0, 0));
|
||||
veclist.Add(Vector3.Zero);
|
||||
|
||||
float offsetHeight = 0;
|
||||
pos = m_Scene.GetNewRezLocation(
|
||||
|
|
|
@ -163,7 +163,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
|
|||
|
||||
public void RegisterScriptInvocation(object target, MethodInfo mi)
|
||||
{
|
||||
m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name);
|
||||
// m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name);
|
||||
|
||||
Type delegateType;
|
||||
List<Type> typeArgs = mi.GetParameters()
|
||||
|
@ -325,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
|
|||
/// </summary>
|
||||
public void RegisterConstant(string cname, object value)
|
||||
{
|
||||
m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString());
|
||||
// m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString());
|
||||
lock (m_constants)
|
||||
{
|
||||
m_constants.Add(cname,value);
|
||||
|
|
|
@ -63,35 +63,41 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
|||
/// </summary>
|
||||
private bool m_ModuleEnabled = false;
|
||||
|
||||
public LocalSimulationConnectorModule()
|
||||
{
|
||||
ServiceVersion = "SIMULATION/0.2";
|
||||
}
|
||||
|
||||
#region Region Module interface
|
||||
|
||||
public void Initialise(IConfigSource config)
|
||||
public void Initialise(IConfigSource configSource)
|
||||
{
|
||||
IConfig moduleConfig = config.Configs["Modules"];
|
||||
IConfig moduleConfig = configSource.Configs["Modules"];
|
||||
if (moduleConfig != null)
|
||||
{
|
||||
string name = moduleConfig.GetString("SimulationServices", "");
|
||||
if (name == Name)
|
||||
{
|
||||
//IConfig userConfig = config.Configs["SimulationService"];
|
||||
//if (userConfig == null)
|
||||
//{
|
||||
// m_log.Error("[AVATAR CONNECTOR]: SimulationService missing from OpenSim.ini");
|
||||
// return;
|
||||
//}
|
||||
InitialiseService(configSource);
|
||||
|
||||
m_ModuleEnabled = true;
|
||||
|
||||
m_log.Info("[SIMULATION CONNECTOR]: Local simulation enabled");
|
||||
m_log.Info("[LOCAL SIMULATION CONNECTOR]: Local simulation enabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InitialiseService(IConfigSource configSource)
|
||||
{
|
||||
ServiceVersion = "SIMULATION/0.2";
|
||||
IConfig config = configSource.Configs["SimulationService"];
|
||||
if (config != null)
|
||||
{
|
||||
ServiceVersion = config.GetString("ConnectorProtocolVersion", ServiceVersion);
|
||||
|
||||
if (ServiceVersion != "SIMULATION/0.1" && ServiceVersion != "SIMULATION/0.2")
|
||||
throw new Exception(string.Format("Invalid ConnectorProtocolVersion {0}", ServiceVersion));
|
||||
|
||||
m_log.InfoFormat(
|
||||
"[LOCAL SIMULATION CONNECTOR]: Initialzied with connector protocol version {0}", ServiceVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public void PostInitialise()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -50,9 +50,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
|||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteSimulationConnectorModule")]
|
||||
public class RemoteSimulationConnectorModule : ISharedRegionModule, ISimulationService
|
||||
{
|
||||
private bool initialized = false;
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private bool initialized = false;
|
||||
protected bool m_enabled = false;
|
||||
protected Scene m_aScene;
|
||||
// RemoteSimulationConnector does not care about local regions; it delegates that to the Local module
|
||||
|
@ -64,27 +64,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
|||
|
||||
#region Region Module interface
|
||||
|
||||
public virtual void Initialise(IConfigSource config)
|
||||
public virtual void Initialise(IConfigSource configSource)
|
||||
{
|
||||
|
||||
IConfig moduleConfig = config.Configs["Modules"];
|
||||
IConfig moduleConfig = configSource.Configs["Modules"];
|
||||
if (moduleConfig != null)
|
||||
{
|
||||
string name = moduleConfig.GetString("SimulationServices", "");
|
||||
if (name == Name)
|
||||
{
|
||||
//IConfig userConfig = config.Configs["SimulationService"];
|
||||
//if (userConfig == null)
|
||||
//{
|
||||
// m_log.Error("[AVATAR CONNECTOR]: SimulationService missing from OpenSim.ini");
|
||||
// return;
|
||||
//}
|
||||
m_localBackend = new LocalSimulationConnectorModule();
|
||||
|
||||
m_localBackend.InitialiseService(configSource);
|
||||
|
||||
m_remoteConnector = new SimulationServiceConnector();
|
||||
|
||||
m_enabled = true;
|
||||
|
||||
m_log.Info("[SIMULATION CONNECTOR]: Remote simulation enabled");
|
||||
m_log.Info("[REMOTE SIMULATION CONNECTOR]: Remote simulation enabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,8 +138,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
|||
}
|
||||
|
||||
protected virtual void InitOnce(Scene scene)
|
||||
{
|
||||
m_localBackend = new LocalSimulationConnectorModule();
|
||||
{
|
||||
m_aScene = scene;
|
||||
//m_regionClient = new RegionToRegionClient(m_aScene, m_hyperlinkService);
|
||||
m_thisIP = Util.GetHostFromDNS(scene.RegionInfo.ExternalHostName);
|
||||
|
|
|
@ -551,6 +551,9 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
{
|
||||
//Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem");
|
||||
|
||||
if (!Permissions.CanTransferUserInventory(itemId, senderId, recipient))
|
||||
return null;
|
||||
|
||||
InventoryItemBase item = new InventoryItemBase(itemId, senderId);
|
||||
item = InventoryService.GetItem(item);
|
||||
|
||||
|
@ -2127,7 +2130,10 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
{
|
||||
// If we don't have permission, stop right here
|
||||
if (!permissionToTakeCopy)
|
||||
{
|
||||
remoteClient.SendAlertMessage("You don't have permission to take the object");
|
||||
return;
|
||||
}
|
||||
|
||||
permissionToTake = true;
|
||||
// Don't delete
|
||||
|
|
|
@ -4174,28 +4174,29 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
}
|
||||
|
||||
if (RegionInfo.EstateSettings != null)
|
||||
{
|
||||
if (RegionInfo.EstateSettings.IsBanned(agent.AgentID, 0))
|
||||
{
|
||||
m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
|
||||
agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
|
||||
reason = String.Format("Denied access to region {0}: You have been banned from that region.",
|
||||
RegionInfo.RegionName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
|
||||
}
|
||||
|
||||
// We only test the things below when we want to cut off
|
||||
// child agents from being present in the scene for which their root
|
||||
// agent isn't allowed. Otherwise, we allow child agents. The test for
|
||||
// the root is done elsewhere (QueryAccess)
|
||||
if (!bypassAccessControl)
|
||||
{
|
||||
if (RegionInfo.EstateSettings != null)
|
||||
{
|
||||
int flags = GetUserFlags(agent.AgentID);
|
||||
if (RegionInfo.EstateSettings.IsBanned(agent.AgentID, flags))
|
||||
{
|
||||
m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
|
||||
agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
|
||||
reason = String.Format("Denied access to region {0}: You have been banned from that region.",
|
||||
RegionInfo.RegionName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
|
||||
}
|
||||
|
||||
List<UUID> agentGroups = new List<UUID>();
|
||||
|
||||
if (m_groupsModule != null)
|
||||
|
@ -4392,36 +4393,42 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
|
||||
// We have to wait until the viewer contacts this region
|
||||
// after receiving the EnableSimulator HTTP Event Queue message. This triggers the viewer to send
|
||||
// after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol)
|
||||
// or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send
|
||||
// a UseCircuitCode packet which in turn calls AddNewClient which finally creates the ScenePresence.
|
||||
ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
|
||||
ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID);
|
||||
|
||||
if (childAgentUpdate != null)
|
||||
if (sp != null)
|
||||
{
|
||||
if (cAgentData.SessionID != childAgentUpdate.ControllingClient.SessionId)
|
||||
if (cAgentData.SessionID != sp.ControllingClient.SessionId)
|
||||
{
|
||||
m_log.WarnFormat("[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).", childAgentUpdate.UUID, cAgentData.SessionID);
|
||||
m_log.WarnFormat(
|
||||
"[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).",
|
||||
sp.UUID, cAgentData.SessionID);
|
||||
|
||||
Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}",
|
||||
childAgentUpdate.UUID, childAgentUpdate.ControllingClient.SessionId, cAgentData.SessionID));
|
||||
sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID));
|
||||
}
|
||||
|
||||
childAgentUpdate.ChildAgentDataUpdate(cAgentData);
|
||||
sp.ChildAgentDataUpdate(cAgentData);
|
||||
|
||||
int ntimes = 20;
|
||||
if (cAgentData.SenderWantsToWaitForRoot)
|
||||
{
|
||||
while (childAgentUpdate.IsChildAgent && ntimes-- > 0)
|
||||
while (sp.IsChildAgent && ntimes-- > 0)
|
||||
Thread.Sleep(1000);
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[SCENE]: Found presence {0} {1} {2} in {3} after {4} waits",
|
||||
childAgentUpdate.Name, childAgentUpdate.UUID, childAgentUpdate.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 20 - ntimes);
|
||||
sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", Name, 20 - ntimes);
|
||||
|
||||
if (childAgentUpdate.IsChildAgent)
|
||||
if (sp.IsChildAgent)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -294,10 +294,24 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
/// </summary>
|
||||
private Vector3 posLastSignificantMove;
|
||||
|
||||
// For teleports and crossings callbacks
|
||||
#region For teleports and crossings callbacks
|
||||
|
||||
/// <summary>
|
||||
/// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address.
|
||||
/// </summary>
|
||||
string m_callbackURI;
|
||||
|
||||
UUID m_originRegionID;
|
||||
|
||||
/// <summary>
|
||||
/// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
|
||||
/// teleport is reusing the connection.
|
||||
/// </summary>
|
||||
/// <remarks>May be refactored or move somewhere else soon.</remarks>
|
||||
public bool DoNotCloseAfterTeleport { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <value>
|
||||
/// Script engines present in the scene
|
||||
/// </value>
|
||||
|
@ -764,13 +778,6 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
|
||||
/// teleport is reusing the connection.
|
||||
/// </summary>
|
||||
/// <remarks>May be refactored or move somewhere else soon.</remarks>
|
||||
public bool DoNotCloseAfterTeleport { get; set; }
|
||||
|
||||
private float m_speedModifier = 1.0f;
|
||||
|
||||
public float SpeedModifier
|
||||
|
@ -1516,14 +1523,14 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
int count = 20;
|
||||
while (m_originRegionID.Equals(UUID.Zero) && count-- > 0)
|
||||
{
|
||||
m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.RegionInfo.RegionName);
|
||||
m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name);
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
if (m_originRegionID.Equals(UUID.Zero))
|
||||
{
|
||||
// Movement into region will fail
|
||||
m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived", client.Name);
|
||||
m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1829,8 +1836,14 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
// Here's where you get them.
|
||||
m_AgentControlFlags = flags;
|
||||
m_headrotation = agentData.HeadRotation;
|
||||
byte oldState = State;
|
||||
State = agentData.State;
|
||||
|
||||
// We need to send this back to the client in order to stop the edit beams
|
||||
if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None)
|
||||
ControllingClient.SendAgentTerseUpdate(this);
|
||||
|
||||
|
||||
PhysicsActor actor = PhysicsActor;
|
||||
if (actor == null)
|
||||
{
|
||||
|
@ -3199,8 +3212,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
|
||||
// Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m
|
||||
if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance ||
|
||||
Util.GetDistanceTo(CameraPosition, m_lastChildAgentUpdateCamPosition) >= Scene.ChildReprioritizationDistance)
|
||||
if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance)
|
||||
{
|
||||
m_lastChildAgentUpdatePosition = AbsolutePosition;
|
||||
m_lastChildAgentUpdateCamPosition = CameraPosition;
|
||||
|
|
|
@ -49,10 +49,20 @@ public class ExtendedPhysics : INonSharedRegionModule
|
|||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[EXTENDED PHYSICS]";
|
||||
|
||||
// =============================================================
|
||||
// Since BulletSim is a plugin, this these values aren't defined easily in one place.
|
||||
// This table must coorespond to an identical table in BSScene.
|
||||
// This table must correspond to an identical table in BSScene.
|
||||
|
||||
// Per scene functions. See BSScene.
|
||||
|
||||
// Per avatar functions. See BSCharacter.
|
||||
|
||||
// Per prim functions. See BSPrim.
|
||||
public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
|
||||
public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
|
||||
|
||||
// =============================================================
|
||||
|
||||
private IConfig Configuration { get; set; }
|
||||
private bool Enabled { get; set; }
|
||||
private Scene BaseScene { get; set; }
|
||||
|
@ -123,6 +133,7 @@ public class ExtendedPhysics : INonSharedRegionModule
|
|||
|
||||
// Register as LSL functions all the [ScriptInvocation] marked methods.
|
||||
Comms.RegisterScriptInvocations(this);
|
||||
Comms.RegisterConstants(this);
|
||||
|
||||
// When an object is modified, we might need to update its extended physics parameters
|
||||
BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
|
||||
|
@ -136,7 +147,6 @@ public class ExtendedPhysics : INonSharedRegionModule
|
|||
|
||||
private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// Event generated when some property of a prim changes.
|
||||
|
@ -168,9 +178,11 @@ public class ExtendedPhysics : INonSharedRegionModule
|
|||
public static int PHYS_LINKSET_TYPE_MANUAL = 2;
|
||||
|
||||
[ScriptInvocation]
|
||||
public void physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
|
||||
public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
int ret = -1;
|
||||
|
||||
if (!Enabled) return ret;
|
||||
|
||||
// The part that is requesting the change.
|
||||
SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID);
|
||||
|
@ -186,7 +198,7 @@ public class ExtendedPhysics : INonSharedRegionModule
|
|||
Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor;
|
||||
if (rootPhysActor != null)
|
||||
{
|
||||
rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType);
|
||||
ret = (int)rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -204,6 +216,49 @@ public class ExtendedPhysics : INonSharedRegionModule
|
|||
{
|
||||
m_log.WarnFormat("{0} physSetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
[ScriptInvocation]
|
||||
public int physGetLinksetType(UUID hostID, UUID scriptID)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (!Enabled) return ret;
|
||||
|
||||
// The part that is requesting the change.
|
||||
SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID);
|
||||
|
||||
if (requestingPart != null)
|
||||
{
|
||||
// The type is is always on the root of a linkset.
|
||||
SceneObjectGroup containingGroup = requestingPart.ParentGroup;
|
||||
SceneObjectPart rootPart = containingGroup.RootPart;
|
||||
|
||||
if (rootPart != null)
|
||||
{
|
||||
Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor;
|
||||
if (rootPhysActor != null)
|
||||
{
|
||||
ret = (int)rootPhysActor.Extension(PhysFunctGetLinksetType);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("{0} physGetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}",
|
||||
LogHeader, rootPart.Name, hostID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("{0} physGetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}",
|
||||
LogHeader, requestingPart.Name, hostID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,17 @@ public abstract class BSLinkset
|
|||
return ret;
|
||||
}
|
||||
|
||||
public class BSLinkInfo
|
||||
{
|
||||
public BSPrimLinkable member;
|
||||
public BSLinkInfo(BSPrimLinkable pMember)
|
||||
{
|
||||
member = pMember;
|
||||
}
|
||||
}
|
||||
|
||||
public LinksetImplementation LinksetImpl { get; protected set; }
|
||||
|
||||
public BSPrimLinkable LinksetRoot { get; protected set; }
|
||||
|
||||
protected BSScene m_physicsScene { get; private set; }
|
||||
|
@ -78,7 +89,8 @@ public abstract class BSLinkset
|
|||
public int LinksetID { get; private set; }
|
||||
|
||||
// The children under the root in this linkset.
|
||||
protected HashSet<BSPrimLinkable> m_children;
|
||||
// protected HashSet<BSPrimLinkable> m_children;
|
||||
protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children;
|
||||
|
||||
// We lock the diddling of linkset classes to prevent any badness.
|
||||
// This locks the modification of the instances of this class. Changes
|
||||
|
@ -109,7 +121,7 @@ public abstract class BSLinkset
|
|||
m_nextLinksetID = 1;
|
||||
m_physicsScene = scene;
|
||||
LinksetRoot = parent;
|
||||
m_children = new HashSet<BSPrimLinkable>();
|
||||
m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>();
|
||||
LinksetMass = parent.RawMass;
|
||||
Rebuilding = false;
|
||||
|
||||
|
@ -170,17 +182,7 @@ public abstract class BSLinkset
|
|||
bool ret = false;
|
||||
lock (m_linksetActivityLock)
|
||||
{
|
||||
ret = m_children.Contains(child);
|
||||
/* Safer version but the above should work
|
||||
foreach (BSPrimLinkable bp in m_children)
|
||||
{
|
||||
if (child.LocalID == bp.LocalID)
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
ret = m_children.ContainsKey(child);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -194,7 +196,24 @@ public abstract class BSLinkset
|
|||
lock (m_linksetActivityLock)
|
||||
{
|
||||
action(LinksetRoot);
|
||||
foreach (BSPrimLinkable po in m_children)
|
||||
foreach (BSPrimLinkable po in m_children.Keys)
|
||||
{
|
||||
if (action(po))
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Perform an action on each member of the linkset including root prim.
|
||||
// Depends on the action on whether this should be done at taint time.
|
||||
public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
|
||||
public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
|
||||
{
|
||||
bool ret = false;
|
||||
lock (m_linksetActivityLock)
|
||||
{
|
||||
foreach (BSLinkInfo po in m_children.Values)
|
||||
{
|
||||
if (action(po))
|
||||
break;
|
||||
|
@ -364,7 +383,7 @@ public abstract class BSLinkset
|
|||
{
|
||||
lock (m_linksetActivityLock)
|
||||
{
|
||||
foreach (BSPrimLinkable bp in m_children)
|
||||
foreach (BSPrimLinkable bp in m_children.Keys)
|
||||
{
|
||||
mass += bp.RawMass;
|
||||
}
|
||||
|
@ -382,7 +401,7 @@ public abstract class BSLinkset
|
|||
com = LinksetRoot.Position * LinksetRoot.RawMass;
|
||||
float totalMass = LinksetRoot.RawMass;
|
||||
|
||||
foreach (BSPrimLinkable bp in m_children)
|
||||
foreach (BSPrimLinkable bp in m_children.Keys)
|
||||
{
|
||||
com += bp.Position * bp.RawMass;
|
||||
totalMass += bp.RawMass;
|
||||
|
@ -401,7 +420,7 @@ public abstract class BSLinkset
|
|||
{
|
||||
com = LinksetRoot.Position;
|
||||
|
||||
foreach (BSPrimLinkable bp in m_children)
|
||||
foreach (BSPrimLinkable bp in m_children.Keys)
|
||||
{
|
||||
com += bp.Position;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
|||
public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
|
||||
: base(scene, parent)
|
||||
{
|
||||
LinksetImpl = LinksetImplementation.Compound;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
|
@ -257,7 +258,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
|||
{
|
||||
if (!HasChild(child))
|
||||
{
|
||||
m_children.Add(child);
|
||||
m_children.Add(child, new BSLinkInfo(child));
|
||||
|
||||
DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
|
||||
|
||||
|
@ -353,7 +354,7 @@ public sealed class BSLinksetCompound : BSLinkset
|
|||
|
||||
// Add the shapes of all the components of the linkset
|
||||
int memberIndex = 1;
|
||||
ForEachMember(delegate(BSPrimLinkable cPrim)
|
||||
ForEachMember((cPrim) =>
|
||||
{
|
||||
if (IsRoot(cPrim))
|
||||
{
|
||||
|
|
|
@ -36,8 +36,78 @@ public sealed class BSLinksetConstraints : BSLinkset
|
|||
{
|
||||
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
|
||||
|
||||
public class BSLinkInfoConstraint : BSLinkInfo
|
||||
{
|
||||
public ConstraintType constraintType;
|
||||
public BSConstraint constraint;
|
||||
public OMV.Vector3 linearLimitLow;
|
||||
public OMV.Vector3 linearLimitHigh;
|
||||
public OMV.Vector3 angularLimitLow;
|
||||
public OMV.Vector3 angularLimitHigh;
|
||||
public bool useFrameOffset;
|
||||
public bool enableTransMotor;
|
||||
public float transMotorMaxVel;
|
||||
public float transMotorMaxForce;
|
||||
public float cfm;
|
||||
public float erp;
|
||||
public float solverIterations;
|
||||
|
||||
public BSLinkInfoConstraint(BSPrimLinkable pMember)
|
||||
: base(pMember)
|
||||
{
|
||||
constraint = null;
|
||||
ResetToFixedConstraint();
|
||||
}
|
||||
|
||||
// Set all the parameters for this constraint to a fixed, non-movable constraint.
|
||||
public void ResetToFixedConstraint()
|
||||
{
|
||||
constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
|
||||
linearLimitLow = OMV.Vector3.Zero;
|
||||
linearLimitHigh = OMV.Vector3.Zero;
|
||||
angularLimitLow = OMV.Vector3.Zero;
|
||||
angularLimitHigh = OMV.Vector3.Zero;
|
||||
useFrameOffset = BSParam.LinkConstraintUseFrameOffset;
|
||||
enableTransMotor = BSParam.LinkConstraintEnableTransMotor;
|
||||
transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
|
||||
transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
|
||||
cfm = BSParam.LinkConstraintCFM;
|
||||
erp = BSParam.LinkConstraintERP;
|
||||
solverIterations = BSParam.LinkConstraintSolverIterations;
|
||||
}
|
||||
|
||||
// Given a constraint, apply the current constraint parameters to same.
|
||||
public void SetConstraintParameters(BSConstraint constrain)
|
||||
{
|
||||
switch (constraintType)
|
||||
{
|
||||
case ConstraintType.D6_CONSTRAINT_TYPE:
|
||||
BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
|
||||
if (constrain6dof != null)
|
||||
{
|
||||
// zero linear and angular limits makes the objects unable to move in relation to each other
|
||||
constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
|
||||
constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
|
||||
|
||||
// tweek the constraint to increase stability
|
||||
constrain6dof.UseFrameOffset(useFrameOffset);
|
||||
constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
|
||||
constrain6dof.SetCFMAndERP(cfm, erp);
|
||||
if (solverIterations != 0f)
|
||||
{
|
||||
constrain6dof.SetSolverIterations(solverIterations);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
|
||||
{
|
||||
LinksetImpl = LinksetImplementation.Constraint;
|
||||
}
|
||||
|
||||
// When physical properties are changed the linkset needs to recalculate
|
||||
|
@ -142,7 +212,7 @@ public sealed class BSLinksetConstraints : BSLinkset
|
|||
{
|
||||
if (!HasChild(child))
|
||||
{
|
||||
m_children.Add(child);
|
||||
m_children.Add(child, new BSLinkInfoConstraint(child));
|
||||
|
||||
DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
|
||||
|
||||
|
@ -190,73 +260,74 @@ public sealed class BSLinksetConstraints : BSLinkset
|
|||
}
|
||||
|
||||
// Create a static constraint between the two passed objects
|
||||
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
|
||||
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
|
||||
{
|
||||
BSLinkInfoConstraint liConstraint = li as BSLinkInfoConstraint;
|
||||
if (liConstraint == null)
|
||||
return null;
|
||||
|
||||
// Zero motion for children so they don't interpolate
|
||||
childPrim.ZeroMotion(true);
|
||||
li.member.ZeroMotion(true);
|
||||
|
||||
// Relative position normalized to the root prim
|
||||
// Essentually a vector pointing from center of rootPrim to center of childPrim
|
||||
OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
|
||||
BSConstraint constrain = null;
|
||||
|
||||
// real world coordinate of midpoint between the two objects
|
||||
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
|
||||
switch (liConstraint.constraintType)
|
||||
{
|
||||
case ConstraintType.D6_CONSTRAINT_TYPE:
|
||||
// Relative position normalized to the root prim
|
||||
// Essentually a vector pointing from center of rootPrim to center of li.member
|
||||
OMV.Vector3 childRelativePosition = liConstraint.member.Position - rootPrim.Position;
|
||||
|
||||
DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
|
||||
rootPrim.LocalID,
|
||||
rootPrim.LocalID, rootPrim.PhysBody.AddrString,
|
||||
childPrim.LocalID, childPrim.PhysBody.AddrString,
|
||||
rootPrim.Position, childPrim.Position, midPoint);
|
||||
// real world coordinate of midpoint between the two objects
|
||||
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
|
||||
|
||||
// create a constraint that allows no freedom of movement between the two objects
|
||||
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
||||
DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
|
||||
rootPrim.LocalID,
|
||||
rootPrim.LocalID, rootPrim.PhysBody.AddrString,
|
||||
liConstraint.member.LocalID, liConstraint.member.PhysBody.AddrString,
|
||||
rootPrim.Position, liConstraint.member.Position, midPoint);
|
||||
|
||||
BSConstraint6Dof constrain = new BSConstraint6Dof(
|
||||
m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
|
||||
// PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
|
||||
// create a constraint that allows no freedom of movement between the two objects
|
||||
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
|
||||
|
||||
/* 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
|
||||
* of the objects.
|
||||
* Code left for future programmers.
|
||||
// ==================================================================================
|
||||
// relative position normalized to the root prim
|
||||
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
|
||||
OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
|
||||
constrain = new BSConstraint6Dof(
|
||||
m_physicsScene.World, rootPrim.PhysBody, liConstraint.member.PhysBody, midPoint, true, true );
|
||||
|
||||
// relative rotation of the child to the parent
|
||||
OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
|
||||
OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
|
||||
/* 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
|
||||
* of the objects.
|
||||
* Code left for future programmers.
|
||||
// ==================================================================================
|
||||
// relative position normalized to the root prim
|
||||
OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
|
||||
OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation;
|
||||
|
||||
DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
|
||||
BS6DofConstraint constrain = new BS6DofConstraint(
|
||||
PhysicsScene.World, rootPrim.Body, childPrim.Body,
|
||||
OMV.Vector3.Zero,
|
||||
OMV.Quaternion.Inverse(rootPrim.Orientation),
|
||||
OMV.Vector3.Zero,
|
||||
OMV.Quaternion.Inverse(childPrim.Orientation),
|
||||
true,
|
||||
true
|
||||
);
|
||||
// ==================================================================================
|
||||
*/
|
||||
// relative rotation of the child to the parent
|
||||
OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation;
|
||||
OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
|
||||
|
||||
DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID);
|
||||
constrain = new BS6DofConstraint(
|
||||
PhysicsScene.World, rootPrim.Body, liConstraint.member.Body,
|
||||
OMV.Vector3.Zero,
|
||||
OMV.Quaternion.Inverse(rootPrim.Orientation),
|
||||
OMV.Vector3.Zero,
|
||||
OMV.Quaternion.Inverse(liConstraint.member.Orientation),
|
||||
true,
|
||||
true
|
||||
);
|
||||
// ==================================================================================
|
||||
*/
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
liConstraint.SetConstraintParameters(constrain);
|
||||
|
||||
m_physicsScene.Constraints.AddConstraint(constrain);
|
||||
|
||||
// zero linear and angular limits makes the objects unable to move in relation to each other
|
||||
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
||||
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
||||
|
||||
// tweek the constraint to increase stability
|
||||
constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset);
|
||||
constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor,
|
||||
BSParam.LinkConstraintTransMotorMaxVel,
|
||||
BSParam.LinkConstraintTransMotorMaxForce);
|
||||
constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
|
||||
if (BSParam.LinkConstraintSolverIterations != 0f)
|
||||
{
|
||||
constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
|
||||
}
|
||||
return constrain;
|
||||
}
|
||||
|
||||
|
@ -317,23 +388,24 @@ public sealed class BSLinksetConstraints : BSLinkset
|
|||
return; // Note the 'finally' clause at the botton which will get executed.
|
||||
}
|
||||
|
||||
foreach (BSPrimLinkable child in m_children)
|
||||
ForEachLinkInfo((li) =>
|
||||
{
|
||||
// A child in the linkset physically shows the mass of the whole linkset.
|
||||
// This allows Bullet to apply enough force on the child to move the whole linkset.
|
||||
// (Also do the mass stuff before recomputing the constraint so mass is not zero.)
|
||||
child.UpdatePhysicalMassProperties(linksetMass, true);
|
||||
li.member.UpdatePhysicalMassProperties(linksetMass, true);
|
||||
|
||||
BSConstraint constrain;
|
||||
if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
|
||||
if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain))
|
||||
{
|
||||
// If constraint doesn't exist yet, create it.
|
||||
constrain = BuildConstraint(LinksetRoot, child);
|
||||
constrain = BuildConstraint(LinksetRoot, li);
|
||||
}
|
||||
constrain.RecomputeConstraintVariables(linksetMass);
|
||||
|
||||
// PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
|
||||
}
|
||||
return false; // 'false' says to keep processing other members
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -1541,6 +1541,50 @@ public class BSPrim : BSPhysObject
|
|||
PhysicalActors.RemoveDependencies();
|
||||
}
|
||||
|
||||
#region Extension
|
||||
public override object Extension(string pFunct, params object[] pParams)
|
||||
{
|
||||
object ret = null;
|
||||
switch (pFunct)
|
||||
{
|
||||
case BSScene.PhysFunctGetLinksetType:
|
||||
{
|
||||
BSPrimLinkable myHandle = this as BSPrimLinkable;
|
||||
if (myHandle != null)
|
||||
{
|
||||
ret = (object)myHandle.LinksetType;
|
||||
}
|
||||
m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret);
|
||||
break;
|
||||
}
|
||||
case BSScene.PhysFunctSetLinksetType:
|
||||
{
|
||||
if (pParams.Length > 0)
|
||||
{
|
||||
BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0];
|
||||
BSPrimLinkable myHandle = this as BSPrimLinkable;
|
||||
if (myHandle != null && myHandle.Linkset.IsRoot(myHandle))
|
||||
{
|
||||
PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate()
|
||||
{
|
||||
// Cause the linkset type to change
|
||||
m_log.DebugFormat("{0} Extension.physSetLinksetType, oldType={1}, newType={2}",
|
||||
LogHeader, myHandle.Linkset.LinksetImpl, linksetType);
|
||||
myHandle.ConvertLinkset(linksetType);
|
||||
});
|
||||
}
|
||||
ret = (object)(int)linksetType;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = base.Extension(pFunct, pParams);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endregion // Extension
|
||||
|
||||
// The physics engine says that properties have updated. Update same and inform
|
||||
// the world that things have changed.
|
||||
// NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
|
||||
|
|
|
@ -233,5 +233,46 @@ public class BSPrimLinkable : BSPrimDisplaced
|
|||
base.HasSomeCollision = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the existing linkset of this prim into a new type.
|
||||
public bool ConvertLinkset(BSLinkset.LinksetImplementation newType)
|
||||
{
|
||||
bool ret = false;
|
||||
if (LinksetType != newType)
|
||||
{
|
||||
// Set the implementation type first so the call to BSLinkset.Factory gets the new type.
|
||||
this.LinksetType = newType;
|
||||
|
||||
BSLinkset oldLinkset = this.Linkset;
|
||||
BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this);
|
||||
|
||||
this.Linkset = newLinkset;
|
||||
|
||||
// Pick up any physical dependencies this linkset might have in the physics engine.
|
||||
oldLinkset.RemoveDependencies(this);
|
||||
|
||||
// Create a list of the children (mainly because can't interate through a list that's changing)
|
||||
List<BSPrimLinkable> children = new List<BSPrimLinkable>();
|
||||
oldLinkset.ForEachMember((child) =>
|
||||
{
|
||||
if (!oldLinkset.IsRoot(child))
|
||||
children.Add(child);
|
||||
return false; // 'false' says to continue to next member
|
||||
});
|
||||
|
||||
// Remove the children from the old linkset and add to the new (will be a new instance from the factory)
|
||||
foreach (BSPrimLinkable child in children)
|
||||
{
|
||||
oldLinkset.RemoveMeFromLinkset(child);
|
||||
newLinkset.AddMeToLinkset(child);
|
||||
child.Linkset = newLinkset;
|
||||
}
|
||||
|
||||
// Force the shape and linkset to get reconstructed
|
||||
newLinkset.Refresh(this);
|
||||
this.ForceBodyShapeRebuild(true /* inTaintTime */);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -862,6 +862,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
|
||||
public override bool IsThreaded { get { return false; } }
|
||||
|
||||
#region Extensions
|
||||
// =============================================================
|
||||
// Per scene functions. See below.
|
||||
|
||||
// Per avatar functions. See BSCharacter.
|
||||
|
||||
// Per prim functions. See BSPrim.
|
||||
public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
|
||||
public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
|
||||
// =============================================================
|
||||
|
||||
public override object Extension(string pFunct, params object[] pParams)
|
||||
{
|
||||
return base.Extension(pFunct, pParams);
|
||||
}
|
||||
#endregion // Extensions
|
||||
|
||||
#region Taints
|
||||
// The simulation execution order is:
|
||||
// Simulate()
|
||||
|
|
|
@ -418,7 +418,8 @@ namespace OpenSim.Region.Physics.Manager
|
|||
// Extendable interface for new, physics engine specific operations
|
||||
public virtual object Extension(string pFunct, params object[] pParams)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// A NOP of the physics engine does not implement this feature
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -393,7 +393,8 @@ namespace OpenSim.Region.Physics.Manager
|
|||
// Extendable interface for new, physics engine specific operations
|
||||
public virtual object Extension(string pFunct, params object[] pParams)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// A NOP if the extension thing is not implemented by the physics engine
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
|
||||
object[] convertedParms = new object[parms.Length];
|
||||
for (int i = 0; i < parms.Length; i++)
|
||||
convertedParms[i] = ConvertFromLSL(parms[i],signature[i], fname);
|
||||
convertedParms[i] = ConvertFromLSL(parms[i], signature[i], fname);
|
||||
|
||||
// now call the function, the contract with the function is that it will always return
|
||||
// non-null but don't trust it completely
|
||||
|
@ -448,7 +448,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
}
|
||||
}
|
||||
|
||||
MODError(String.Format("{1}: parameter type mismatch; expecting {0}",type.Name, fname));
|
||||
MODError(String.Format("{0}: parameter type mismatch; expecting {1}, type(parm)={2}", fname, type.Name, lslparm.GetType()));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -937,7 +937,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
|
|||
{
|
||||
string retval = null;
|
||||
if (value is int)
|
||||
retval = ((int)value).ToString();
|
||||
retval = String.Format("new LSL_Types.LSLInteger({0})",((int)value).ToString());
|
||||
else if (value is float)
|
||||
retval = String.Format("new LSL_Types.LSLFloat({0})",((float)value).ToString());
|
||||
else if (value is string)
|
||||
|
|
|
@ -79,7 +79,11 @@ namespace OpenSim.Services.Connectors.SimianGrid
|
|||
{
|
||||
m_simianURL = m_config.GetString("SimianServiceURL");
|
||||
if (String.IsNullOrEmpty(m_simianURL))
|
||||
m_log.ErrorFormat("[SimianGrid] service URL is not defined");
|
||||
{
|
||||
//m_log.DebugFormat("[SimianGrid] service URL is not defined");
|
||||
m_enabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -74,11 +74,15 @@ namespace OpenSim.Services.Connectors.SimianGrid
|
|||
{
|
||||
m_simianURL = m_config.GetString("SimianServiceURL");
|
||||
if (String.IsNullOrEmpty(m_simianURL))
|
||||
m_log.ErrorFormat("[SimianGrid] service URL is not defined");
|
||||
{
|
||||
// m_log.DebugFormat("[SimianGrid] service URL is not defined");
|
||||
m_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
InitialiseSimCap();
|
||||
SimulatorCapability = SimulatorCapability.Trim();
|
||||
m_log.WarnFormat("[SimianExternalCaps] using {0} as simulator capability",SimulatorCapability);
|
||||
m_log.InfoFormat("[SimianExternalCaps] using {0} as simulator capability",SimulatorCapability);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -68,8 +68,18 @@ namespace OpenSim.Tests.Clients.AssetsClient
|
|||
m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} max threads = {1} - {2}", serverURI, max1, max2);
|
||||
ThreadPool.GetMinThreads(out max1, out max2);
|
||||
m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} min threads = {1} - {2}", serverURI, max1, max2);
|
||||
ThreadPool.SetMinThreads(1, 1);
|
||||
ThreadPool.SetMaxThreads(10, 3);
|
||||
|
||||
if (!ThreadPool.SetMinThreads(1, 1))
|
||||
m_log.WarnFormat("[ASSET CLIENT]: Failed to set min threads");
|
||||
|
||||
if (!ThreadPool.SetMaxThreads(10, 3))
|
||||
m_log.WarnFormat("[ASSET CLIENT]: Failed to set max threads");
|
||||
|
||||
ThreadPool.GetMaxThreads(out max1, out max2);
|
||||
m_log.InfoFormat("[ASSET CLIENT]: Post set max threads = {1} - {2}", serverURI, max1, max2);
|
||||
ThreadPool.GetMinThreads(out max1, out max2);
|
||||
m_log.InfoFormat("[ASSET CLIENT]: Post set min threads = {1} - {2}", serverURI, max1, max2);
|
||||
|
||||
ServicePointManager.DefaultConnectionLimit = 12;
|
||||
|
||||
AssetServicesConnector m_Connector = new AssetServicesConnector(serverURI);
|
||||
|
|
|
@ -239,7 +239,6 @@ namespace OpenSim.Tools.Configger
|
|||
config.Set("physics", "OpenDynamicsEngine");
|
||||
config.Set("meshing", "Meshmerizer");
|
||||
config.Set("physical_prim", true);
|
||||
config.Set("see_into_this_sim_from_neighbor", true);
|
||||
config.Set("serverside_object_permissions", true);
|
||||
config.Set("storage_plugin", "OpenSim.Data.SQLite.dll");
|
||||
config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3");
|
||||
|
|
|
@ -11,22 +11,56 @@
|
|||
</appSettings>
|
||||
<log4net>
|
||||
<appender name="Console" type="OpenSim.Framework.Console.OpenSimAppender, OpenSim.Framework.Console">
|
||||
<filter type="log4net.Filter.LoggerMatchFilter">
|
||||
<loggerToMatch value="special"/>
|
||||
<acceptOnMatch value="false"/>
|
||||
</filter>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date{HH:mm:ss} - %message%newline" />
|
||||
<conversionPattern value="%date{HH:mm:ss} - %message" />
|
||||
<!-- console log with milliseconds. Useful for debugging -->
|
||||
<!-- <conversionPattern value="%date{HH:mm:ss.fff} - %message" /> -->
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
|
||||
<file value="OpenSim.32BitLaunch.log" />
|
||||
<appendToFile value="true" />
|
||||
<filter type="log4net.Filter.LoggerMatchFilter">
|
||||
<loggerToMatch value="special"/>
|
||||
<acceptOnMatch value="false"/>
|
||||
</filter>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date %-5level - %logger %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="StatsLogFileAppender" type="log4net.Appender.FileAppender">
|
||||
<file value="OpenSimStats.log"/>
|
||||
<appendToFile value="true" />
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date - %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="Console" />
|
||||
<appender-ref ref="LogFileAppender" />
|
||||
</root>
|
||||
|
||||
<!-- Independently control logging level for XEngine -->
|
||||
<logger name="OpenSim.Region.ScriptEngine.XEngine">
|
||||
<level value="INFO"/>
|
||||
</logger>
|
||||
|
||||
<!-- Independently control logging level for per region module loading -->
|
||||
<logger name="OpenSim.ApplicationPlugins.RegionModulesController.RegionModulesControllerPlugin">
|
||||
<level value="INFO"/>
|
||||
</logger>
|
||||
|
||||
<!-- used for stats recording -->
|
||||
<logger name="special.StatsLogger">
|
||||
<appender-ref ref="StatsLogFileAppender"/>
|
||||
</logger>
|
||||
</log4net>
|
||||
</configuration>
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
</appSettings>
|
||||
<log4net>
|
||||
<appender name="Console" type="OpenSim.Framework.Console.OpenSimAppender, OpenSim.Framework.Console">
|
||||
<filter type="log4net.Filter.LoggerMatchFilter">
|
||||
<loggerToMatch value="special"/>
|
||||
<acceptOnMatch value="false"/>
|
||||
</filter>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date{HH:mm:ss} - %message" />
|
||||
<!-- console log with milliseconds. Useful for debugging -->
|
||||
|
@ -21,11 +25,23 @@
|
|||
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
|
||||
<file value="OpenSim.log" />
|
||||
<appendToFile value="true" />
|
||||
<filter type="log4net.Filter.LoggerMatchFilter">
|
||||
<loggerToMatch value="special"/>
|
||||
<acceptOnMatch value="false"/>
|
||||
</filter>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date %-5level - %logger %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="StatsLogFileAppender" type="log4net.Appender.FileAppender">
|
||||
<file value="OpenSimStats.log"/>
|
||||
<appendToFile value="true" />
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date - %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="Console" />
|
||||
|
@ -42,5 +58,10 @@
|
|||
<level value="INFO"/>
|
||||
</logger>
|
||||
|
||||
<!-- used for stats recording -->
|
||||
<logger name="special.StatsLogger">
|
||||
<appender-ref ref="StatsLogFileAppender"/>
|
||||
</logger>
|
||||
|
||||
</log4net>
|
||||
</configuration>
|
||||
|
|
|
@ -180,10 +180,6 @@
|
|||
;; if the first change occurred this number of seconds ago.
|
||||
; MaximumTimeBeforePersistenceConsidered = 600
|
||||
|
||||
;# {see_into_this_sim_from_neighbor} {} {Should avatars in neighbor sims see objects in this sim?} {true false} true
|
||||
;; Should avatars in neighbor sims see objects in this sim?
|
||||
; see_into_this_sim_from_neighbor = true
|
||||
|
||||
;# {physical_prim} {} {Allow prims to be physical?} {true false} true
|
||||
;; if you would like to allow prims to be physical and move by physics
|
||||
;; with the physical checkbox in the client set this to true.
|
||||
|
|
|
@ -710,8 +710,8 @@
|
|||
Enabled = true
|
||||
|
||||
; Controls the number of milliseconds that are slept per 100 prims rezzed in attachments
|
||||
; Experimental setting to control CPU spiking when avatars with many attachments login
|
||||
; or when multiple avatars with medium level attachments login simultaneously.
|
||||
; Experimental setting to control CPU spiking when avatars with many attachments login/change outfit
|
||||
; or when multiple avatars with medium level attachments login/change outfit simultaneously.
|
||||
; If 0 then no throttling is performed.
|
||||
ThrottlePer100PrimsRezzed = 0;
|
||||
|
||||
|
|
|
@ -11,22 +11,44 @@
|
|||
</appSettings>
|
||||
<log4net>
|
||||
<appender name="Console" type="OpenSim.Framework.Console.OpenSimAppender, OpenSim.Framework.Console">
|
||||
<filter type="log4net.Filter.LoggerMatchFilter">
|
||||
<loggerToMatch value="special"/>
|
||||
<acceptOnMatch value="false"/>
|
||||
</filter>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date{HH:mm:ss} - %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
|
||||
<file value="Robust.32BitLaunch.log" />
|
||||
<appendToFile value="true" />
|
||||
<filter type="log4net.Filter.LoggerMatchFilter">
|
||||
<loggerToMatch value="special"/>
|
||||
<acceptOnMatch value="false"/>
|
||||
</filter>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date %-5level - %logger %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="StatsLogFileAppender" type="log4net.Appender.FileAppender">
|
||||
<file value="RobustStats.log"/>
|
||||
<appendToFile value="true" />
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date - %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="Console" />
|
||||
<appender-ref ref="LogFileAppender" />
|
||||
</root>
|
||||
|
||||
<!-- used for stats recording -->
|
||||
<logger name="special.StatsLogger">
|
||||
<appender-ref ref="StatsLogFileAppender"/>
|
||||
</logger>
|
||||
</log4net>
|
||||
</configuration>
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
</appSettings>
|
||||
<log4net>
|
||||
<appender name="Console" type="OpenSim.Framework.Console.OpenSimAppender, OpenSim.Framework.Console">
|
||||
<filter type="log4net.Filter.LoggerMatchFilter">
|
||||
<loggerToMatch value="special"/>
|
||||
<acceptOnMatch value="false"/>
|
||||
</filter>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date{HH:mm:ss} - %message%newline" />
|
||||
</layout>
|
||||
|
@ -19,15 +23,32 @@
|
|||
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
|
||||
<file value="Robust.log" />
|
||||
<appendToFile value="true" />
|
||||
<filter type="log4net.Filter.LoggerMatchFilter">
|
||||
<loggerToMatch value="special"/>
|
||||
<acceptOnMatch value="false"/>
|
||||
</filter>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date %-5level - %logger %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="StatsLogFileAppender" type="log4net.Appender.FileAppender">
|
||||
<file value="RobustStats.log"/>
|
||||
<appendToFile value="true" />
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date - %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="Console" />
|
||||
<appender-ref ref="LogFileAppender" />
|
||||
</root>
|
||||
|
||||
<!-- used for stats recording -->
|
||||
<logger name="special.StatsLogger">
|
||||
<appender-ref ref="StatsLogFileAppender"/>
|
||||
</logger>
|
||||
</log4net>
|
||||
</configuration>
|
||||
|
|
|
@ -30,6 +30,17 @@
|
|||
SimulationServiceInConnector = true
|
||||
LibraryModule = true
|
||||
|
||||
[SimulationService]
|
||||
; This is the protocol version which the simulator advertises to the source destination when acting as a target destination for a teleport
|
||||
; It is used to control the teleport handoff process.
|
||||
; Valid values are
|
||||
; "SIMULATION/0.2"
|
||||
; - this is the default. A source simulator which only implements "SIMULATION/0.1" can still teleport with that protocol
|
||||
; - this protocol is more efficient than "SIMULATION/0.1"
|
||||
; "SIMULATION/0.1"
|
||||
; - this is an older teleport protocol used in OpenSimulator 0.7.5 and before.
|
||||
ConnectorProtocolVersion = "SIMULATION/0.2"
|
||||
|
||||
[SimulationDataStore]
|
||||
LocalServiceModule = "OpenSim.Services.Connectors.dll:SimulationDataService"
|
||||
|
||||
|
|
|
@ -26,6 +26,17 @@
|
|||
GridInfoServiceInConnector = true
|
||||
MapImageServiceInConnector = true
|
||||
|
||||
[SimulationService]
|
||||
; This is the protocol version which the simulator advertises to the source destination when acting as a target destination for a teleport
|
||||
; It is used to control the teleport handoff process.
|
||||
; Valid values are
|
||||
; "SIMULATION/0.2"
|
||||
; - this is the default. A source simulator which only implements "SIMULATION/0.1" can still teleport with that protocol
|
||||
; - this protocol is more efficient than "SIMULATION/0.1"
|
||||
; "SIMULATION/0.1"
|
||||
; - this is an older teleport protocol used in OpenSimulator 0.7.5 and before.
|
||||
ConnectorProtocolVersion = "SIMULATION/0.2"
|
||||
|
||||
[SimulationDataStore]
|
||||
LocalServiceModule = "OpenSim.Services.Connectors.dll:SimulationDataService"
|
||||
|
||||
|
|
Loading…
Reference in New Issue