Merge branch 'master' of /home/opensim/var/repo/opensim

Conflicts:
	bin/OpenSim.ini.example
	bin/OpenSimDefaults.ini
	bin/openjpeg-dotnet-x86_64.dll
	bin/openjpeg-dotnet.dll
integration
BlueWall 2012-10-01 10:55:03 -04:00
commit 0938ea2e1e
141 changed files with 16587 additions and 2247 deletions

View File

@ -209,3 +209,4 @@ In addition, we would like to thank:
* The NANT Developers * The NANT Developers
* Microsoft (.NET, MSSQL-Adapters) * Microsoft (.NET, MSSQL-Adapters)
*x *x

View File

@ -572,7 +572,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
region.ExternalHostName = (string) requestData["external_address"]; region.ExternalHostName = (string) requestData["external_address"];
bool persist = Convert.ToBoolean((string) requestData["persist"]); bool persist = Convert.ToBoolean(requestData["persist"]);
if (persist) if (persist)
{ {
// default place for region configuration files is in the // default place for region configuration files is in the
@ -728,7 +728,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
responseData["success"] = true; responseData["success"] = true;
responseData["region_name"] = region.RegionName; responseData["region_name"] = region.RegionName;
responseData["region_id"] = region.RegionID.ToString(); responseData["region_id"] = region.RegionID.ToString();
responseData["region_uuid"] = region.RegionID.ToString(); //Deprecate July 2012
m_log.Info("[RADMIN]: CreateRegion: request complete"); m_log.Info("[RADMIN]: CreateRegion: request complete");
} }
@ -982,8 +981,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
string lastName = (string) requestData["user_lastname"]; string lastName = (string) requestData["user_lastname"];
string password = (string) requestData["user_password"]; string password = (string) requestData["user_password"];
uint regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]); uint regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
uint regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]); uint regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
string email = ""; // empty string for email string email = ""; // empty string for email
if (requestData.Contains("user_email")) if (requestData.Contains("user_email"))
@ -1180,9 +1179,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController
if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"]; if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"];
if (requestData.ContainsKey("start_region_x")) if (requestData.ContainsKey("start_region_x"))
regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]); regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
if (requestData.ContainsKey("start_region_y")) if (requestData.ContainsKey("start_region_y"))
regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]); regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
// if (requestData.ContainsKey("start_lookat_x")) // if (requestData.ContainsKey("start_lookat_x"))
// ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]); // ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
@ -1881,29 +1880,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
{ {
return; return;
} }
#region Deprecate July 2012
//region_ID, regionid, region_uuid will be deprecated in July 2012!!!!!!
else if (requestData.ContainsKey("regionid") &&
!String.IsNullOrEmpty((string)requestData["regionid"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter regionid will be deprecated as of July 2012. Use region_id instead");
}
else if (requestData.ContainsKey("region_ID") &&
!String.IsNullOrEmpty((string)requestData["region_ID"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter region_ID will be deprecated as of July 2012. Use region_id instead");
}
else if (requestData.ContainsKey("regionID") &&
!String.IsNullOrEmpty((string)requestData["regionID"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter regionID will be deprecated as of July 2012. Use region_id instead");
}
else if (requestData.ContainsKey("region_uuid") &&
!String.IsNullOrEmpty((string)requestData["region_uuid"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter region_uuid will be deprecated as of July 2012. Use region_id instead");
}
#endregion
else else
{ {
responseData["accepted"] = false; responseData["accepted"] = false;
@ -1925,56 +1901,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
throw new Exception(String.Format("Region ID {0} not found", regionID)); throw new Exception(String.Format("Region ID {0} not found", regionID));
} }
} }
#region Deprecate July 2012
else if (requestData.ContainsKey("regionid") &&
!String.IsNullOrEmpty((string)requestData["regionid"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter regionid will be deprecated as of July 2012. Use region_id instead");
UUID regionID = (UUID)(string)requestData["regionid"];
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
{
responseData["error"] = String.Format("Region ID {0} not found", regionID);
throw new Exception(String.Format("Region ID {0} not found", regionID));
}
}
else if (requestData.ContainsKey("region_ID") &&
!String.IsNullOrEmpty((string)requestData["region_ID"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter region_ID will be deprecated as of July 2012. Use region_id instead");
UUID regionID = (UUID)(string)requestData["region_ID"];
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
{
responseData["error"] = String.Format("Region ID {0} not found", regionID);
throw new Exception(String.Format("Region ID {0} not found", regionID));
}
}
else if (requestData.ContainsKey("regionID") &&
!String.IsNullOrEmpty((string)requestData["regionID"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter regionID will be deprecated as of July 2012. Use region_id instead");
UUID regionID = (UUID)(string)requestData["regionID"];
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
{
responseData["error"] = String.Format("Region ID {0} not found", regionID);
throw new Exception(String.Format("Region ID {0} not found", regionID));
}
}
else if (requestData.ContainsKey("region_uuid") &&
!String.IsNullOrEmpty((string)requestData["region_uuid"]))
{
m_log.WarnFormat("[RADMIN]: Use of parameter region_uuid will be deprecated as of July 2012. Use region_id instead");
UUID regionID = (UUID)(string)requestData["region_uuid"];
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
{
responseData["error"] = String.Format("Region ID {0} not found", regionID);
throw new Exception(String.Format("Region ID {0} not found", regionID));
}
}
#endregion
else if (requestData.ContainsKey("region_name") && else if (requestData.ContainsKey("region_name") &&
!String.IsNullOrEmpty((string)requestData["region_name"])) !String.IsNullOrEmpty((string)requestData["region_name"]))
{ {

View File

@ -312,14 +312,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
// Now that everything is setup we can proceed to // Now that everything is setup we can proceed to
// add THIS agent to the HTTP server's handler list // add THIS agent to the HTTP server's handler list
if (!AddAgentHandler(Rest.Name,this)) // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
{ // have to be handled through the AddHttpHandler interface.
Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId); // if (!AddAgentHandler(Rest.Name,this))
foreach (IRest handler in handlers) // {
{ // Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
handler.Close(); // foreach (IRest handler in handlers)
} // {
} // handler.Close();
// }
// }
} }
catch (Exception e) catch (Exception e)
@ -342,11 +344,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
{ {
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId); Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
try // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
{ // have to be handled through the AddHttpHandler interface.
RemoveAgentHandler(Rest.Name, this); // try
} // {
catch (KeyNotFoundException){} // RemoveAgentHandler(Rest.Name, this);
// }
// catch (KeyNotFoundException){}
foreach (IRest handler in handlers) foreach (IRest handler in handlers)
{ {

View File

@ -297,7 +297,9 @@ namespace OpenSim.ApplicationPlugins.Rest
{ {
if (!IsEnabled) return false; if (!IsEnabled) return false;
_agents.Add(agentName, handler); _agents.Add(agentName, handler);
return _httpd.AddAgentHandler(agentName, handler); // return _httpd.AddAgentHandler(agentName, handler);
return false;
} }
/// <summary> /// <summary>
@ -316,7 +318,7 @@ namespace OpenSim.ApplicationPlugins.Rest
if (_agents[agentName] == handler) if (_agents[agentName] == handler)
{ {
_agents.Remove(agentName); _agents.Remove(agentName);
return _httpd.RemoveAgentHandler(agentName, handler); // return _httpd.RemoveAgentHandler(agentName, handler);
} }
return false; return false;
} }
@ -358,10 +360,10 @@ namespace OpenSim.ApplicationPlugins.Rest
_httpd.RemoveStreamHandler(h.HttpMethod, h.Path); _httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
} }
_handlers = null; _handlers = null;
foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents) // foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
{ // {
_httpd.RemoveAgentHandler(h.Key, h.Value); // _httpd.RemoveAgentHandler(h.Key, h.Value);
} // }
_agents = null; _agents = null;
} }

View File

@ -17,3 +17,8 @@ CREATE TABLE `GridUser` (
) ENGINE=InnoDB; ) ENGINE=InnoDB;
COMMIT; COMMIT;
:VERSION 2 # --------------------------
BEGIN;
COMMIT;

View File

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using log4net;
using OpenMetaverse;
namespace OpenSim.Framework
{
public class AssetPermissions
{
private static readonly ILog m_log =
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
private bool[] m_DisallowExport, m_DisallowImport;
private string[] m_AssetTypeNames;
public AssetPermissions(IConfig config)
{
Type enumType = typeof(AssetType);
m_AssetTypeNames = Enum.GetNames(enumType);
for (int i = 0; i < m_AssetTypeNames.Length; i++)
m_AssetTypeNames[i] = m_AssetTypeNames[i].ToLower();
int n = Enum.GetValues(enumType).Length;
m_DisallowExport = new bool[n];
m_DisallowImport = new bool[n];
LoadPermsFromConfig(config, "DisallowExport", m_DisallowExport);
LoadPermsFromConfig(config, "DisallowImport", m_DisallowImport);
}
private void LoadPermsFromConfig(IConfig assetConfig, string variable, bool[] bitArray)
{
if (assetConfig == null)
return;
string perms = assetConfig.GetString(variable, String.Empty);
string[] parts = perms.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in parts)
{
int index = Array.IndexOf(m_AssetTypeNames, s.Trim().ToLower());
if (index >= 0)
bitArray[index] = true;
else
m_log.WarnFormat("[Asset Permissions]: Invalid AssetType {0}", s);
}
}
public bool AllowedExport(sbyte type)
{
string assetTypeName = ((AssetType)type).ToString();
int index = Array.IndexOf(m_AssetTypeNames, assetTypeName.ToLower());
if (index >= 0 && m_DisallowExport[index])
{
m_log.DebugFormat("[Asset Permissions]: Export denied: configuration does not allow export of AssetType {0}", assetTypeName);
return false;
}
return true;
}
public bool AllowedImport(sbyte type)
{
string assetTypeName = ((AssetType)type).ToString();
int index = Array.IndexOf(m_AssetTypeNames, assetTypeName.ToLower());
if (index >= 0 && m_DisallowImport[index])
{
m_log.DebugFormat("[Asset Permissions]: Import denied: configuration does not allow import of AssetType {0}", assetTypeName);
return false;
}
return true;
}
}
}

View File

@ -54,8 +54,23 @@ namespace OpenSim.Framework.Servers.HttpServer
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
/// <summary>
/// Gets or sets the debug level.
/// </summary>
/// <value>
/// See MainServer.DebugLevel.
/// </value>
public int DebugLevel { get; set; } public int DebugLevel { get; set; }
/// <summary>
/// Request number for diagnostic purposes.
/// </summary>
/// <remarks>
/// This is an internal number. In some debug situations an external number may also be supplied in the
/// opensim-request-id header but we are not currently logging this.
/// </remarks>
public int RequestNumber { get; private set; }
private volatile int NotSocketErrors = 0; private volatile int NotSocketErrors = 0;
public volatile bool HTTPDRunning = false; public volatile bool HTTPDRunning = false;
@ -67,7 +82,7 @@ namespace OpenSim.Framework.Servers.HttpServer
protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>(); protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>();
protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>(); protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>();
protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>(); // protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
new Dictionary<string, PollServiceEventArgs>(); new Dictionary<string, PollServiceEventArgs>();
@ -245,29 +260,29 @@ namespace OpenSim.Framework.Servers.HttpServer
return new List<string>(m_pollHandlers.Keys); return new List<string>(m_pollHandlers.Keys);
} }
// Note that the agent string is provided simply to differentiate // // Note that the agent string is provided simply to differentiate
// the handlers - it is NOT required to be an actual agent header // // the handlers - it is NOT required to be an actual agent header
// value. // // value.
public bool AddAgentHandler(string agent, IHttpAgentHandler handler) // public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
{ // {
lock (m_agentHandlers) // lock (m_agentHandlers)
{ // {
if (!m_agentHandlers.ContainsKey(agent)) // if (!m_agentHandlers.ContainsKey(agent))
{ // {
m_agentHandlers.Add(agent, handler); // m_agentHandlers.Add(agent, handler);
return true; // return true;
} // }
} // }
//
//must already have a handler for that path so return false // //must already have a handler for that path so return false
return false; // return false;
} // }
//
public List<string> GetAgentHandlerKeys() // public List<string> GetAgentHandlerKeys()
{ // {
lock (m_agentHandlers) // lock (m_agentHandlers)
return new List<string>(m_agentHandlers.Keys); // return new List<string>(m_agentHandlers.Keys);
} // }
public bool AddLLSDHandler(string path, LLSDMethod handler) public bool AddLLSDHandler(string path, LLSDMethod handler)
{ {
@ -296,6 +311,8 @@ namespace OpenSim.Framework.Servers.HttpServer
private void OnRequest(object source, RequestEventArgs args) private void OnRequest(object source, RequestEventArgs args)
{ {
RequestNumber++;
try try
{ {
IHttpClientContext context = (IHttpClientContext)source; IHttpClientContext context = (IHttpClientContext)source;
@ -405,7 +422,6 @@ namespace OpenSim.Framework.Servers.HttpServer
string requestMethod = request.HttpMethod; string requestMethod = request.HttpMethod;
string uriString = request.RawUrl; string uriString = request.RawUrl;
// string reqnum = "unknown";
int requestStartTick = Environment.TickCount; int requestStartTick = Environment.TickCount;
// Will be adjusted later on. // Will be adjusted later on.
@ -422,22 +438,22 @@ namespace OpenSim.Framework.Servers.HttpServer
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
// This is the REST agent interface. We require an agent to properly identify // // This is the REST agent interface. We require an agent to properly identify
// itself. If the REST handler recognizes the prefix it will attempt to // // itself. If the REST handler recognizes the prefix it will attempt to
// satisfy the request. If it is not recognizable, and no damage has occurred // // satisfy the request. If it is not recognizable, and no damage has occurred
// the request can be passed through to the other handlers. This is a low // // the request can be passed through to the other handlers. This is a low
// probability event; if a request is matched it is normally expected to be // // probability event; if a request is matched it is normally expected to be
// handled // // handled
IHttpAgentHandler agentHandler; // IHttpAgentHandler agentHandler;
//
if (TryGetAgentHandler(request, response, out agentHandler)) // if (TryGetAgentHandler(request, response, out agentHandler))
{ // {
if (HandleAgentRequest(agentHandler, request, response)) // if (HandleAgentRequest(agentHandler, request, response))
{ // {
requestEndTick = Environment.TickCount; // requestEndTick = Environment.TickCount;
return; // return;
} // }
} // }
//response.KeepAlive = true; //response.KeepAlive = true;
response.SendChunked = false; response.SendChunked = false;
@ -529,8 +545,8 @@ namespace OpenSim.Framework.Servers.HttpServer
if (DebugLevel >= 3) if (DebugLevel >= 3)
m_log.DebugFormat( m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery); RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
buffer = HandleHTTPRequest(request, response); buffer = HandleHTTPRequest(request, response);
break; break;
@ -541,8 +557,8 @@ namespace OpenSim.Framework.Servers.HttpServer
if (DebugLevel >= 3) if (DebugLevel >= 3)
m_log.DebugFormat( m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery); RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
buffer = HandleLLSDRequests(request, response); buffer = HandleLLSDRequests(request, response);
break; break;
@ -620,11 +636,11 @@ namespace OpenSim.Framework.Servers.HttpServer
} }
catch (IOException e) catch (IOException e)
{ {
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e); m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
} }
catch (Exception e) catch (Exception e)
{ {
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e); m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
SendHTML500(response); SendHTML500(response);
} }
finally finally
@ -632,15 +648,24 @@ namespace OpenSim.Framework.Servers.HttpServer
// Every month or so this will wrap and give bad numbers, not really a problem // Every month or so this will wrap and give bad numbers, not really a problem
// since its just for reporting // since its just for reporting
int tickdiff = requestEndTick - requestStartTick; int tickdiff = requestEndTick - requestStartTick;
if (tickdiff > 3000) if (tickdiff > 3000 && requestHandler.Name != "GetTexture")
{ {
m_log.InfoFormat( m_log.InfoFormat(
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms", "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
RequestNumber,
requestMethod, requestMethod,
uriString, uriString,
requestHandler != null ? requestHandler.Name : "", requestHandler != null ? requestHandler.Name : "",
requestHandler != null ? requestHandler.Description : "", requestHandler != null ? requestHandler.Description : "",
request.RemoteIPEndPoint.ToString(), request.RemoteIPEndPoint,
tickdiff);
}
else if (DebugLevel >= 4)
{
m_log.DebugFormat(
"[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms",
RequestNumber,
Port,
tickdiff); tickdiff);
} }
} }
@ -649,30 +674,45 @@ namespace OpenSim.Framework.Servers.HttpServer
private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler) private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}", "[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description); RequestNumber,
Port,
request.HttpMethod,
request.Url.PathAndQuery,
requestHandler.Name,
requestHandler.Description,
request.RemoteIPEndPoint);
if (DebugLevel >= 4) if (DebugLevel >= 5)
LogIncomingInDetail(request); LogIncomingInDetail(request);
} }
private void LogIncomingToContentTypeHandler(OSHttpRequest request) private void LogIncomingToContentTypeHandler(OSHttpRequest request)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
request.ContentType, request.HttpMethod, request.Url.PathAndQuery); RequestNumber,
Port,
request.ContentType,
request.HttpMethod,
request.Url.PathAndQuery,
request.RemoteIPEndPoint);
if (DebugLevel >= 4) if (DebugLevel >= 5)
LogIncomingInDetail(request); LogIncomingInDetail(request);
} }
private void LogIncomingToXmlRpcHandler(OSHttpRequest request) private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}", "[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
request.HttpMethod, request.Url.PathAndQuery); RequestNumber,
Port,
request.HttpMethod,
request.Url.PathAndQuery,
request.RemoteIPEndPoint);
if (DebugLevel >= 4) if (DebugLevel >= 5)
LogIncomingInDetail(request); LogIncomingInDetail(request);
} }
@ -682,19 +722,19 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
string output; string output;
if (DebugLevel == 4) if (DebugLevel == 5)
{ {
const int sampleLength = 80; const int sampleLength = 80;
char[] sampleChars = new char[sampleLength]; char[] sampleChars = new char[sampleLength];
reader.Read(sampleChars, 0, sampleLength); reader.Read(sampleChars, 0, sampleLength);
output = string.Format("[BASE HTTP SERVER]: {0}...", new string(sampleChars).Replace("\n", @"\n")); output = new string(sampleChars);
} }
else else
{ {
output = string.Format("[BASE HTTP SERVER]: {0}", reader.ReadToEnd()); output = reader.ReadToEnd();
} }
m_log.Debug(output); m_log.DebugFormat("[BASE HTTP SERVER]: {0}...", output.Replace("\n", @"\n"));
} }
} }
@ -790,24 +830,24 @@ namespace OpenSim.Framework.Servers.HttpServer
} }
} }
private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler) // private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
{ // {
agentHandler = null; // agentHandler = null;
//
lock (m_agentHandlers) // lock (m_agentHandlers)
{ // {
foreach (IHttpAgentHandler handler in m_agentHandlers.Values) // foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
{ // {
if (handler.Match(request, response)) // if (handler.Match(request, response))
{ // {
agentHandler = handler; // agentHandler = handler;
return true; // return true;
} // }
} // }
} // }
//
return false; // return false;
} // }
/// <summary> /// <summary>
/// Try all the registered xmlrpc handlers when an xmlrpc request is received. /// Try all the registered xmlrpc handlers when an xmlrpc request is received.
@ -1732,21 +1772,21 @@ namespace OpenSim.Framework.Servers.HttpServer
m_pollHandlers.Remove(path); m_pollHandlers.Remove(path);
} }
public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) // public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
{ // {
lock (m_agentHandlers) // lock (m_agentHandlers)
{ // {
IHttpAgentHandler foundHandler; // IHttpAgentHandler foundHandler;
//
if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler) // if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
{ // {
m_agentHandlers.Remove(agent); // m_agentHandlers.Remove(agent);
return true; // return true;
} // }
} // }
//
return false; // return false;
} // }
public void RemoveXmlRPCHandler(string method) public void RemoveXmlRPCHandler(string method)
{ {

View File

@ -41,10 +41,10 @@ namespace OpenSim.Framework.Servers.HttpServer
uint Port { get; } uint Port { get; }
bool UseSSL { get; } bool UseSSL { get; }
// Note that the agent string is provided simply to differentiate // // Note that the agent string is provided simply to differentiate
// the handlers - it is NOT required to be an actual agent header // // the handlers - it is NOT required to be an actual agent header
// value. // // value.
bool AddAgentHandler(string agent, IHttpAgentHandler handler); // bool AddAgentHandler(string agent, IHttpAgentHandler handler);
/// <summary> /// <summary>
/// Add a handler for an HTTP request. /// Add a handler for an HTTP request.
@ -106,13 +106,13 @@ namespace OpenSim.Framework.Servers.HttpServer
bool SetDefaultLLSDHandler(DefaultLLSDMethod handler); bool SetDefaultLLSDHandler(DefaultLLSDMethod handler);
/// <summary> // /// <summary>
/// Remove the agent if it is registered. // /// Remove the agent if it is registered.
/// </summary> // /// </summary>
/// <param name="agent"></param> // /// <param name="agent"></param>
/// <param name="handler"></param> // /// <param name="handler"></param>
/// <returns></returns> // /// <returns></returns>
bool RemoveAgentHandler(string agent, IHttpAgentHandler handler); // bool RemoveAgentHandler(string agent, IHttpAgentHandler handler);
/// <summary> /// <summary>
/// Remove an HTTP handler /// Remove an HTTP handler

View File

@ -48,9 +48,12 @@ namespace OpenSim.Framework.Servers
/// Control the printing of certain debug messages. /// Control the printing of certain debug messages.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// If DebugLevel >= 1, then short warnings are logged when receiving bad input data. /// If DebugLevel >= 1 then short warnings are logged when receiving bad input data.
/// If DebugLevel >= 2, then long warnings are logged when receiving bad input data. /// If DebugLevel >= 2 then long warnings are logged when receiving bad input data.
/// If DebugLevel >= 3, then short notices about all incoming non-poll HTTP requests are logged. /// If DebugLevel >= 3 then short notices about all incoming non-poll HTTP requests are logged.
/// If DebugLevel >= 4 then the time taken to fulfill the request is logged.
/// If DebugLevel >= 5 then the start of the body of incoming non-poll HTTP requests will be logged.
/// If DebugLevel >= 6 then the entire body of incoming non-poll HTTP requests will be logged.
/// </remarks> /// </remarks>
public static int DebugLevel public static int DebugLevel
{ {
@ -102,7 +105,6 @@ namespace OpenSim.Framework.Servers
get { return new Dictionary<uint, BaseHttpServer>(m_Servers); } get { return new Dictionary<uint, BaseHttpServer>(m_Servers); }
} }
public static void RegisterHttpConsoleCommands(ICommandConsole console) public static void RegisterHttpConsoleCommands(ICommandConsole console)
{ {
console.Commands.AddCommand( console.Commands.AddCommand(
@ -111,15 +113,20 @@ namespace OpenSim.Framework.Servers
"Show all registered http handlers", HandleShowHttpHandlersCommand); "Show all registered http handlers", HandleShowHttpHandlersCommand);
console.Commands.AddCommand( console.Commands.AddCommand(
"Debug", false, "debug http", "debug http [<level>]", "Debug", false, "debug http", "debug http <in|out|all> [<level>]",
"Turn on inbound non-poll http request debugging.", "Turn on http request logging.",
"If level <= 0, then no extra logging is done.\n" "If in or all and\n"
+ "If level >= 1, then short warnings are logged when receiving bad input data.\n" + " level <= 0 then no extra logging is done.\n"
+ "If level >= 2, then long warnings are logged when receiving bad input data.\n" + " level >= 1 then short warnings are logged when receiving bad input data.\n"
+ "If level >= 3, then short notices about all incoming non-poll HTTP requests are logged.\n" + " level >= 2 then long warnings are logged when receiving bad input data.\n"
+ "If level >= 4, then a sample from the beginning of the incoming data is logged.\n" + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
+ "If level >= 5, then the entire incoming data is logged.\n" + " level >= 4 then the time taken to fulfill the request is logged.\n"
+ "If no level is specified then the current level is returned.", + " level >= 5 then a sample from the beginning of the incoming data is logged.\n"
+ " level >= 6 then the entire incoming data is logged.\n"
+ " no level is specified then the current level is returned.\n\n"
+ "If out or all and\n"
+ " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
+ " level >= 4 then the time taken to fulfill the request is logged.\n",
HandleDebugHttpCommand); HandleDebugHttpCommand);
} }
@ -127,24 +134,74 @@ namespace OpenSim.Framework.Servers
/// Turn on some debugging values for OpenSim. /// Turn on some debugging values for OpenSim.
/// </summary> /// </summary>
/// <param name="args"></param> /// <param name="args"></param>
private static void HandleDebugHttpCommand(string module, string[] args) private static void HandleDebugHttpCommand(string module, string[] cmdparams)
{ {
if (args.Length == 3) if (cmdparams.Length < 3)
{ {
int newDebug; MainConsole.Instance.Output("Usage: debug http <in|out|all> 0..6");
if (int.TryParse(args[2], out newDebug)) return;
{
MainServer.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug);
} }
}
else if (args.Length == 2) bool inReqs = false;
bool outReqs = false;
bool allReqs = false;
string subCommand = cmdparams[2];
if (subCommand.ToLower() == "in")
{ {
MainConsole.Instance.OutputFormat("Current debug http level is {0}", MainServer.DebugLevel); inReqs = true;
}
else if (subCommand.ToLower() == "out")
{
outReqs = true;
}
else if (subCommand.ToLower() == "all")
{
allReqs = true;
} }
else else
{ {
MainConsole.Instance.Output("Usage: debug http 0..5"); MainConsole.Instance.Output("You must specify in, out or all");
return;
}
if (cmdparams.Length >= 4)
{
string rawNewDebug = cmdparams[3];
int newDebug;
if (!int.TryParse(rawNewDebug, out newDebug))
{
MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawNewDebug);
return;
}
if (newDebug < 0 || newDebug > 6)
{
MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0..6", newDebug);
return;
}
if (allReqs || inReqs)
{
MainServer.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("IN debug level set to {0}", newDebug);
}
if (allReqs || outReqs)
{
WebUtil.DebugLevel = newDebug;
MainConsole.Instance.OutputFormat("OUT debug level set to {0}", newDebug);
}
}
else
{
if (allReqs || inReqs)
MainConsole.Instance.OutputFormat("Current IN debug level is {0}", MainServer.DebugLevel);
if (allReqs || outReqs)
MainConsole.Instance.OutputFormat("Current OUT debug level is {0}", WebUtil.DebugLevel);
} }
} }
@ -174,9 +231,9 @@ namespace OpenSim.Framework.Servers
foreach (String s in httpServer.GetHTTPHandlerKeys()) foreach (String s in httpServer.GetHTTPHandlerKeys())
handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty)); handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
handlers.AppendFormat("* Agent:\n"); // handlers.AppendFormat("* Agent:\n");
foreach (String s in httpServer.GetAgentHandlerKeys()) // foreach (String s in httpServer.GetAgentHandlerKeys())
handlers.AppendFormat("\t{0}\n", s); // handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* LLSD:\n"); handlers.AppendFormat("* LLSD:\n");
foreach (String s in httpServer.GetLLSDHandlerKeys()) foreach (String s in httpServer.GetLLSDHandlerKeys())

View File

@ -53,10 +53,18 @@ namespace OpenSim.Framework
LogManager.GetLogger( LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType); MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Control the printing of certain debug messages.
/// </summary>
/// <remarks>
/// If DebugLevel >= 3 then short notices about outgoing HTTP requests are logged.
/// </remarks>
public static int DebugLevel { get; set; }
/// <summary> /// <summary>
/// Request number for diagnostic purposes. /// Request number for diagnostic purposes.
/// </summary> /// </summary>
public static int RequestNumber = 0; public static int RequestNumber { get; internal set; }
/// <summary> /// <summary>
/// this is the header field used to communicate the local request id /// this is the header field used to communicate the local request id
@ -146,7 +154,11 @@ namespace OpenSim.Framework
private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed)
{ {
int reqnum = RequestNumber++; int reqnum = RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})",
reqnum, method, url, timeout, compressed);
string errorMessage = "unknown error"; string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
@ -229,7 +241,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime) if (tickdiff > LongCallTime)
m_log.InfoFormat( m_log.InfoFormat(
"[OSD REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
method, method,
url, url,
@ -238,10 +250,14 @@ namespace OpenSim.Framework
strBuffer != null strBuffer != null
? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer)
: ""); : "");
else if (DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
} }
m_log.DebugFormat( m_log.DebugFormat(
"[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage); "[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage);
return ErrorResponseMap(errorMessage); return ErrorResponseMap(errorMessage);
} }
@ -317,7 +333,11 @@ namespace OpenSim.Framework
{ {
int reqnum = RequestNumber++; int reqnum = RequestNumber++;
string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
// m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method);
if (DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})",
reqnum, method, url, timeout);
string errorMessage = "unknown error"; string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
@ -380,7 +400,7 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > LongCallTime) if (tickdiff > LongCallTime)
m_log.InfoFormat( m_log.InfoFormat(
"[SERVICE FORM]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
method, method,
url, url,
@ -389,9 +409,13 @@ namespace OpenSim.Framework
queryString != null queryString != null
? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString
: ""); : "");
else if (DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
} }
m_log.WarnFormat("[SERVICE FORM]: <{0}> form request to {1} failed: {2}", reqnum, url, errorMessage); m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage);
return ErrorResponseMap(errorMessage); return ErrorResponseMap(errorMessage);
} }
@ -643,7 +667,6 @@ namespace OpenSim.Framework
/// <returns></returns> /// <returns></returns>
public static string[] GetPreferredImageTypes(string accept) public static string[] GetPreferredImageTypes(string accept)
{ {
if (accept == null || accept == string.Empty) if (accept == null || accept == string.Empty)
return new string[0]; return new string[0];
@ -693,18 +716,31 @@ namespace OpenSim.Framework
// //
public static void MakeRequest<TRequest, TResponse>(string verb, public static void MakeRequest<TRequest, TResponse>(string verb,
string requestUrl, TRequest obj, Action<TResponse> action) string requestUrl, TRequest obj, Action<TResponse> action)
{
MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, action, 0);
}
public static void MakeRequest<TRequest, TResponse>(string verb,
string requestUrl, TRequest obj, Action<TResponse> action,
int maxConnections)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
int tickdata = 0; int tickdata = 0;
// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl);
Type type = typeof(TRequest); Type type = typeof(TRequest);
WebRequest request = WebRequest.Create(requestUrl); WebRequest request = WebRequest.Create(requestUrl);
HttpWebRequest ht = (HttpWebRequest)request;
if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
ht.ServicePoint.ConnectionLimit = maxConnections;
WebResponse response = null; WebResponse response = null;
TResponse deserial = default(TResponse); TResponse deserial = default(TResponse);
XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
@ -854,7 +890,7 @@ namespace OpenSim.Framework
} }
m_log.InfoFormat( m_log.InfoFormat(
"[ASYNC REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
verb, verb,
requestUrl, requestUrl,
@ -862,6 +898,12 @@ namespace OpenSim.Framework
tickdata, tickdata,
originalRequest); originalRequest);
} }
else if (WebUtil.DebugLevel >= 4)
{
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
}
} }
} }
@ -882,7 +924,11 @@ namespace OpenSim.Framework
public static string MakeRequest(string verb, string requestUrl, string obj) public static string MakeRequest(string verb, string requestUrl, string obj)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
int tickdata = 0; int tickdata = 0;
@ -967,13 +1013,17 @@ namespace OpenSim.Framework
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime) if (tickdiff > WebUtil.LongCallTime)
m_log.InfoFormat( m_log.InfoFormat(
"[FORMS]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
verb, verb,
requestUrl, requestUrl,
tickdiff, tickdiff,
tickdata, tickdata,
obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
else if (WebUtil.DebugLevel >= 4)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
return respstring; return respstring;
} }
@ -996,9 +1046,23 @@ namespace OpenSim.Framework
/// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting
/// the request. You'll want to make sure you deal with this as they're not uncommon</exception> /// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj) public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
{
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0);
}
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout)
{
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0);
}
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount(); int tickstart = Util.EnvironmentTickCount();
int tickdata = 0; int tickdata = 0;
@ -1007,6 +1071,10 @@ namespace OpenSim.Framework
TResponse deserial = default(TResponse); TResponse deserial = default(TResponse);
WebRequest request = WebRequest.Create(requestUrl); WebRequest request = WebRequest.Create(requestUrl);
HttpWebRequest ht = (HttpWebRequest)request;
if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
ht.ServicePoint.ConnectionLimit = maxConnections;
request.Method = verb; request.Method = verb;
MemoryStream buffer = null; MemoryStream buffer = null;
@ -1111,7 +1179,7 @@ namespace OpenSim.Framework
} }
m_log.InfoFormat( m_log.InfoFormat(
"[SynchronousRestObjectRequester]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", "[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
reqnum, reqnum,
verb, verb,
requestUrl, requestUrl,
@ -1119,6 +1187,12 @@ namespace OpenSim.Framework
tickdata, tickdata,
originalRequest); originalRequest);
} }
else if (WebUtil.DebugLevel >= 4)
{
m_log.DebugFormat(
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
reqnum, tickdiff, tickdata);
}
return deserial; return deserial;
} }

View File

@ -27,6 +27,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Net;
using System.Reflection; using System.Reflection;
using log4net; using log4net;
using log4net.Config; using log4net.Config;
@ -73,6 +74,7 @@ namespace OpenSim
AppDomain.CurrentDomain.UnhandledException += AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
ServicePointManager.DefaultConnectionLimit = 12;
// Add the arguments supplied when running the application to the configuration // Add the arguments supplied when running the application to the configuration
ArgvConfigSource configSource = new ArgvConfigSource(args); ArgvConfigSource configSource = new ArgvConfigSource(args);

View File

@ -57,40 +57,37 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
/// <summary> /// <summary>
/// Return a xfer uploader if one does not already exist. /// Return the xfer uploader for the given transaction.
/// </summary> /// </summary>
/// <remarks>
/// If an uploader does not already exist for this transaction then it is created, otherwise the existing
/// uploader is returned.
/// </remarks>
/// <param name="transactionID"></param> /// <param name="transactionID"></param>
/// <param name="assetID"> /// <returns>The asset xfer uploader</returns>
/// We must transfer the new asset ID into the uploader on creation, otherwise public AssetXferUploader RequestXferUploader(UUID transactionID)
/// we can see race conditions with other threads which can retrieve an item before it is updated with the new
/// asset id.
/// </param>
/// <returns>
/// The xfer uploader requested. Null if one is already in existence.
/// FIXME: This is a bizarre thing to do, and is probably meant to signal an error condition if multiple
/// transfers are made. Needs to be corrected.
/// </returns>
public AssetXferUploader RequestXferUploader(UUID transactionID, UUID assetID)
{ {
AssetXferUploader uploader;
lock (XferUploaders) lock (XferUploaders)
{ {
if (!XferUploaders.ContainsKey(transactionID)) if (!XferUploaders.ContainsKey(transactionID))
{ {
AssetXferUploader uploader = new AssetXferUploader(this, m_Scene, assetID, m_dumpAssetsToFile); uploader = new AssetXferUploader(this, m_Scene, transactionID, m_dumpAssetsToFile);
// m_log.DebugFormat( // m_log.DebugFormat(
// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID); // "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID);
XferUploaders.Add(transactionID, uploader); XferUploaders.Add(transactionID, uploader);
}
else
{
uploader = XferUploaders[transactionID];
}
}
return uploader; return uploader;
} }
}
m_log.WarnFormat("[AGENT ASSETS TRANSACTIONS]: Ignoring request for asset xfer uploader {0} since it already exists", transactionID);
return null;
}
public void HandleXfer(ulong xferID, uint packetID, byte[] data) public void HandleXfer(ulong xferID, uint packetID, byte[] data)
{ {
@ -151,115 +148,28 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
string description, string name, sbyte invType, string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask) sbyte type, byte wearableType, uint nextOwnerMask)
{ {
AssetXferUploader uploader = null; AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders)
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
uploader.RequestCreateInventoryItem( uploader.RequestCreateInventoryItem(
remoteClient, transactionID, folderID, remoteClient, folderID, callbackID,
callbackID, description, name, invType, type, description, name, invType, type, wearableType, nextOwnerMask);
wearableType, nextOwnerMask);
else
m_log.ErrorFormat(
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to create inventory item {1} from {2}",
transactionID, name, remoteClient.Name);
}
/// <summary>
/// Get an uploaded asset. If the data is successfully retrieved,
/// the transaction will be removed.
/// </summary>
/// <param name="transactionID"></param>
/// <returns>The asset if the upload has completed, null if it has not.</returns>
private AssetBase GetTransactionAsset(UUID transactionID)
{
lock (XferUploaders)
{
if (XferUploaders.ContainsKey(transactionID))
{
AssetXferUploader uploader = XferUploaders[transactionID];
AssetBase asset = uploader.GetAssetData();
RemoveXferUploader(transactionID);
return asset;
}
}
return null;
} }
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient,
SceneObjectPart part, UUID transactionID, SceneObjectPart part, UUID transactionID,
TaskInventoryItem item) TaskInventoryItem item)
{ {
AssetXferUploader uploader = null; AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders) uploader.RequestUpdateTaskInventoryItem(remoteClient, item);
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
{
AssetBase asset = GetTransactionAsset(transactionID);
// Only legacy viewers use this, and they prefer CAPS, which
// we have, so this really never runs.
// Allow it, but only for "safe" types.
if ((InventoryType)item.InvType != InventoryType.Notecard &&
(InventoryType)item.InvType != InventoryType.LSL)
return;
if (asset != null)
{
// m_log.DebugFormat(
// "[AGENT ASSETS TRANSACTIONS]: Updating item {0} in {1} for transaction {2}",
// item.Name, part.Name, transactionID);
asset.FullID = UUID.Random();
asset.Name = item.Name;
asset.Description = item.Description;
asset.Type = (sbyte)item.Type;
item.AssetID = asset.FullID;
m_Scene.AssetService.Store(asset);
}
}
else
{
m_log.ErrorFormat(
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update task inventory item {1} in {2}",
transactionID, item.Name, part.Name);
}
} }
public void RequestUpdateInventoryItem(IClientAPI remoteClient, public void RequestUpdateInventoryItem(IClientAPI remoteClient,
UUID transactionID, InventoryItemBase item) UUID transactionID, InventoryItemBase item)
{ {
AssetXferUploader uploader = null; AssetXferUploader uploader = RequestXferUploader(transactionID);
lock (XferUploaders) uploader.RequestUpdateInventoryItem(remoteClient, item);
{
if (XferUploaders.ContainsKey(transactionID))
uploader = XferUploaders[transactionID];
}
if (uploader != null)
{
uploader.RequestUpdateInventoryItem(remoteClient, transactionID, item);
}
else
{
m_log.ErrorFormat(
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update inventory item {1} for {2}",
transactionID, item.Name, remoteClient.Name);
}
} }
} }
} }

View File

@ -215,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", "[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName); item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
AgentAssetTransactions transactions = AgentAssetTransactions transactions =
@ -274,13 +274,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID); AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
if (uploader != null)
{
uploader.Initialise(remoteClient, assetID, transaction, type,
data, storeLocal, tempFile);
}
} }
/// <summary> /// <summary>

View File

@ -40,39 +40,75 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Upload state.
/// </summary>
/// <remarks>
/// New -> Uploading -> Complete
/// </remarks>
private enum UploadState
{
New,
Uploading,
Complete
}
/// <summary> /// <summary>
/// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we /// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we
/// are performing a delayed update. /// are performing a delayed update.
/// </summary> /// </summary>
AgentAssetTransactions m_transactions; AgentAssetTransactions m_transactions;
private UploadState m_uploadState = UploadState.New;
private AssetBase m_asset; private AssetBase m_asset;
private UUID InventFolder = UUID.Zero; private UUID InventFolder = UUID.Zero;
private sbyte invType = 0; private sbyte invType = 0;
private bool m_createItem = false; private bool m_createItem;
private uint m_createItemCallback = 0; private uint m_createItemCallback;
private bool m_updateItem = false;
private bool m_updateItem;
private InventoryItemBase m_updateItemData; private InventoryItemBase m_updateItemData;
private bool m_updateTaskItem;
private TaskInventoryItem m_updateTaskItemData;
private string m_description = String.Empty; private string m_description = String.Empty;
private bool m_dumpAssetToFile; private bool m_dumpAssetToFile;
private bool m_finished = false;
private string m_name = String.Empty; private string m_name = String.Empty;
private bool m_storeLocal; // private bool m_storeLocal;
private uint nextPerm = 0; private uint nextPerm = 0;
private IClientAPI ourClient; private IClientAPI ourClient;
private UUID TransactionID = UUID.Zero;
private UUID m_transactionID;
private sbyte type = 0; private sbyte type = 0;
private byte wearableType = 0; private byte wearableType = 0;
public ulong XferID; public ulong XferID;
private Scene m_Scene; private Scene m_Scene;
public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile) /// <summary>
/// AssetXferUploader constructor
/// </summary>
/// <param name='transactions'>/param>
/// <param name='scene'></param>
/// <param name='transactionID'></param>
/// <param name='dumpAssetToFile'>
/// If true then when the asset is uploaded it is dumped to a file with the format
/// String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat",
/// now.Year, now.Month, now.Day, now.Hour, now.Minute,
/// now.Second, m_asset.Name, m_asset.Type);
/// for debugging purposes.
/// </param>
public AssetXferUploader(
AgentAssetTransactions transactions, Scene scene, UUID transactionID, bool dumpAssetToFile)
{ {
m_asset = new AssetBase();
m_transactions = transactions; m_transactions = transactions;
m_transactionID = transactionID;
m_Scene = scene; m_Scene = scene;
m_asset = new AssetBase() { FullID = assetID };
m_dumpAssetToFile = dumpAssetToFile; m_dumpAssetToFile = dumpAssetToFile;
} }
@ -118,30 +154,50 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
/// <summary> /// <summary>
/// Initialise asset transfer from the client /// Start asset transfer from the client
/// </summary> /// </summary>
/// <param name="xferID"></param> /// <param name="remoteClient"></param>
/// <param name="packetID"></param> /// <param name="assetID"></param>
/// <param name="data"></param> /// <param name="transaction"></param>
public void Initialise(IClientAPI remoteClient, UUID assetID, /// <param name="type"></param>
UUID transaction, sbyte type, byte[] data, bool storeLocal, /// <param name="data">
/// Optional data. If present then the asset is created immediately with this data
/// rather than requesting an upload from the client. The data must be longer than 2 bytes.
/// </param>
/// <param name="storeLocal"></param>
/// <param name="tempFile"></param>
public void StartUpload(
IClientAPI remoteClient, UUID assetID, UUID transaction, sbyte type, byte[] data, bool storeLocal,
bool tempFile) bool tempFile)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}", // "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}",
// remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length); // remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length);
lock (this)
{
if (m_uploadState != UploadState.New)
{
m_log.WarnFormat(
"[ASSET XFER UPLOADER]: Tried to start upload of asset {0}, transaction {1} for {2} but this is already in state {3}. Aborting.",
assetID, transaction, remoteClient.Name, m_uploadState);
return;
}
m_uploadState = UploadState.Uploading;
}
ourClient = remoteClient; ourClient = remoteClient;
m_asset.Name = "blank";
m_asset.Description = "empty"; m_asset.FullID = assetID;
m_asset.Type = type; m_asset.Type = type;
m_asset.CreatorID = remoteClient.AgentId.ToString(); m_asset.CreatorID = remoteClient.AgentId.ToString();
m_asset.Data = data; m_asset.Data = data;
m_asset.Local = storeLocal; m_asset.Local = storeLocal;
m_asset.Temporary = tempFile; m_asset.Temporary = tempFile;
TransactionID = transaction; // m_storeLocal = storeLocal;
m_storeLocal = storeLocal;
if (m_asset.Data.Length > 2) if (m_asset.Data.Length > 2)
{ {
@ -166,36 +222,35 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
protected void SendCompleteMessage() protected void SendCompleteMessage()
{ {
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true,
m_asset.FullID);
// We must lock in order to avoid a race with a separate thread dealing with an inventory item or create // We must lock in order to avoid a race with a separate thread dealing with an inventory item or create
// message from other client UDP. // message from other client UDP.
lock (this) lock (this)
{ {
m_finished = true; m_uploadState = UploadState.Complete;
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID);
if (m_createItem) if (m_createItem)
{ {
DoCreateItem(m_createItemCallback); CompleteCreateItem(m_createItemCallback);
} }
else if (m_updateItem) else if (m_updateItem)
{ {
StoreAssetForItemUpdate(m_updateItemData); CompleteItemUpdate(m_updateItemData);
// Remove ourselves from the list of transactions if completion was delayed until the transaction
// was complete.
// TODO: Should probably do the same for create item.
m_transactions.RemoveXferUploader(TransactionID);
} }
else if (m_storeLocal) else if (m_updateTaskItem)
{ {
m_Scene.AssetService.Store(m_asset); CompleteTaskItemUpdate(m_updateTaskItemData);
} }
// else if (m_storeLocal)
// {
// m_Scene.AssetService.Store(m_asset);
// }
} }
m_log.DebugFormat( m_log.DebugFormat(
"[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}", "[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}",
m_asset.FullID, TransactionID); m_asset.FullID, m_transactionID);
if (m_dumpAssetToFile) if (m_dumpAssetToFile)
{ {
@ -223,11 +278,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
public void RequestCreateInventoryItem(IClientAPI remoteClient, public void RequestCreateInventoryItem(IClientAPI remoteClient,
UUID transactionID, UUID folderID, uint callbackID, UUID folderID, uint callbackID,
string description, string name, sbyte invType, string description, string name, sbyte invType,
sbyte type, byte wearableType, uint nextOwnerMask) sbyte type, byte wearableType, uint nextOwnerMask)
{
if (TransactionID == transactionID)
{ {
InventFolder = folderID; InventFolder = folderID;
m_name = name; m_name = name;
@ -243,9 +296,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
// We must lock to avoid a race with a separate thread uploading the asset. // We must lock to avoid a race with a separate thread uploading the asset.
lock (this) lock (this)
{ {
if (m_finished) if (m_uploadState == UploadState.Complete)
{ {
DoCreateItem(callbackID); CompleteCreateItem(callbackID);
} }
else else
{ {
@ -254,9 +307,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
} }
} }
}
public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item) public void RequestUpdateInventoryItem(IClientAPI remoteClient, InventoryItemBase item)
{ {
// We must lock to avoid a race with a separate thread uploading the asset. // We must lock to avoid a race with a separate thread uploading the asset.
lock (this) lock (this)
@ -271,9 +323,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
item.AssetID = m_asset.FullID; item.AssetID = m_asset.FullID;
m_Scene.InventoryService.UpdateItem(item); m_Scene.InventoryService.UpdateItem(item);
if (m_finished) if (m_uploadState == UploadState.Complete)
{ {
StoreAssetForItemUpdate(item); CompleteItemUpdate(item);
} }
else else
{ {
@ -287,20 +339,59 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
} }
} }
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, TaskInventoryItem taskItem)
{
// We must lock to avoid a race with a separate thread uploading the asset.
lock (this)
{
m_asset.Name = taskItem.Name;
m_asset.Description = taskItem.Description;
m_asset.Type = (sbyte)taskItem.Type;
taskItem.AssetID = m_asset.FullID;
if (m_uploadState == UploadState.Complete)
{
CompleteTaskItemUpdate(taskItem);
}
else
{
m_updateTaskItem = true;
m_updateTaskItemData = taskItem;
}
}
}
/// <summary> /// <summary>
/// Store the asset for the given item. /// Store the asset for the given item when it has been uploaded.
/// </summary> /// </summary>
/// <param name="item"></param> /// <param name="item"></param>
private void StoreAssetForItemUpdate(InventoryItemBase item) private void CompleteItemUpdate(InventoryItemBase item)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}", // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}",
// m_asset.FullID, item.Name, ourClient.Name); // m_asset.FullID, item.Name, ourClient.Name);
m_Scene.AssetService.Store(m_asset); m_Scene.AssetService.Store(m_asset);
m_transactions.RemoveXferUploader(m_transactionID);
} }
private void DoCreateItem(uint callbackID) /// <summary>
/// Store the asset for the given task item when it has been uploaded.
/// </summary>
/// <param name="taskItem"></param>
private void CompleteTaskItemUpdate(TaskInventoryItem taskItem)
{
// m_log.DebugFormat(
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}",
// m_asset.FullID, taskItem.Name, ourClient.Name);
m_Scene.AssetService.Store(m_asset);
m_transactions.RemoveXferUploader(m_transactionID);
}
private void CompleteCreateItem(uint callbackID)
{ {
m_Scene.AssetService.Store(m_asset); m_Scene.AssetService.Store(m_asset);
@ -326,20 +417,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
ourClient.SendInventoryItemCreateUpdate(item, callbackID); ourClient.SendInventoryItemCreateUpdate(item, callbackID);
else else
ourClient.SendAlertMessage("Unable to create inventory item"); ourClient.SendAlertMessage("Unable to create inventory item");
}
/// <summary> m_transactions.RemoveXferUploader(m_transactionID);
/// Get the asset data uploaded in this transfer.
/// </summary>
/// <returns>null if the asset has not finished uploading</returns>
public AssetBase GetAssetData()
{
if (m_finished)
{
return m_asset;
}
return null;
} }
} }
} }

View File

@ -240,6 +240,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
} }
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp) public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp)
{
if (!Enabled)
return false;
if (AttachObjectInternal(sp, group, attachmentPt, silent, temp))
{
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
return true;
}
return false;
}
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp)
{ {
lock (sp.AttachmentsSyncLock) lock (sp.AttachmentsSyncLock)
{ {
@ -794,7 +808,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
// This will throw if the attachment fails // This will throw if the attachment fails
try try
{ {
AttachObject(sp, objatt, attachmentPt, false, false); AttachObjectInternal(sp, objatt, attachmentPt, false, false);
} }
catch (Exception e) catch (Exception e)
{ {
@ -859,6 +873,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID);
item = m_scene.InventoryService.GetItem(item); item = m_scene.InventoryService.GetItem(item);
if (item == null)
return;
bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
if (changed && m_scene.AvatarFactory != null) if (changed && m_scene.AvatarFactory != null)
{ {
@ -948,15 +965,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
AttachmentPt &= 0x7f; AttachmentPt &= 0x7f;
// Calls attach with a Zero position // Calls attach with a Zero position
if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, false)) AttachObject(sp, part.ParentGroup, AttachmentPt, false, false);
{
// m_log.Debug(
// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
// + ", AttachmentPoint: " + AttachmentPt);
// Save avatar attachment information
m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId);
}
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -62,7 +62,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
public class AttachmentsModuleTests : OpenSimTestCase public class AttachmentsModuleTests : OpenSimTestCase
{ {
private AutoResetEvent m_chatEvent = new AutoResetEvent(false); private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
private OSChatMessage m_osChatMessageReceived; // private OSChatMessage m_osChatMessageReceived;
// Used to test whether the operations have fired the attach event. Must be reset after each test.
private int m_numberOfAttachEventsFired;
[TestFixtureSetUp] [TestFixtureSetUp]
public void FixtureInit() public void FixtureInit()
@ -83,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
{ {
// Console.WriteLine("Got chat [{0}]", oscm.Message); // Console.WriteLine("Got chat [{0}]", oscm.Message);
m_osChatMessageReceived = oscm; // m_osChatMessageReceived = oscm;
m_chatEvent.Set(); m_chatEvent.Set();
} }
@ -99,6 +102,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
"attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config); "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
scene.EventManager.OnAttach += (localID, itemID, avatarID) => m_numberOfAttachEventsFired++;
return scene; return scene;
} }
@ -181,6 +186,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
m_numberOfAttachEventsFired = 0;
Scene scene = CreateTestScene(); Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
@ -189,6 +196,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false);
// Check status on scene presence // Check status on scene presence
@ -216,7 +224,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// TestHelpers.DisableLogging(); // Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
/// <summary> /// <summary>
@ -228,6 +237,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
m_numberOfAttachEventsFired = 0;
Scene scene = CreateTestScene(); Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
@ -247,6 +258,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(sp.HasAttachments(), Is.False); Assert.That(sp.HasAttachments(), Is.False);
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
} }
[Test] [Test]
@ -261,6 +275,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.RezSingleAttachmentFromInventory( scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest); sp, attItem.ID, (uint)AttachmentPoint.Chest);
@ -280,6 +295,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
/// <summary> /// <summary>
@ -338,6 +356,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
ISceneEntity so ISceneEntity so
= scene.AttachmentsModule.RezSingleAttachmentFromInventory( = scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest); sp, attItem.ID, (uint)AttachmentPoint.Chest);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId); scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId);
// Check scene presence status // Check scene presence status
@ -353,6 +373,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
// Check object in scene // Check object in scene
Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null); Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
[Test] [Test]
@ -369,6 +392,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup so SceneObjectGroup so
= (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory( = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest); sp, attItem.ID, (uint)AttachmentPoint.Chest);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so); scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so);
// Check status on scene presence // Check status on scene presence
@ -380,6 +405,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0)); Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
/// <summary> /// <summary>
@ -461,10 +489,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
m_numberOfAttachEventsFired = 0;
scene.IncomingCloseAgent(presence.UUID, false); scene.IncomingCloseAgent(presence.UUID, false);
// Check that we can't retrieve this attachment from the scene. // Check that we can't retrieve this attachment from the scene.
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
} }
[Test] [Test]
@ -480,6 +512,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
acd.Appearance = new AvatarAppearance(); acd.Appearance = new AvatarAppearance();
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
m_numberOfAttachEventsFired = 0;
ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
Assert.That(presence.HasAttachments(), Is.True); Assert.That(presence.HasAttachments(), Is.True);
@ -502,6 +536,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events. We expect OnAttach to fire on login.
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
} }
[Test] [Test]
@ -522,10 +559,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Vector3 newPosition = new Vector3(1, 2, 4); Vector3 newPosition = new Vector3(1, 2, 4);
m_numberOfAttachEventsFired = 0;
scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient); scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient);
Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition)); Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition));
Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition)); Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
} }
[Test] [Test]
@ -574,6 +615,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportPosition = new Vector3(10, 11, 12);
Vector3 teleportLookAt = new Vector3(20, 21, 22); Vector3 teleportLookAt = new Vector3(20, 21, 22);
m_numberOfAttachEventsFired = 0;
sceneA.RequestTeleportLocation( sceneA.RequestTeleportLocation(
beforeTeleportSp.ControllingClient, beforeTeleportSp.ControllingClient,
sceneB.RegionInfo.RegionHandle, sceneB.RegionInfo.RegionHandle,
@ -616,29 +658,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0)); Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
}
// I'm commenting this test because scene setup NEEDS InventoryService to // Check events
// be non-null Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
//[Test] }
// public void T032_CrossAttachments()
// {
// TestHelpers.InMethod();
//
// ScenePresence presence = scene.GetScenePresence(agent1);
// ScenePresence presence2 = scene2.GetScenePresence(agent1);
// presence2.AddAttachment(sog1);
// presence2.AddAttachment(sog2);
//
// ISharedRegionModule serialiser = new SerialiserModule();
// SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser);
// SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser);
//
// Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross");
//
// //Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful");
// Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted");
// Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects");
// }
} }
} }

View File

@ -107,7 +107,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
} }
} }
#region ISharedRegionModule #region ISharedRegionModule
public override string Name public override string Name
@ -149,7 +148,36 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
base.AddRegion(scene); base.AddRegion(scene);
if (m_Enabled) if (m_Enabled)
{
scene.RegisterModuleInterface<IUserAgentVerificationModule>(this); scene.RegisterModuleInterface<IUserAgentVerificationModule>(this);
scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject;
}
}
void OnIncomingSceneObject(SceneObjectGroup so)
{
if (!so.IsAttachment)
return;
if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar))
return;
// foreign user
AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar);
if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
{
if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
{
string url = aCircuit.ServiceURLs["AssetServerURI"].ToString();
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url);
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url);
uuidGatherer.GatherAssetUuids(so, ids);
foreach (KeyValuePair<UUID, AssetType> kvp in ids)
uuidGatherer.FetchAsset(kvp.Key);
}
}
} }
protected override void OnNewClient(IClientAPI client) protected override void OnNewClient(IClientAPI client)
@ -217,6 +245,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
// Log them out of this grid // Log them out of this grid
Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId); Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
string userId = Scene.UserManagementModule.GetUserUUI(sp.UUID);
Scene.GridUserService.LoggedOut(userId, UUID.Zero, Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
} }
} }

View File

@ -71,19 +71,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
#region Internal functions #region Internal functions
public AssetBase FetchAsset(string url, UUID assetID) public AssetMetadata FetchMetadata(string url, UUID assetID)
{ {
if (!url.EndsWith("/") && !url.EndsWith("=")) if (!url.EndsWith("/") && !url.EndsWith("="))
url = url + "/"; url = url + "/";
AssetBase asset = m_scene.AssetService.Get(url + assetID.ToString()); AssetMetadata meta = m_scene.AssetService.GetMetadata(url + assetID.ToString());
if (asset != null) if (meta != null)
{ m_log.DebugFormat("[HG ASSET MAPPER]: Fetched metadata for asset {0} of type {1} from {2} ", assetID, meta.Type, url);
m_log.DebugFormat("[HG ASSET MAPPER]: Copied asset {0} from {1} to local asset server. ", asset.ID, url); else
return asset; m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetched metadata for asset {0} from {1} ", assetID, url);
}
return null; return meta;
} }
public bool PostAsset(string url, AssetBase asset) public bool PostAsset(string url, AssetBase asset)
@ -93,6 +93,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
if (!url.EndsWith("/") && !url.EndsWith("=")) if (!url.EndsWith("/") && !url.EndsWith("="))
url = url + "/"; url = url + "/";
bool success = true;
// See long comment in AssetCache.AddAsset // See long comment in AssetCache.AddAsset
if (!asset.Temporary || asset.Local) if (!asset.Temporary || asset.Local)
{ {
@ -103,14 +104,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
// not having a global naming infrastructure // not having a global naming infrastructure
AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID); AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
Copy(asset, asset1); Copy(asset, asset1);
try
{
asset1.ID = url + asset.ID; asset1.ID = url + asset.ID;
}
catch
{
m_log.Warn("[HG ASSET MAPPER]: Oops.");
}
AdjustIdentifiers(asset1.Metadata); AdjustIdentifiers(asset1.Metadata);
if (asset1.Metadata.Type == (sbyte)AssetType.Object) if (asset1.Metadata.Type == (sbyte)AssetType.Object)
@ -118,10 +112,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
else else
asset1.Data = asset.Data; asset1.Data = asset.Data;
m_scene.AssetService.Store(asset1); string id = m_scene.AssetService.Store(asset1);
if (id == string.Empty)
{
m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID);
success = false;
}
else
m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url); m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
} }
return true; return success;
} }
else else
m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache."); m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache.");
@ -222,28 +222,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
public void Get(UUID assetID, UUID ownerID, string userAssetURL) public void Get(UUID assetID, UUID ownerID, string userAssetURL)
{ {
// Get the item from the remote asset server onto the local AssetCache // Get the item from the remote asset server onto the local AssetService
// and place an entry in m_assetMap
m_log.Debug("[HG ASSET MAPPER]: Fetching object " + assetID + " from asset server " + userAssetURL); AssetMetadata meta = FetchMetadata(userAssetURL, assetID);
AssetBase asset = FetchAsset(userAssetURL, assetID); if (meta == null)
return;
if (asset != null) // The act of gathering UUIDs downloads the assets from the remote server
{
// OK, now fetch the inside.
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL); HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids);
if (ids.ContainsKey(assetID))
ids.Remove(assetID);
foreach (UUID uuid in ids.Keys)
FetchAsset(userAssetURL, uuid);
m_log.DebugFormat("[HG ASSET MAPPER]: Successfully fetched asset {0} from asset server {1}", asset.ID, userAssetURL);
}
else
m_log.Warn("[HG ASSET MAPPER]: Could not fetch asset from remote asset server " + userAssetURL);
} }
@ -257,18 +246,22 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
if (asset != null) if (asset != null)
{ {
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty); HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids); uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
bool success = false;
foreach (UUID uuid in ids.Keys) foreach (UUID uuid in ids.Keys)
{ {
asset = m_scene.AssetService.Get(uuid.ToString()); asset = m_scene.AssetService.Get(uuid.ToString());
if (asset == null) if (asset == null)
m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid); m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid);
else else
PostAsset(userAssetURL, asset); success = PostAsset(userAssetURL, asset);
} }
// maybe all pieces got there... // maybe all pieces got there...
if (!success)
m_log.DebugFormat("[HG ASSET MAPPER]: Problems posting item {0} to asset server {1}", assetID, userAssetURL);
else
m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL); m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL);
} }

View File

@ -263,9 +263,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
//} //}
// OK, we're done fetching. Pass it up to the default RezObject // OK, we're done fetching. Pass it up to the default RezObject
return base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
RezSelected, RemoveItem, fromTaskID, attachment); RezSelected, RemoveItem, fromTaskID, attachment);
if (sog == null)
remoteClient.SendAgentAlertMessage("Unable to rez: problem accessing inventory or locating assets", false);
return sog;
} }
public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver) public override void TransferInventoryAssets(InventoryItemBase item, UUID sender, UUID receiver)

View File

@ -1,57 +0,0 @@
/*
* 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 OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
{
public class HGUuidGatherer : UuidGatherer
{
protected string m_assetServerURL;
protected HGAssetMapper m_assetMapper;
public HGUuidGatherer(HGAssetMapper assMap, IAssetService assetCache, string assetServerURL) : base(assetCache)
{
m_assetMapper = assMap;
m_assetServerURL = assetServerURL;
}
protected override AssetBase GetAsset(UUID uuid)
{
if (string.Empty == m_assetServerURL)
return m_assetCache.Get(uuid.ToString());
else
return m_assetMapper.FetchAsset(m_assetServerURL, uuid);
}
}
}

View File

@ -137,6 +137,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
ud.FirstName = words[0]; ud.FirstName = words[0];
ud.LastName = "@" + words[1]; ud.LastName = "@" + words[1];
users.Add(ud); users.Add(ud);
// WARNING! that uriStr is not quite right... it may be missing the / at the end,
// which will cause trouble (duplicate entries on some tables). We should
// get the UUI instead from the UAS. TO BE FIXED.
AddUser(userID, names[0], names[1], uriStr); AddUser(userID, names[0], names[1], uriStr);
m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} found", words[0], words[1]); m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} found", words[0], words[1]);
} }

View File

@ -429,8 +429,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
public void AddUser(UUID uuid, string first, string last, string homeURL) public void AddUser(UUID uuid, string first, string last, string homeURL)
{ {
// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
AddUser(uuid, homeURL + ";" + first + " " + last); AddUser(uuid, homeURL + ";" + first + " " + last);
} }
@ -553,8 +552,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
MainConsole.Instance.Output("-----------------------------------------------------------------------------"); MainConsole.Instance.Output("-----------------------------------------------------------------------------");
foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache)
{ {
MainConsole.Instance.Output(String.Format("{0} {1} {2}", MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
kvp.Key, kvp.Value.FirstName, kvp.Value.LastName)); kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
} }
return; return;

View File

@ -111,10 +111,14 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
public void GetDrawStringSize(string text, string fontName, int fontSize, public void GetDrawStringSize(string text, string fontName, int fontSize,
out double xSize, out double ySize) out double xSize, out double ySize)
{
lock (this)
{ {
using (Font myFont = new Font(fontName, fontSize)) using (Font myFont = new Font(fontName, fontSize))
{ {
SizeF stringSize = new SizeF(); SizeF stringSize = new SizeF();
// XXX: This lock may be unnecessary.
lock (m_graph) lock (m_graph)
{ {
stringSize = m_graph.MeasureString(text, myFont); stringSize = m_graph.MeasureString(text, myFont);
@ -123,6 +127,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
} }
} }
} }
}
#endregion #endregion

View File

@ -56,6 +56,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
private bool m_Enabled = false; private bool m_Enabled = false;
private AssetPermissions m_AssetPerms;
public Type ReplaceableInterface public Type ReplaceableInterface
{ {
get { return null; } get { return null; }
@ -128,6 +130,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
if (m_LocalAssetServiceURI != string.Empty) if (m_LocalAssetServiceURI != string.Empty)
m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/'); m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/');
IConfig hgConfig = source.Configs["HGAssetService"];
m_AssetPerms = new AssetPermissions(hgConfig); // it's ok if arg is null
m_Enabled = true; m_Enabled = true;
m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled"); m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled");
} }
@ -206,14 +211,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
asset = m_HGService.Get(id); asset = m_HGService.Get(id);
if (asset != null) if (asset != null)
{ {
// Now store it locally // Now store it locally, if allowed
// For now, let me just do it for textures and scripts if (m_AssetPerms.AllowedImport(asset.Type))
if (((AssetType)asset.Type == AssetType.Texture) ||
((AssetType)asset.Type == AssetType.LSLBytecode) ||
((AssetType)asset.Type == AssetType.LSLText))
{
m_GridService.Store(asset); m_GridService.Store(asset);
} else
return null;
} }
} }
else else
@ -328,7 +330,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
string id = string.Empty; string id = string.Empty;
if (IsHG(asset.ID)) if (IsHG(asset.ID))
{
if (m_AssetPerms.AllowedExport(asset.Type))
id = m_HGService.Store(asset); id = m_HGService.Store(asset);
else
return String.Empty;
}
else else
id = m_GridService.Store(asset); id = m_GridService.Store(asset);

View File

@ -46,8 +46,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
public class GridConnectorsTests : OpenSimTestCase public class GridConnectorsTests : OpenSimTestCase
{ {
LocalGridServicesConnector m_LocalConnector; LocalGridServicesConnector m_LocalConnector;
private void SetUp()
[SetUp]
public override void SetUp()
{ {
base.SetUp();
IConfigSource config = new IniConfigSource(); IConfigSource config = new IniConfigSource();
config.AddConfig("Modules"); config.AddConfig("Modules");
config.AddConfig("GridService"); config.AddConfig("GridService");
@ -71,8 +75,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();
SetUp();
// Create 4 regions // Create 4 regions
GridRegion r1 = new GridRegion(); GridRegion r1 = new GridRegion();
r1.RegionName = "Test Region 1"; r1.RegionName = "Test Region 1";

View File

@ -65,11 +65,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
public void OnMakeRootAgent(ScenePresence sp) public void OnMakeRootAgent(ScenePresence sp)
{ {
// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName);
if (sp.PresenceType != PresenceType.Npc) if (sp.PresenceType != PresenceType.Npc)
{
string userid = sp.Scene.UserManagementModule.GetUserUUI(sp.UUID);
//m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", userid, sp.Scene.RegionInfo.RegionName);
m_GridUserService.SetLastPosition( m_GridUserService.SetLastPosition(
sp.UUID.ToString(), UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); userid, UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
}
} }
public void OnNewClient(IClientAPI client) public void OnNewClient(IClientAPI client)
@ -82,9 +84,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
if (client.SceneAgent.IsChildAgent) if (client.SceneAgent.IsChildAgent)
return; return;
// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); string userId = client.AgentId.ToString();
if (client.Scene is Scene)
{
Scene s = (Scene)client.Scene;
userId = s.UserManagementModule.GetUserUUI(client.AgentId);
}
//m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", userId, client.Scene.RegionInfo.RegionName);
m_GridUserService.LoggedOut( m_GridUserService.LoggedOut(
client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, userId, client.SessionId, client.Scene.RegionInfo.RegionID,
client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat); client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat);
} }
} }

View File

@ -44,6 +44,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private const int KEEPTIME = 30; // 30 secs
private ExpiringCache<string, GridUserInfo> m_Infos = new ExpiringCache<string, GridUserInfo>();
#region ISharedRegionModule #region ISharedRegionModule
private bool m_Enabled = false; private bool m_Enabled = false;
@ -128,23 +131,60 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
public bool LoggedOut(string userID, UUID sessionID, UUID region, Vector3 position, Vector3 lookat) public bool LoggedOut(string userID, UUID sessionID, UUID region, Vector3 position, Vector3 lookat)
{ {
if (m_Infos.Contains(userID))
m_Infos.Remove(userID);
return m_RemoteConnector.LoggedOut(userID, sessionID, region, position, lookat); return m_RemoteConnector.LoggedOut(userID, sessionID, region, position, lookat);
} }
public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
{ {
return m_RemoteConnector.SetHome(userID, regionID, position, lookAt); if (m_RemoteConnector.SetHome(userID, regionID, position, lookAt))
{
// Update the cache too
GridUserInfo info = null;
if (m_Infos.TryGetValue(userID, out info))
{
info.HomeRegionID = regionID;
info.HomePosition = position;
info.HomeLookAt = lookAt;
}
return true;
}
return false;
} }
public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt)
{ {
return m_RemoteConnector.SetLastPosition(userID, sessionID, regionID, position, lookAt); if (m_RemoteConnector.SetLastPosition(userID, sessionID, regionID, position, lookAt))
{
// Update the cache too
GridUserInfo info = null;
if (m_Infos.TryGetValue(userID, out info))
{
info.LastRegionID = regionID;
info.LastPosition = position;
info.LastLookAt = lookAt;
}
return true;
}
return false;
} }
public GridUserInfo GetGridUserInfo(string userID) public GridUserInfo GetGridUserInfo(string userID)
{ {
return m_RemoteConnector.GetGridUserInfo(userID); GridUserInfo info = null;
if (m_Infos.TryGetValue(userID, out info))
return info;
info = m_RemoteConnector.GetGridUserInfo(userID);
m_Infos.AddOrUpdate(userID, info, KEEPTIME);
return info;
} }
public GridUserInfo[] GetGridUserInfo(string[] userID) public GridUserInfo[] GetGridUserInfo(string[] userID)

View File

@ -65,8 +65,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
protected TaskInventoryItem m_soundItem; protected TaskInventoryItem m_soundItem;
[SetUp] [SetUp]
public void SetUp() public override void SetUp()
{ {
base.SetUp();
// FIXME: Do something about this - relying on statics in unit tests causes trouble sooner or later
new SceneManager(); new SceneManager();
m_archiverModule = new ArchiverModule(); m_archiverModule = new ArchiverModule();

View File

@ -184,6 +184,22 @@ namespace OpenSim.Region.Framework.Scenes
public delegate void OnPluginConsoleDelegate(string[] args); public delegate void OnPluginConsoleDelegate(string[] args);
/// <summary>
/// Triggered after <see cref="OpenSim.IApplicationPlugin.PostInitialise"/>
/// has been called for all <see cref="OpenSim.IApplicationPlugin"/>
/// loaded via <see cref="OpenSim.OpenSimBase.LoadPlugins"/>.
/// Handlers for this event are typically used to parse the arguments
/// from <see cref="OnPluginConsoleDelegate"/> in order to process or
/// filter the arguments and pass them onto <see cref="OpenSim.Region.CoreModules.Framework.InterfaceCommander.Commander.ProcessConsoleCommand"/>
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerOnPluginConsole"/> in
/// <see cref="Scene.SendCommandToPlugins"/> via
/// <see cref="SceneManager.SendCommandToPluginModules"/> via
/// <see cref="OpenSim.OpenSimBase.HandleCommanderCommand"/> via
/// <see cref="OpenSim.OpenSimBase.AddPluginCommands"/> via
/// <see cref="OpenSim.OpenSimBase.StartupSpecific"/>
/// </remarks>
public event OnPluginConsoleDelegate OnPluginConsole; public event OnPluginConsoleDelegate OnPluginConsole;
/// <summary> /// <summary>
@ -198,6 +214,18 @@ namespace OpenSim.Region.Framework.Scenes
public delegate void OnSetRootAgentSceneDelegate(UUID agentID, Scene scene); public delegate void OnSetRootAgentSceneDelegate(UUID agentID, Scene scene);
/// <summary>
/// Triggered before the grunt work for adding a root agent to a
/// scene has been performed (resuming attachment scripts, physics,
/// animations etc.)
/// </summary>
/// <remarks>
/// Triggered before <see cref="OnMakeRootAgent"/>
/// by <see cref="TriggerSetRootAgentScene"/>
/// in <see cref="ScenePresence.MakeRootAgent"/>
/// via <see cref="Scene.AgentCrossing"/>
/// and <see cref="ScenePresence.CompleteMovement"/>
/// </remarks>
public event OnSetRootAgentSceneDelegate OnSetRootAgentScene; public event OnSetRootAgentSceneDelegate OnSetRootAgentScene;
/// <summary> /// <summary>
@ -222,13 +250,45 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// Fired when an object is touched/grabbed. /// Fired when an object is touched/grabbed.
/// </summary> /// </summary>
/// <remarks>
/// The originalID is the local ID of the part that was actually touched. The localID itself is always that of /// The originalID is the local ID of the part that was actually touched. The localID itself is always that of
/// the root part. /// the root part.
/// Triggerd in response to <see cref="OpenSim.Framework.IClientAPI.OnGrabObject"/>
/// via <see cref="TriggerObjectGrab"/>
/// in <see cref="Scene.ProcessObjectGrab"/>
/// </remarks>
public event ObjectGrabDelegate OnObjectGrab; public event ObjectGrabDelegate OnObjectGrab;
public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs); public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs);
/// <summary>
/// Triggered when an object is being touched/grabbed continuously.
/// </summary>
/// <remarks>
/// Triggered in response to <see cref="OpenSim.Framework.IClientAPI.OnGrabUpdate"/>
/// via <see cref="TriggerObjectGrabbing"/>
/// in <see cref="Scene.ProcessObjectGrabUpdate"/>
/// </remarks>
public event ObjectGrabDelegate OnObjectGrabbing; public event ObjectGrabDelegate OnObjectGrabbing;
/// <summary>
/// Triggered when an object stops being touched/grabbed.
/// </summary>
/// <remarks>
/// Triggered in response to <see cref="OpenSim.Framework.IClientAPI.OnDeGrabObject"/>
/// via <see cref="TriggerObjectDeGrab"/>
/// in <see cref="Scene.ProcessObjectDeGrab"/>
/// </remarks>
public event ObjectDeGrabDelegate OnObjectDeGrab; public event ObjectDeGrabDelegate OnObjectDeGrab;
/// <summary>
/// Triggered when a script resets.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerScriptReset"/>
/// in <see cref="Scene.ProcessScriptReset"/>
/// via <see cref="OpenSim.Framework.IClientAPI.OnScriptReset"/>
/// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleScriptReset"/>
/// </remarks>
public event ScriptResetDelegate OnScriptReset; public event ScriptResetDelegate OnScriptReset;
public event OnPermissionErrorDelegate OnPermissionError; public event OnPermissionErrorDelegate OnPermissionError;
@ -238,29 +298,105 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Occurs after OnNewScript. /// Occurs after OnNewScript.
/// Triggered by <see cref="TriggerRezScript"/>
/// in <see cref="SceneObjectPartInventory.CreateScriptInstance"/>
/// </remarks> /// </remarks>
public event NewRezScript OnRezScript; public event NewRezScript OnRezScript;
public delegate void NewRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource); public delegate void NewRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource);
public delegate void RemoveScript(uint localID, UUID itemID); public delegate void RemoveScript(uint localID, UUID itemID);
/// <summary>
/// Triggered when a script is removed from an object.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerRemoveScript"/>
/// in <see cref="Scene.RemoveTaskInventory"/>,
/// <see cref="Scene.CreateAgentInventoryItemFromTask"/>,
/// <see cref="SceneObjectPartInventory.RemoveScriptInstance"/>,
/// <see cref="SceneObjectPartInventory.RemoveInventoryItem"/>
/// </remarks>
public event RemoveScript OnRemoveScript; public event RemoveScript OnRemoveScript;
public delegate void StartScript(uint localID, UUID itemID); public delegate void StartScript(uint localID, UUID itemID);
/// <summary>
/// Triggered when a script starts.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerStartScript"/>
/// in <see cref="Scene.SetScriptRunning"/>
/// via <see cref="OpenSim.Framework.IClientAPI.OnSetScriptRunning"/>,
/// via <see cref="OpenSim.Region.ClientStack.LindenUDP.HandleSetScriptRunning"/>
/// </remarks>
public event StartScript OnStartScript; public event StartScript OnStartScript;
public delegate void StopScript(uint localID, UUID itemID); public delegate void StopScript(uint localID, UUID itemID);
/// <summary>
/// Triggered when a script stops.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerStopScript"/>,
/// in <see cref="SceneObjectPartInventory.CreateScriptInstance"/>,
/// <see cref="SceneObjectPartInventory.StopScriptInstance"/>,
/// <see cref="Scene.SetScriptRunning"/>
/// </remarks>
public event StopScript OnStopScript; public event StopScript OnStopScript;
public delegate bool SceneGroupMoved(UUID groupID, Vector3 delta); public delegate bool SceneGroupMoved(UUID groupID, Vector3 delta);
/// <summary>
/// Triggered when an object is moved.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerGroupMove"/>
/// in <see cref="SceneObjectGroup.UpdateGroupPosition"/>,
/// <see cref="SceneObjectGroup.GrabMovement"/>
/// </remarks>
public event SceneGroupMoved OnSceneGroupMove; public event SceneGroupMoved OnSceneGroupMove;
public delegate void SceneGroupGrabed(UUID groupID, Vector3 offset, UUID userID); public delegate void SceneGroupGrabed(UUID groupID, Vector3 offset, UUID userID);
/// <summary>
/// Triggered when an object is grabbed.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerGroupGrab"/>
/// in <see cref="SceneObjectGroup.OnGrabGroup"/>
/// via <see cref="SceneObjectGroup.ObjectGrabHandler"/>
/// via <see cref="Scene.ProcessObjectGrab"/>
/// via <see cref="OpenSim.Framework.IClientAPI.OnGrabObject"/>
/// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleObjectGrab"/>
/// </remarks>
public event SceneGroupGrabed OnSceneGroupGrab; public event SceneGroupGrabed OnSceneGroupGrab;
public delegate bool SceneGroupSpinStarted(UUID groupID); public delegate bool SceneGroupSpinStarted(UUID groupID);
/// <summary>
/// Triggered when an object starts to spin.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerGroupSpinStart"/>
/// in <see cref="SceneObjectGroup.SpinStart"/>
/// via <see cref="SceneGraph.SpinStart"/>
/// via <see cref="OpenSim.Framework.IClientAPI.OnSpinStart"/>
/// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleObjectSpinStart"/>
/// </remarks>
public event SceneGroupSpinStarted OnSceneGroupSpinStart; public event SceneGroupSpinStarted OnSceneGroupSpinStart;
public delegate bool SceneGroupSpun(UUID groupID, Quaternion rotation); public delegate bool SceneGroupSpun(UUID groupID, Quaternion rotation);
/// <summary>
/// Triggered when an object is being spun.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerGroupSpin"/>
/// in <see cref="SceneObjectGroup.SpinMovement"/>
/// via <see cref="SceneGraph.SpinObject"/>
/// via <see cref="OpenSim.Framework.IClientAPI.OnSpinUpdate"/>
/// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleObjectSpinUpdate"/>
/// </remarks>
public event SceneGroupSpun OnSceneGroupSpin; public event SceneGroupSpun OnSceneGroupSpin;
public delegate void LandObjectAdded(ILandObject newParcel); public delegate void LandObjectAdded(ILandObject newParcel);
@ -299,6 +435,9 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Occurs before OnRezScript /// Occurs before OnRezScript
/// Triggered by <see cref="TriggerNewScript"/>
/// in <see cref="Scene.RezScriptFromAgentInventory"/>,
/// <see cref="Scene.RezNewScript"/>
/// </remarks> /// </remarks>
public event NewScript OnNewScript; public event NewScript OnNewScript;
@ -333,6 +472,12 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Triggered after the scene receives a client's upload of an updated script and has stored it in an asset. /// Triggered after the scene receives a client's upload of an updated script and has stored it in an asset.
/// Triggered by <see cref="TriggerUpdateScript"/>
/// in <see cref="Scene.CapsUpdateTaskInventoryScriptAsset"/>
/// via <see cref="Scene.CapsUpdateTaskInventoryScriptAsset"/>
/// via <see cref="OpenSim.Region.ClientStack.Linden.BunchOfCaps.TaskScriptUpdated"/>
/// via <see cref="OpenSim.Region.ClientStack.Linden.TaskInventoryScriptUpdater.OnUpLoad"/>
/// via <see cref="OpenSim.Region.ClientStack.Linden.TaskInventoryScriptUpdater.uploaderCaps"/>
/// </remarks> /// </remarks>
public event UpdateScript OnUpdateScript; public event UpdateScript OnUpdateScript;
@ -358,48 +503,203 @@ namespace OpenSim.Region.Framework.Scenes
} }
/// <summary> /// <summary>
/// Triggered when some scene object properties change.
/// </summary>
/// <remarks>
/// ScriptChangedEvent is fired when a scene object property that a script might be interested /// ScriptChangedEvent is fired when a scene object property that a script might be interested
/// in (such as color, scale or inventory) changes. Only enough information sent is for the LSL changed event. /// in (such as color, scale or inventory) changes. Only enough information sent is for the LSL changed event.
/// This is not an indication that the script has changed (see OnUpdateScript for that). /// This is not an indication that the script has changed (see OnUpdateScript for that).
/// This event is sent to a script to tell it that some property changed on /// This event is sent to a script to tell it that some property changed on
/// the object the script is in. See http://lslwiki.net/lslwiki/wakka.php?wakka=changed . /// the object the script is in. See http://lslwiki.net/lslwiki/wakka.php?wakka=changed .
/// </summary> /// Triggered by <see cref="TriggerOnScriptChangedEvent"/>
/// in <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.TeleportAgentWithinRegion"/>,
/// <see cref="SceneObjectPart.TriggerScriptChangedEvent"/>
/// </remarks>
public event ScriptChangedEvent OnScriptChangedEvent; public event ScriptChangedEvent OnScriptChangedEvent;
public delegate void ScriptChangedEvent(uint localID, uint change); public delegate void ScriptChangedEvent(uint localID, uint change);
public delegate void ScriptControlEvent(UUID item, UUID avatarID, uint held, uint changed); public delegate void ScriptControlEvent(UUID item, UUID avatarID, uint held, uint changed);
/// <summary>
/// Triggered when a script receives control input from an agent.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerControlEvent"/>
/// in <see cref="ScenePresence.SendControlsToScripts"/>
/// via <see cref="ScenePresence.HandleAgentUpdate"/>
/// via <see cref="OpenSim.Framework.IClientAPI.OnAgentUpdate"/>
/// via <see cref="OpenSim.Region.ClientStack.LindenUDP.LLClientView.HandleAgentUpdate"/>
/// </remarks>
public event ScriptControlEvent OnScriptControlEvent; public event ScriptControlEvent OnScriptControlEvent;
public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos); public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos);
/// <summary>
/// Triggered when an object has arrived within a tolerance distance
/// of a motion target.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerAtTargetEvent"/>
/// in <see cref="SceneObjectGroup.checkAtTargets"/>
/// via <see cref="SceneObjectGroup.ScheduleGroupForFullUpdate"/>,
/// <see cref="Scene.CheckAtTargets"/> via <see cref="Scene.Update"/>
/// </remarks>
public event ScriptAtTargetEvent OnScriptAtTargetEvent; public event ScriptAtTargetEvent OnScriptAtTargetEvent;
public delegate void ScriptNotAtTargetEvent(uint localID); public delegate void ScriptNotAtTargetEvent(uint localID);
/// <summary>
/// Triggered when an object has a motion target but has not arrived
/// within a tolerance distance.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerNotAtTargetEvent"/>
/// in <see cref="SceneObjectGroup.checkAtTargets"/>
/// via <see cref="SceneObjectGroup.ScheduleGroupForFullUpdate"/>,
/// <see cref="Scene.CheckAtTargets"/> via <see cref="Scene.Update"/>
/// </remarks>
public event ScriptNotAtTargetEvent OnScriptNotAtTargetEvent; public event ScriptNotAtTargetEvent OnScriptNotAtTargetEvent;
public delegate void ScriptAtRotTargetEvent(uint localID, uint handle, Quaternion targetrot, Quaternion atrot); public delegate void ScriptAtRotTargetEvent(uint localID, uint handle, Quaternion targetrot, Quaternion atrot);
/// <summary>
/// Triggered when an object has arrived within a tolerance rotation
/// of a rotation target.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerAtRotTargetEvent"/>
/// in <see cref="SceneObjectGroup.checkAtTargets"/>
/// via <see cref="SceneObjectGroup.ScheduleGroupForFullUpdate"/>,
/// <see cref="Scene.CheckAtTargets"/> via <see cref="Scene.Update"/>
/// </remarks>
public event ScriptAtRotTargetEvent OnScriptAtRotTargetEvent; public event ScriptAtRotTargetEvent OnScriptAtRotTargetEvent;
public delegate void ScriptNotAtRotTargetEvent(uint localID); public delegate void ScriptNotAtRotTargetEvent(uint localID);
/// <summary>
/// Triggered when an object has a rotation target but has not arrived
/// within a tolerance rotation.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerNotAtRotTargetEvent"/>
/// in <see cref="SceneObjectGroup.checkAtTargets"/>
/// via <see cref="SceneObjectGroup.ScheduleGroupForFullUpdate"/>,
/// <see cref="Scene.CheckAtTargets"/> via <see cref="Scene.Update"/>
/// </remarks>
public event ScriptNotAtRotTargetEvent OnScriptNotAtRotTargetEvent; public event ScriptNotAtRotTargetEvent OnScriptNotAtRotTargetEvent;
public delegate void ScriptColliding(uint localID, ColliderArgs colliders); public delegate void ScriptColliding(uint localID, ColliderArgs colliders);
/// <summary>
/// Triggered when a physical collision has started between a prim
/// and something other than the region terrain.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerScriptCollidingStart"/>
/// in <see cref="SceneObjectPart.SendCollisionEvent"/>
/// via <see cref="SceneObjectPart.PhysicsCollision"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
/// </remarks>
public event ScriptColliding OnScriptColliderStart; public event ScriptColliding OnScriptColliderStart;
/// <summary>
/// Triggered when something that previously collided with a prim has
/// not stopped colliding with it.
/// </summary>
/// <remarks>
/// <seealso cref="OnScriptColliderStart"/>
/// Triggered by <see cref="TriggerScriptColliding"/>
/// in <see cref="SceneObjectPart.SendCollisionEvent"/>
/// via <see cref="SceneObjectPart.PhysicsCollision"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
/// </remarks>
public event ScriptColliding OnScriptColliding; public event ScriptColliding OnScriptColliding;
/// <summary>
/// Triggered when something that previously collided with a prim has
/// stopped colliding with it.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerScriptCollidingEnd"/>
/// in <see cref="SceneObjectPart.SendCollisionEvent"/>
/// via <see cref="SceneObjectPart.PhysicsCollision"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
/// </remarks>
public event ScriptColliding OnScriptCollidingEnd; public event ScriptColliding OnScriptCollidingEnd;
/// <summary>
/// Triggered when a physical collision has started between an object
/// and the region terrain.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerScriptLandCollidingStart"/>
/// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
/// via <see cref="SceneObjectPart.PhysicsCollision"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
/// </remarks>
public event ScriptColliding OnScriptLandColliderStart; public event ScriptColliding OnScriptLandColliderStart;
/// <summary>
/// Triggered when an object that previously collided with the region
/// terrain has not yet stopped colliding with it.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerScriptLandColliding"/>
/// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
/// via <see cref="SceneObjectPart.PhysicsCollision"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
/// </remarks>
public event ScriptColliding OnScriptLandColliding; public event ScriptColliding OnScriptLandColliding;
/// <summary>
/// Triggered when an object that previously collided with the region
/// terrain has stopped colliding with it.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerScriptLandCollidingEnd"/>
/// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
/// via <see cref="SceneObjectPart.PhysicsCollision"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/>
/// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/>
/// </remarks>
public event ScriptColliding OnScriptLandColliderEnd; public event ScriptColliding OnScriptLandColliderEnd;
public delegate void OnMakeChildAgentDelegate(ScenePresence presence); public delegate void OnMakeChildAgentDelegate(ScenePresence presence);
/// <summary>
/// Triggered when an agent has been made a child agent of a scene.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerOnMakeChildAgent"/>
/// in <see cref="ScenePresence.MakeChildAgent"/>
/// via <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.CrossAgentToNewRegionAsync"/>,
/// <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.DoTeleport"/>,
/// <see cref="OpenSim.Region.CoreModules.InterGrid.KillAUser.ShutdownNoLogout"/>
/// </remarks>
public event OnMakeChildAgentDelegate OnMakeChildAgent; public event OnMakeChildAgentDelegate OnMakeChildAgent;
public delegate void OnSaveNewWindlightProfileDelegate(); public delegate void OnSaveNewWindlightProfileDelegate();
public delegate void OnSendNewWindlightProfileTargetedDelegate(RegionLightShareData wl, UUID user); public delegate void OnSendNewWindlightProfileTargetedDelegate(RegionLightShareData wl, UUID user);
/// <summary> /// <summary>
/// Triggered after the grunt work for adding a root agent to a
/// scene has been performed (resuming attachment scripts, physics,
/// animations etc.)
/// </summary>
/// <remarks>
/// This event is on the critical path for transferring an avatar from one region to another. Try and do /// This event is on the critical path for transferring an avatar from one region to another. Try and do
/// as little work on this event as possible, or do work asynchronously. /// as little work on this event as possible, or do work asynchronously.
/// </summary> /// Triggered after <see cref="OnSetRootAgentScene"/>
/// by <see cref="TriggerOnMakeRootAgent"/>
/// in <see cref="ScenePresence.MakeRootAgent"/>
/// via <see cref="Scene.AgentCrossing"/>
/// and <see cref="ScenePresence.CompleteMovement"/>
/// </remarks>
public event Action<ScenePresence> OnMakeRootAgent; public event Action<ScenePresence> OnMakeRootAgent;
public event OnSendNewWindlightProfileTargetedDelegate OnSendNewWindlightProfileTargeted; public event OnSendNewWindlightProfileTargetedDelegate OnSendNewWindlightProfileTargeted;
@ -425,9 +725,17 @@ namespace OpenSim.Region.Framework.Scenes
public event AvatarKillData OnAvatarKilled; public event AvatarKillData OnAvatarKilled;
public delegate void AvatarKillData(uint KillerLocalID, ScenePresence avatar); public delegate void AvatarKillData(uint KillerLocalID, ScenePresence avatar);
// public delegate void ScriptTimerEvent(uint localID, double timerinterval); /*
public delegate void ScriptTimerEvent(uint localID, double timerinterval);
// public event ScriptTimerEvent OnScriptTimerEvent; /// <summary>
/// Used to be triggered when the LSL timer event fires.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerTimerEvent"/>
/// via <see cref="SceneObjectPart.handleTimerAccounting"/>
/// </remarks>
public event ScriptTimerEvent OnScriptTimerEvent;
*/
public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour); public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour);
public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID); public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID);
@ -437,12 +745,27 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// Triggered when an object is added to the scene. /// Triggered when an object is added to the scene.
/// </summary> /// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerObjectAddedToScene"/>
/// in <see cref="Scene.AddNewSceneObject"/>,
/// <see cref="Scene.DuplicateObject"/>,
/// <see cref="Scene.doObjectDuplicateOnRay"/>
/// </remarks>
public event Action<SceneObjectGroup> OnObjectAddedToScene; public event Action<SceneObjectGroup> OnObjectAddedToScene;
/// <summary>
/// Delegate for <see cref="OnObjectBeingRemovedFromScene"/>
/// </summary>
/// <param name="obj">The object being removed from the scene</param>
public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
/// <summary> /// <summary>
/// Triggered when an object is removed from the scene. /// Triggered when an object is removed from the scene.
/// </summary> /// </summary>
public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj); /// <remarks>
/// Triggered by <see cref="TriggerObjectBeingRemovedFromScene"/>
/// in <see cref="Scene.DeleteSceneObject"/>
/// </remarks>
public event ObjectBeingRemovedFromScene OnObjectBeingRemovedFromScene; public event ObjectBeingRemovedFromScene OnObjectBeingRemovedFromScene;
public delegate void NoticeNoLandDataFromStorage(); public delegate void NoticeNoLandDataFromStorage();
@ -628,9 +951,28 @@ namespace OpenSim.Region.Framework.Scenes
public event PrimsLoaded OnPrimsLoaded; public event PrimsLoaded OnPrimsLoaded;
public delegate void TeleportStart(IClientAPI client, GridRegion destination, GridRegion finalDestination, uint teleportFlags, bool gridLogout); public delegate void TeleportStart(IClientAPI client, GridRegion destination, GridRegion finalDestination, uint teleportFlags, bool gridLogout);
/// <summary>
/// Triggered when a teleport starts
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerTeleportStart"/>
/// in <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.CreateAgent"/>
/// and <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.HGEntityTransferModule.CreateAgent"/>
/// via <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.DoTeleport"/>
/// </remarks>
public event TeleportStart OnTeleportStart; public event TeleportStart OnTeleportStart;
public delegate void TeleportFail(IClientAPI client, bool gridLogout); public delegate void TeleportFail(IClientAPI client, bool gridLogout);
/// <summary>
/// Trigered when a teleport fails.
/// </summary>
/// <remarks>
/// Triggered by <see cref="TriggerTeleportFail"/>
/// in <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.Fail"/>
/// via <see cref="OpenSim.Region.CoreModules.Framework.EntityTransfer.EntityTransferModule.DoTeleport"/>
/// </remarks>
public event TeleportFail OnTeleportFail; public event TeleportFail OnTeleportFail;
public class MoneyTransferArgs : EventArgs public class MoneyTransferArgs : EventArgs
@ -638,7 +980,9 @@ namespace OpenSim.Region.Framework.Scenes
public UUID sender; public UUID sender;
public UUID receiver; public UUID receiver;
// Always false. The SL protocol sucks. /// <summary>
/// Always false. The SL protocol sucks.
/// </summary>
public bool authenticated = false; public bool authenticated = false;
public int amount; public int amount;
@ -2133,7 +2477,11 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
// this lets us keep track of nasty script events like timer, etc. /// <summary>
/// this lets us keep track of nasty script events like timer, etc.
/// </summary>
/// <param name="objLocalID"></param>
/// <param name="Interval"></param>
public void TriggerTimerEvent(uint objLocalID, double Interval) public void TriggerTimerEvent(uint objLocalID, double Interval)
{ {
throw new NotImplementedException("TriggerTimerEvent was thought to be not used anymore and the registration for the event from scene object part has been commented out due to a memory leak"); throw new NotImplementedException("TriggerTimerEvent was thought to be not used anymore and the registration for the event from scene object part has been commented out due to a memory leak");

View File

@ -151,7 +151,8 @@ namespace OpenSim.Region.Framework.Scenes
// TODO: need to figure out how allow client agents but deny // TODO: need to figure out how allow client agents but deny
// root agents when ACL denies access to root agent // root agents when ACL denies access to root agent
public bool m_strictAccessControl = true; public bool m_strictAccessControl = true;
public int MaxUndoCount = 5;
public int MaxUndoCount { get; set; }
// Using this for RegionReady module to prevent LoginsDisabled from changing under our feet; // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
public bool LoginLock = false; public bool LoginLock = false;
@ -741,6 +742,8 @@ namespace OpenSim.Region.Framework.Scenes
//Animation states //Animation states
m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20);
PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims); PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims);
CollidablePrims = startupConfig.GetBoolean("collidable_prim", CollidablePrims); CollidablePrims = startupConfig.GetBoolean("collidable_prim", CollidablePrims);
@ -861,6 +864,8 @@ namespace OpenSim.Region.Framework.Scenes
} }
// FIXME: Ultimately this should be in a module. // FIXME: Ultimately this should be in a module.
SendPeriodicAppearanceUpdates = true;
IConfig appearanceConfig = m_config.Configs["Appearance"]; IConfig appearanceConfig = m_config.Configs["Appearance"];
if (appearanceConfig != null) if (appearanceConfig != null)
{ {

View File

@ -1119,14 +1119,6 @@ namespace OpenSim.Region.Framework.Scenes
parts[i].UUID = UUID.Random(); parts[i].UUID = UUID.Random();
} }
// helper provided for parts.
public int GetSceneMaxUndo()
{
if (m_scene != null)
return m_scene.MaxUndoCount;
return 5;
}
// justincc: I don't believe this hack is needed any longer, especially since the physics // justincc: I don't believe this hack is needed any longer, especially since the physics
// parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
// this method was preventing proper reload of scene objects. // this method was preventing proper reload of scene objects.
@ -2703,29 +2695,32 @@ namespace OpenSim.Region.Framework.Scenes
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
PhysicsActor pa = m_rootPart.PhysActor;
RootPart.StoreUndoState(true); RootPart.StoreUndoState(true);
if (Scene != null)
{
scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y)); scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y));
scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z)); scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z));
PhysicsActor pa = m_rootPart.PhysActor;
if (pa != null && pa.IsPhysical) if (pa != null && pa.IsPhysical)
{ {
scale.X = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.X)); scale.X = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.X));
scale.Y = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Y)); scale.Y = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Y));
scale.Z = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Z)); scale.Z = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Z));
} }
}
float x = (scale.X / RootPart.Scale.X); float x = (scale.X / RootPart.Scale.X);
float y = (scale.Y / RootPart.Scale.Y); float y = (scale.Y / RootPart.Scale.Y);
float z = (scale.Z / RootPart.Scale.Z); float z = (scale.Z / RootPart.Scale.Z);
SceneObjectPart[] parts; SceneObjectPart[] parts = m_parts.GetArray();
if (x > 1.0f || y > 1.0f || z > 1.0f)
if (Scene != null & (x > 1.0f || y > 1.0f || z > 1.0f))
{ {
parts = m_parts.GetArray();
for (int i = 0; i < parts.Length; i++) for (int i = 0; i < parts.Length; i++)
{ {
SceneObjectPart obPart = parts[i]; SceneObjectPart obPart = parts[i];
@ -2739,7 +2734,7 @@ namespace OpenSim.Region.Framework.Scenes
if (pa != null && pa.IsPhysical) if (pa != null && pa.IsPhysical)
{ {
if (oldSize.X * x > m_scene.m_maxPhys) if (oldSize.X * x > Scene.m_maxPhys)
{ {
f = m_scene.m_maxPhys / oldSize.X; f = m_scene.m_maxPhys / oldSize.X;
a = f / x; a = f / x;
@ -2747,7 +2742,7 @@ namespace OpenSim.Region.Framework.Scenes
y *= a; y *= a;
z *= a; z *= a;
} }
else if (oldSize.X * x < m_scene.m_minPhys) else if (oldSize.X * x < Scene.m_minPhys)
{ {
f = m_scene.m_minPhys / oldSize.X; f = m_scene.m_minPhys / oldSize.X;
a = f / x; a = f / x;
@ -2756,7 +2751,7 @@ namespace OpenSim.Region.Framework.Scenes
z *= a; z *= a;
} }
if (oldSize.Y * y > m_scene.m_maxPhys) if (oldSize.Y * y > Scene.m_maxPhys)
{ {
f = m_scene.m_maxPhys / oldSize.Y; f = m_scene.m_maxPhys / oldSize.Y;
a = f / y; a = f / y;
@ -2764,7 +2759,7 @@ namespace OpenSim.Region.Framework.Scenes
y *= a; y *= a;
z *= a; z *= a;
} }
else if (oldSize.Y * y < m_scene.m_minPhys) else if (oldSize.Y * y < Scene.m_minPhys)
{ {
f = m_scene.m_minPhys / oldSize.Y; f = m_scene.m_minPhys / oldSize.Y;
a = f / y; a = f / y;
@ -2773,7 +2768,7 @@ namespace OpenSim.Region.Framework.Scenes
z *= a; z *= a;
} }
if (oldSize.Z * z > m_scene.m_maxPhys) if (oldSize.Z * z > Scene.m_maxPhys)
{ {
f = m_scene.m_maxPhys / oldSize.Z; f = m_scene.m_maxPhys / oldSize.Z;
a = f / z; a = f / z;
@ -2781,7 +2776,7 @@ namespace OpenSim.Region.Framework.Scenes
y *= a; y *= a;
z *= a; z *= a;
} }
else if (oldSize.Z * z < m_scene.m_minPhys) else if (oldSize.Z * z < Scene.m_minPhys)
{ {
f = m_scene.m_minPhys / oldSize.Z; f = m_scene.m_minPhys / oldSize.Z;
a = f / z; a = f / z;
@ -2792,7 +2787,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
else else
{ {
if (oldSize.X * x > m_scene.m_maxNonphys) if (oldSize.X * x > Scene.m_maxNonphys)
{ {
f = m_scene.m_maxNonphys / oldSize.X; f = m_scene.m_maxNonphys / oldSize.X;
a = f / x; a = f / x;
@ -2800,7 +2795,7 @@ namespace OpenSim.Region.Framework.Scenes
y *= a; y *= a;
z *= a; z *= a;
} }
else if (oldSize.X * x < m_scene.m_minNonphys) else if (oldSize.X * x < Scene.m_minNonphys)
{ {
f = m_scene.m_minNonphys / oldSize.X; f = m_scene.m_minNonphys / oldSize.X;
a = f / x; a = f / x;
@ -2809,7 +2804,7 @@ namespace OpenSim.Region.Framework.Scenes
z *= a; z *= a;
} }
if (oldSize.Y * y > m_scene.m_maxNonphys) if (oldSize.Y * y > Scene.m_maxNonphys)
{ {
f = m_scene.m_maxNonphys / oldSize.Y; f = m_scene.m_maxNonphys / oldSize.Y;
a = f / y; a = f / y;
@ -2817,7 +2812,7 @@ namespace OpenSim.Region.Framework.Scenes
y *= a; y *= a;
z *= a; z *= a;
} }
else if (oldSize.Y * y < m_scene.m_minNonphys) else if (oldSize.Y * y < Scene.m_minNonphys)
{ {
f = m_scene.m_minNonphys / oldSize.Y; f = m_scene.m_minNonphys / oldSize.Y;
a = f / y; a = f / y;
@ -2826,7 +2821,7 @@ namespace OpenSim.Region.Framework.Scenes
z *= a; z *= a;
} }
if (oldSize.Z * z > m_scene.m_maxNonphys) if (oldSize.Z * z > Scene.m_maxNonphys)
{ {
f = m_scene.m_maxNonphys / oldSize.Z; f = m_scene.m_maxNonphys / oldSize.Z;
a = f / z; a = f / z;
@ -2834,7 +2829,7 @@ namespace OpenSim.Region.Framework.Scenes
y *= a; y *= a;
z *= a; z *= a;
} }
else if (oldSize.Z * z < m_scene.m_minNonphys) else if (oldSize.Z * z < Scene.m_minNonphys)
{ {
f = m_scene.m_minNonphys / oldSize.Z; f = m_scene.m_minNonphys / oldSize.Z;
a = f / z; a = f / z;
@ -2858,7 +2853,6 @@ namespace OpenSim.Region.Framework.Scenes
RootPart.Resize(prevScale); RootPart.Resize(prevScale);
// RootPart.IgnoreUndoUpdate = false; // RootPart.IgnoreUndoUpdate = false;
parts = m_parts.GetArray();
for (int i = 0; i < parts.Length; i++) for (int i = 0; i < parts.Length; i++)
{ {
SceneObjectPart obPart = parts[i]; SceneObjectPart obPart = parts[i];

View File

@ -266,8 +266,8 @@ namespace OpenSim.Region.Framework.Scenes
private string m_sitAnimation = "SIT"; private string m_sitAnimation = "SIT";
private string m_text = String.Empty; private string m_text = String.Empty;
private string m_touchName = String.Empty; private string m_touchName = String.Empty;
private readonly Stack<UndoState> m_undo = new Stack<UndoState>(5); private readonly List<UndoState> m_undo = new List<UndoState>(5);
private readonly Stack<UndoState> m_redo = new Stack<UndoState>(5); private readonly List<UndoState> m_redo = new List<UndoState>(5);
private bool m_passTouches = false; private bool m_passTouches = false;
private bool m_passCollisions = false; private bool m_passCollisions = false;
@ -2367,18 +2367,22 @@ namespace OpenSim.Region.Framework.Scenes
/// </remarks> /// </remarks>
/// <param name="scale"></param> /// <param name="scale"></param>
public void Resize(Vector3 scale) public void Resize(Vector3 scale)
{
PhysicsActor pa = PhysActor;
if (ParentGroup.Scene != null)
{ {
scale.X = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.X)); scale.X = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.X));
scale.Y = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Y)); scale.Y = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Y));
scale.Z = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Z)); scale.Z = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Z));
PhysicsActor pa = PhysActor;
if (pa != null && pa.IsPhysical) if (pa != null && pa.IsPhysical)
{ {
scale.X = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.X)); scale.X = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.X));
scale.Y = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Y)); scale.Y = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Y));
scale.Z = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Z)); scale.Z = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Z));
} }
}
// m_log.DebugFormat("[SCENE OBJECT PART]: Resizing {0} {1} to {2}", Name, LocalId, scale); // m_log.DebugFormat("[SCENE OBJECT PART]: Resizing {0} {1} to {2}", Name, LocalId, scale);
@ -3166,61 +3170,62 @@ namespace OpenSim.Region.Framework.Scenes
public void StoreUndoState(bool forGroup) public void StoreUndoState(bool forGroup)
{ {
if (!Undoing) if (ParentGroup == null || ParentGroup.Scene == null)
return;
if (Undoing)
{ {
if (!IgnoreUndoUpdate) // m_log.DebugFormat(
{ // "[SCENE OBJECT PART]: Ignoring undo store for {0} {1} since already undoing", Name, LocalId);
if (ParentGroup != null) return;
}
if (IgnoreUndoUpdate)
{ {
// m_log.DebugFormat("[SCENE OBJECT PART]: Ignoring undo store for {0} {1}", Name, LocalId);
return;
}
lock (m_undo) lock (m_undo)
{ {
if (m_undo.Count > 0) if (m_undo.Count > 0)
{ {
UndoState last = m_undo.Peek(); UndoState last = m_undo[m_undo.Count - 1];
if (last != null) if (last != null)
{ {
// TODO: May need to fix for group comparison // TODO: May need to fix for group comparison
if (last.Compare(this)) if (last.Compare(this))
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE OBJECT PART]: Not storing undo for {0} {1} since current state is same as last undo state, initial stack size {2}", // "[SCENE OBJECT PART]: Not storing undo for {0} {1} since current state is same as last undo state, initial stack size {2}",
// Name, LocalId, m_undo.Count); // Name, LocalId, m_undo.Count);
return; return;
} }
} }
} }
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE OBJECT PART]: Storing undo state for {0} {1}, forGroup {2}, initial stack size {3}", // "[SCENE OBJECT PART]: Storing undo state for {0} {1}, forGroup {2}, initial stack size {3}",
// Name, LocalId, forGroup, m_undo.Count); // Name, LocalId, forGroup, m_undo.Count);
if (ParentGroup.GetSceneMaxUndo() > 0) if (ParentGroup.Scene.MaxUndoCount > 0)
{ {
UndoState nUndo = new UndoState(this, forGroup); UndoState nUndo = new UndoState(this, forGroup);
m_undo.Push(nUndo); m_undo.Add(nUndo);
if (m_undo.Count > ParentGroup.Scene.MaxUndoCount)
m_undo.RemoveAt(0);
if (m_redo.Count > 0) if (m_redo.Count > 0)
m_redo.Clear(); m_redo.Clear();
// m_log.DebugFormat(
// "[SCENE OBJECT PART]: Stored undo state for {0} {1}, forGroup {2}, stack size now {3}",
// Name, LocalId, forGroup, m_undo.Count);
}
}
}
}
// else
// {
// m_log.DebugFormat("[SCENE OBJECT PART]: Ignoring undo store for {0} {1}", Name, LocalId);
// }
}
// else
// {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE OBJECT PART]: Ignoring undo store for {0} {1} since already undoing", Name, LocalId); // "[SCENE OBJECT PART]: Stored undo state for {0} {1}, forGroup {2}, stack size now {3}",
// } // Name, LocalId, forGroup, m_undo.Count);
}
}
} }
/// <summary> /// <summary>
@ -3245,13 +3250,12 @@ namespace OpenSim.Region.Framework.Scenes
if (m_undo.Count > 0) if (m_undo.Count > 0)
{ {
UndoState goback = m_undo.Pop(); UndoState goback = m_undo[m_undo.Count - 1];
m_undo.RemoveAt(m_undo.Count - 1);
if (goback != null)
{
UndoState nUndo = null; UndoState nUndo = null;
if (ParentGroup.GetSceneMaxUndo() > 0) if (ParentGroup.Scene.MaxUndoCount > 0)
{ {
nUndo = new UndoState(this, goback.ForGroup); nUndo = new UndoState(this, goback.ForGroup);
} }
@ -3259,7 +3263,11 @@ namespace OpenSim.Region.Framework.Scenes
goback.PlaybackState(this); goback.PlaybackState(this);
if (nUndo != null) if (nUndo != null)
m_redo.Push(nUndo); {
m_redo.Add(nUndo);
if (m_redo.Count > ParentGroup.Scene.MaxUndoCount)
m_redo.RemoveAt(0);
} }
} }
@ -3279,19 +3287,20 @@ namespace OpenSim.Region.Framework.Scenes
if (m_redo.Count > 0) if (m_redo.Count > 0)
{ {
UndoState gofwd = m_redo.Pop(); UndoState gofwd = m_redo[m_redo.Count - 1];
m_redo.RemoveAt(m_redo.Count - 1);
if (gofwd != null) if (ParentGroup.Scene.MaxUndoCount > 0)
{
if (ParentGroup.GetSceneMaxUndo() > 0)
{ {
UndoState nUndo = new UndoState(this, gofwd.ForGroup); UndoState nUndo = new UndoState(this, gofwd.ForGroup);
m_undo.Push(nUndo); m_undo.Add(nUndo);
if (m_undo.Count > ParentGroup.Scene.MaxUndoCount)
m_undo.RemoveAt(0);
} }
gofwd.PlayfwdState(this); gofwd.PlayfwdState(this);
}
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE OBJECT PART]: Handled redo request for {0} {1}, stack size now {2}", // "[SCENE OBJECT PART]: Handled redo request for {0} {1}, stack size now {2}",

View File

@ -62,8 +62,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Assert.That(g1Post.RootPart.Scale.X, Is.EqualTo(2)); Assert.That(g1Post.RootPart.Scale.X, Is.EqualTo(2));
Assert.That(g1Post.RootPart.Scale.Y, Is.EqualTo(3)); Assert.That(g1Post.RootPart.Scale.Y, Is.EqualTo(3));
Assert.That(g1Post.RootPart.Scale.Z, Is.EqualTo(4)); Assert.That(g1Post.RootPart.Scale.Z, Is.EqualTo(4));
Assert.That(g1Post.RootPart.UndoCount, Is.EqualTo(1));
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,184 @@
/*
* 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 NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.Framework.Scenes.Tests
{
/// <summary>
/// Tests for undo/redo
/// </summary>
public class SceneObjectUndoRedoTests : OpenSimTestCase
{
[Test]
public void TestUndoRedoResizeSceneObject()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
Vector3 firstSize = new Vector3(2, 3, 4);
Vector3 secondSize = new Vector3(5, 6, 7);
Scene scene = new SceneHelpers().SetupScene();
scene.MaxUndoCount = 20;
SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene);
// TODO: It happens to be the case that we are not storing undo states for SOPs which are not yet in a SOG,
// which is the way that AddSceneObject() sets up the object (i.e. it creates the SOP first). However,
// this is somewhat by chance. Really, we shouldn't be storing undo states at all if the object is not
// in a scene.
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0));
g1.GroupResize(firstSize);
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(1));
g1.GroupResize(secondSize);
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(2));
g1.RootPart.Undo();
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(1));
Assert.That(g1.GroupScale, Is.EqualTo(firstSize));
g1.RootPart.Redo();
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(2));
Assert.That(g1.GroupScale, Is.EqualTo(secondSize));
}
[Test]
public void TestUndoLimit()
{
TestHelpers.InMethod();
Vector3 firstSize = new Vector3(2, 3, 4);
Vector3 secondSize = new Vector3(5, 6, 7);
Vector3 thirdSize = new Vector3(8, 9, 10);
Vector3 fourthSize = new Vector3(11, 12, 13);
Scene scene = new SceneHelpers().SetupScene();
scene.MaxUndoCount = 2;
SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene);
g1.GroupResize(firstSize);
g1.GroupResize(secondSize);
g1.GroupResize(thirdSize);
g1.GroupResize(fourthSize);
g1.RootPart.Undo();
g1.RootPart.Undo();
g1.RootPart.Undo();
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0));
Assert.That(g1.GroupScale, Is.EqualTo(secondSize));
}
[Test]
public void TestNoUndoOnObjectsNotInScene()
{
TestHelpers.InMethod();
Vector3 firstSize = new Vector3(2, 3, 4);
Vector3 secondSize = new Vector3(5, 6, 7);
Vector3 thirdSize = new Vector3(8, 9, 10);
Vector3 fourthSize = new Vector3(11, 12, 13);
Scene scene = new SceneHelpers().SetupScene();
scene.MaxUndoCount = 20;
SceneObjectGroup g1 = SceneHelpers.CreateSceneObject(1, TestHelpers.ParseTail(0x1));
g1.GroupResize(firstSize);
g1.GroupResize(secondSize);
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0));
g1.RootPart.Undo();
Assert.That(g1.GroupScale, Is.EqualTo(secondSize));
}
[Test]
public void TestUndoBeyondAvailable()
{
TestHelpers.InMethod();
Vector3 newSize = new Vector3(2, 3, 4);
Scene scene = new SceneHelpers().SetupScene();
scene.MaxUndoCount = 20;
SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene);
Vector3 originalSize = g1.GroupScale;
g1.RootPart.Undo();
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0));
Assert.That(g1.GroupScale, Is.EqualTo(originalSize));
g1.GroupResize(newSize);
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(1));
Assert.That(g1.GroupScale, Is.EqualTo(newSize));
g1.RootPart.Undo();
g1.RootPart.Undo();
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0));
Assert.That(g1.GroupScale, Is.EqualTo(originalSize));
}
[Test]
public void TestRedoBeyondAvailable()
{
TestHelpers.InMethod();
Vector3 newSize = new Vector3(2, 3, 4);
Scene scene = new SceneHelpers().SetupScene();
scene.MaxUndoCount = 20;
SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene);
Vector3 originalSize = g1.GroupScale;
g1.RootPart.Redo();
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(0));
Assert.That(g1.GroupScale, Is.EqualTo(originalSize));
g1.GroupResize(newSize);
g1.RootPart.Undo();
g1.RootPart.Redo();
g1.RootPart.Redo();
Assert.That(g1.RootPart.UndoCount, Is.EqualTo(1));
Assert.That(g1.GroupScale, Is.EqualTo(newSize));
}
}
}

View File

@ -44,7 +44,7 @@ using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.Framework.Scenes.Tests namespace OpenSim.Region.Framework.Scenes.Tests
{ {
[TestFixture] [TestFixture]
public class SceneObjectUserGroupTests public class SceneObjectUserGroupTests : OpenSimTestCase
{ {
/// <summary> /// <summary>
/// Test share with group object functionality /// Test share with group object functionality
@ -54,7 +54,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
public void TestShareWithGroup() public void TestShareWithGroup()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001");

View File

@ -53,25 +53,22 @@ namespace OpenSim.Region.Framework.Scenes
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary> protected IAssetService m_assetService;
/// Asset cache used for gathering assets
/// </summary>
protected IAssetService m_assetCache;
/// <summary> // /// <summary>
/// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate // /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate
/// asset was found by the asset service. // /// asset was found by the asset service.
/// </summary> // /// </summary>
private AssetBase m_requestedObjectAsset; // private AssetBase m_requestedObjectAsset;
//
/// <summary> // /// <summary>
/// Signal whether we are currently waiting for the asset service to deliver an asset. // /// Signal whether we are currently waiting for the asset service to deliver an asset.
/// </summary> // /// </summary>
private bool m_waitingForObjectAsset; // private bool m_waitingForObjectAsset;
public UuidGatherer(IAssetService assetCache) public UuidGatherer(IAssetService assetCache)
{ {
m_assetCache = assetCache; m_assetService = assetCache;
} }
/// <summary> /// <summary>
@ -195,18 +192,18 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
/// <summary> // /// <summary>
/// The callback made when we request the asset for an object from the asset service. // /// The callback made when we request the asset for an object from the asset service.
/// </summary> // /// </summary>
private void AssetReceived(string id, Object sender, AssetBase asset) // private void AssetReceived(string id, Object sender, AssetBase asset)
{ // {
lock (this) // lock (this)
{ // {
m_requestedObjectAsset = asset; // m_requestedObjectAsset = asset;
m_waitingForObjectAsset = false; // m_waitingForObjectAsset = false;
Monitor.Pulse(this); // Monitor.Pulse(this);
} // }
} // }
/// <summary> /// <summary>
/// Get an asset synchronously, potentially using an asynchronous callback. If the /// Get an asset synchronously, potentially using an asynchronous callback. If the
@ -216,25 +213,29 @@ namespace OpenSim.Region.Framework.Scenes
/// <returns></returns> /// <returns></returns>
protected virtual AssetBase GetAsset(UUID uuid) protected virtual AssetBase GetAsset(UUID uuid)
{ {
m_waitingForObjectAsset = true; return m_assetService.Get(uuid.ToString());
m_assetCache.Get(uuid.ToString(), this, AssetReceived);
// The asset cache callback can either // XXX: Switching to do this synchronously where the call was async before but we always waited for it
// // to complete anyway!
// 1. Complete on the same thread (if the asset is already in the cache) or // m_waitingForObjectAsset = true;
// 2. Come in via a different thread (if we need to go fetch it). // m_assetCache.Get(uuid.ToString(), this, AssetReceived);
// //
// The code below handles both these alternatives. // // The asset cache callback can either
lock (this) // //
{ // // 1. Complete on the same thread (if the asset is already in the cache) or
if (m_waitingForObjectAsset) // // 2. Come in via a different thread (if we need to go fetch it).
{ // //
Monitor.Wait(this); // // The code below handles both these alternatives.
m_waitingForObjectAsset = false; // lock (this)
} // {
} // if (m_waitingForObjectAsset)
// {
return m_requestedObjectAsset; // Monitor.Wait(this);
// m_waitingForObjectAsset = false;
// }
// }
//
// return m_requestedObjectAsset;
} }
/// <summary> /// <summary>
@ -365,4 +366,47 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
public class HGUuidGatherer : UuidGatherer
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected string m_assetServerURL;
public HGUuidGatherer(IAssetService assetService, string assetServerURL)
: base(assetService)
{
m_assetServerURL = assetServerURL;
if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("="))
m_assetServerURL = m_assetServerURL + "/";
}
protected override AssetBase GetAsset(UUID uuid)
{
if (string.Empty == m_assetServerURL)
return base.GetAsset(uuid);
else
return FetchAsset(uuid);
}
public AssetBase FetchAsset(UUID assetID)
{
// Test if it's already here
AssetBase asset = m_assetService.Get(assetID.ToString());
if (asset == null)
{
// It's not, so fetch it from abroad
asset = m_assetService.Get(m_assetServerURL + assetID.ToString());
if (asset != null)
m_log.DebugFormat("[HGUUIDGatherer]: Copied asset {0} from {1} to local asset server", assetID, m_assetServerURL);
else
m_log.DebugFormat("[HGUUIDGatherer]: Failed to fetch asset {0} from {1}", assetID, m_assetServerURL);
}
//else
// m_log.DebugFormat("[HGUUIDGatherer]: Asset {0} from {1} was already here", assetID, m_assetServerURL);
return asset;
}
}
} }

View File

@ -231,12 +231,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null) if (m_server == null || m_baseNick == null || m_ircChannel == null || m_user == null)
throw new Exception("Invalid connector configuration"); throw new Exception("Invalid connector configuration");
// Generate an initial nickname if randomizing is enabled // Generate an initial nickname
if (m_randomizeNick) if (m_randomizeNick)
{
m_nick = m_baseNick + Util.RandomClass.Next(1, 99); m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
} else
m_nick = m_baseNick;
m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);

View File

@ -34,6 +34,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
public class BS6DofConstraint : BSConstraint public class BS6DofConstraint : BSConstraint
{ {
private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
// Create a btGeneric6DofConstraint // Create a btGeneric6DofConstraint
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 frame1, Quaternion frame1rot, Vector3 frame1, Quaternion frame1rot,
@ -44,11 +48,14 @@ public class BS6DofConstraint : BSConstraint
m_body1 = obj1; m_body1 = obj1;
m_body2 = obj2; m_body2 = obj2;
m_constraint = new BulletConstraint( m_constraint = new BulletConstraint(
BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
frame1, frame1rot, frame1, frame1rot,
frame2, frame2rot, frame2, frame2rot,
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
m_enabled = true; m_enabled = true;
world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
BSScene.DetailLogZero, world.worldID,
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
} }
public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
@ -58,19 +65,44 @@ public class BS6DofConstraint : BSConstraint
m_world = world; m_world = world;
m_body1 = obj1; m_body1 = obj1;
m_body2 = obj2; m_body2 = obj2;
if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero)
{
world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
BSScene.DetailLogZero, world.worldID,
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
"[BULLETSIM 6DOF CONSTRAINT]", world.worldID,
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
m_enabled = false;
}
else
{
m_constraint = new BulletConstraint( m_constraint = new BulletConstraint(
BulletSimAPI.Create6DofConstraintToPoint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
joinPoint, joinPoint,
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
if (m_constraint.ptr == IntPtr.Zero)
{
world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
LogHeader, obj1.ID, obj2.ID);
m_enabled = false;
}
else
{
m_enabled = true; m_enabled = true;
} }
}
}
public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
{ {
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
{ {
BulletSimAPI.SetFrames2(m_constraint.Ptr, frameA, frameArot, frameB, frameBrot); BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
ret = true; ret = true;
} }
return ret; return ret;
@ -81,9 +113,9 @@ public class BS6DofConstraint : BSConstraint
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
{ {
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
ret = true; ret = true;
} }
return ret; return ret;
@ -94,7 +126,7 @@ public class BS6DofConstraint : BSConstraint
bool ret = false; bool ret = false;
float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled) if (m_enabled)
ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff); ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff);
return ret; return ret;
} }
@ -103,7 +135,7 @@ public class BS6DofConstraint : BSConstraint
bool ret = false; bool ret = false;
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled) if (m_enabled)
ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce); ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
return ret; return ret;
} }
@ -111,7 +143,7 @@ public class BS6DofConstraint : BSConstraint
{ {
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.Ptr, threshold); ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
return ret; return ret;
} }
} }

View File

@ -28,7 +28,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using log4net; using log4net;
using OpenMetaverse; using OMV = OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
@ -39,48 +39,35 @@ public class BSCharacter : BSPhysObject
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS CHAR]"; private static readonly string LogHeader = "[BULLETS CHAR]";
public BSScene Scene { get; private set; }
private String _avName;
// private bool _stopped; // private bool _stopped;
private Vector3 _size; private OMV.Vector3 _size;
private Vector3 _scale; private OMV.Vector3 _scale;
private PrimitiveBaseShape _pbs; private PrimitiveBaseShape _pbs;
private uint _localID = 0;
private bool _grabbed; private bool _grabbed;
private bool _selected; private bool _selected;
private Vector3 _position; private OMV.Vector3 _position;
private float _mass; private float _mass;
public float _density; private float _avatarDensity;
public float _avatarVolume; private float _avatarVolume;
private Vector3 _force; private OMV.Vector3 _force;
private Vector3 _velocity; private OMV.Vector3 _velocity;
private Vector3 _torque; private OMV.Vector3 _torque;
private float _collisionScore; private float _collisionScore;
private Vector3 _acceleration; private OMV.Vector3 _acceleration;
private Quaternion _orientation; private OMV.Quaternion _orientation;
private int _physicsActorType; private int _physicsActorType;
private bool _isPhysical; private bool _isPhysical;
private bool _flying; private bool _flying;
private bool _setAlwaysRun; private bool _setAlwaysRun;
private bool _throttleUpdates; private bool _throttleUpdates;
private bool _isColliding; private bool _isColliding;
private long _collidingStep;
private bool _collidingGround;
private long _collidingGroundStep;
private bool _collidingObj; private bool _collidingObj;
private bool _floatOnWater; private bool _floatOnWater;
private Vector3 _rotationalVelocity; private OMV.Vector3 _rotationalVelocity;
private bool _kinematic; private bool _kinematic;
private float _buoyancy; private float _buoyancy;
public override BulletBody BSBody { get; set; } private OMV.Vector3 _PIDTarget;
public override BulletShape BSShape { get; set; }
public override BSLinkset Linkset { get; set; }
private int _subscribedEventsMs = 0;
private int _nextCollisionOkTime = 0;
private Vector3 _PIDTarget;
private bool _usePID; private bool _usePID;
private float _PIDTau; private float _PIDTau;
private bool _useHoverPID; private bool _useHoverPID;
@ -88,28 +75,26 @@ public class BSCharacter : BSPhysObject
private PIDHoverType _PIDHoverType; private PIDHoverType _PIDHoverType;
private float _PIDHoverTao; private float _PIDHoverTao;
public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
{ {
_localID = localID; base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
_avName = avName;
Scene = parent_scene;
_physicsActorType = (int)ActorTypes.Agent; _physicsActorType = (int)ActorTypes.Agent;
_position = pos; _position = pos;
_size = size; _size = size;
_flying = isFlying; _flying = isFlying;
_orientation = Quaternion.Identity; _orientation = OMV.Quaternion.Identity;
_velocity = Vector3.Zero; _velocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying); _buoyancy = ComputeBuoyancyFromFlying(isFlying);
// The dimensions of the avatar capsule are kept in the scale. // The dimensions of the avatar capsule are kept in the scale.
// Physics creates a unit capsule which is scaled by the physics engine. // Physics creates a unit capsule which is scaled by the physics engine.
_scale = new Vector3(Scene.Params.avatarCapsuleRadius, Scene.Params.avatarCapsuleRadius, size.Z); ComputeAvatarScale(_size);
_density = Scene.Params.avatarDensity; _avatarDensity = PhysicsScene.Params.avatarDensity;
ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale // set _avatarVolume and _mass based on capsule size, _density and _scale
ComputeAvatarVolumeAndMass();
Linkset = new BSLinkset(Scene, this);
ShapeData shapeData = new ShapeData(); ShapeData shapeData = new ShapeData();
shapeData.ID = _localID; shapeData.ID = LocalID;
shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
shapeData.Position = _position; shapeData.Position = _position;
shapeData.Rotation = _orientation; shapeData.Rotation = _orientation;
@ -118,21 +103,25 @@ public class BSCharacter : BSPhysObject
shapeData.Mass = _mass; shapeData.Mass = _mass;
shapeData.Buoyancy = _buoyancy; shapeData.Buoyancy = _buoyancy;
shapeData.Static = ShapeData.numericFalse; shapeData.Static = ShapeData.numericFalse;
shapeData.Friction = Scene.Params.avatarFriction; shapeData.Friction = PhysicsScene.Params.avatarFriction;
shapeData.Restitution = Scene.Params.avatarRestitution; shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
// do actual create at taint time // do actual create at taint time
Scene.TaintedObject("BSCharacter.create", delegate() PhysicsScene.TaintedObject("BSCharacter.create", delegate()
{ {
DetailLog("{0},BSCharacter.create", _localID); DetailLog("{0},BSCharacter.create,taint", LocalID);
BulletSimAPI.CreateObject(Scene.WorldID, shapeData); BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);
// Set the buoyancy for flying. This will be refactored when all the settings happen in C# // Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy); // If not set at creation, the avatar will stop flying when created after crossing a region boundry.
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(Scene.World.Ptr, LocalID)); BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));
// This works here because CreateObject has already put the character into the physical world.
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
(uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
}); });
return; return;
} }
@ -140,9 +129,9 @@ public class BSCharacter : BSPhysObject
public override void Destroy() public override void Destroy()
{ {
DetailLog("{0},BSCharacter.Destroy", LocalID); DetailLog("{0},BSCharacter.Destroy", LocalID);
Scene.TaintedObject("BSCharacter.destroy", delegate() PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
{ {
BulletSimAPI.DestroyObject(Scene.WorldID, _localID); BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
}); });
} }
@ -154,26 +143,26 @@ public class BSCharacter : BSPhysObject
public override bool Stopped { public override bool Stopped {
get { return false; } get { return false; }
} }
public override Vector3 Size { public override OMV.Vector3 Size {
get get
{ {
// Avatar capsule size is kept in the scale parameter. // Avatar capsule size is kept in the scale parameter.
return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
} }
set { set {
// When an avatar's size is set, only the height is changed // When an avatar's size is set, only the height is changed
// and that really only depends on the radius. // and that really only depends on the radius.
_size = value; _size = value;
_scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); ComputeAvatarScale(_size);
// TODO: something has to be done with the avatar's vertical position // TODO: something has to be done with the avatar's vertical position
ComputeAvatarVolumeAndMass(); ComputeAvatarVolumeAndMass();
Scene.TaintedObject("BSCharacter.setSize", delegate() PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
{ {
BulletSimAPI.SetObjectScaleMass(Scene.WorldID, LocalID, _scale, _mass, true); BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true);
}); });
} }
@ -182,11 +171,6 @@ public class BSCharacter : BSPhysObject
set { _pbs = value; set { _pbs = value;
} }
} }
public override uint LocalID {
set { _localID = value;
}
get { return _localID; }
}
public override bool Grabbed { public override bool Grabbed {
set { _grabbed = value; set { _grabbed = value;
} }
@ -198,9 +182,27 @@ public class BSCharacter : BSPhysObject
public override void CrossingFailure() { return; } public override void CrossingFailure() { return; }
public override void link(PhysicsActor obj) { return; } public override void link(PhysicsActor obj) { return; }
public override void delink() { return; } public override void delink() { return; }
public override void LockAngularMotion(Vector3 axis) { return; }
public override Vector3 Position { // Set motion values to zero.
// Do it to the properties so the values get set in the physics engine.
// Push the setting of the values to the viewer.
// Called at taint time!
public override void ZeroMotion()
{
_velocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties directly into the physics engine
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
BulletSimAPI.ClearForces2(BSBody.ptr);
}
public override void LockAngularMotion(OMV.Vector3 axis) { return; }
public override OMV.Vector3 Position {
get { get {
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
return _position; return _position;
@ -209,10 +211,10 @@ public class BSCharacter : BSPhysObject
_position = value; _position = value;
PositionSanityCheck(); PositionSanityCheck();
Scene.TaintedObject("BSCharacter.setPosition", delegate() PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
{ {
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
}); });
} }
} }
@ -225,7 +227,7 @@ public class BSCharacter : BSPhysObject
bool ret = false; bool ret = false;
// If below the ground, move the avatar up // If below the ground, move the avatar up
float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
if (Position.Z < terrainHeight) if (Position.Z < terrainHeight)
{ {
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
@ -247,10 +249,10 @@ public class BSCharacter : BSPhysObject
{ {
// The new position value must be pushed into the physics engine but we can't // The new position value must be pushed into the physics engine but we can't
// just assign to "Position" because of potential call loops. // just assign to "Position" because of potential call loops.
Scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate() PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
{ {
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
}); });
ret = true; ret = true;
} }
@ -266,15 +268,15 @@ public class BSCharacter : BSPhysObject
// used when we only want this prim's mass and not the linkset thing // used when we only want this prim's mass and not the linkset thing
public override float MassRaw { get {return _mass; } } public override float MassRaw { get {return _mass; } }
public override Vector3 Force { public override OMV.Vector3 Force {
get { return _force; } get { return _force; }
set { set {
_force = value; _force = value;
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
Scene.TaintedObject("BSCharacter.SetForce", delegate() PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
{ {
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force); BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
}); });
} }
} }
@ -284,28 +286,28 @@ public class BSCharacter : BSPhysObject
set { return; } set { return; }
} }
public override void VehicleFloatParam(int param, float value) { } public override void VehicleFloatParam(int param, float value) { }
public override void VehicleVectorParam(int param, Vector3 value) {} public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
public override void VehicleRotationParam(int param, Quaternion rotation) { } public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
public override void VehicleFlags(int param, bool remove) { } public override void VehicleFlags(int param, bool remove) { }
// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
public override void SetVolumeDetect(int param) { return; } public override void SetVolumeDetect(int param) { return; }
public override Vector3 GeometricCenter { get { return Vector3.Zero; } } public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
public override Vector3 CenterOfMass { get { return Vector3.Zero; } } public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
public override Vector3 Velocity { public override OMV.Vector3 Velocity {
get { return _velocity; } get { return _velocity; }
set { set {
_velocity = value; _velocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
Scene.TaintedObject("BSCharacter.setVelocity", delegate() PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
{ {
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetObjectVelocity(Scene.WorldID, _localID, _velocity); BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
}); });
} }
} }
public override Vector3 Torque { public override OMV.Vector3 Torque {
get { return _torque; } get { return _torque; }
set { _torque = value; set { _torque = value;
} }
@ -315,19 +317,19 @@ public class BSCharacter : BSPhysObject
set { _collisionScore = value; set { _collisionScore = value;
} }
} }
public override Vector3 Acceleration { public override OMV.Vector3 Acceleration {
get { return _acceleration; } get { return _acceleration; }
set { _acceleration = value; } set { _acceleration = value; }
} }
public override Quaternion Orientation { public override OMV.Quaternion Orientation {
get { return _orientation; } get { return _orientation; }
set { set {
_orientation = value; _orientation = value;
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
Scene.TaintedObject("BSCharacter.setOrientation", delegate() PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
{ {
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation); BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
}); });
} }
} }
@ -364,12 +366,12 @@ public class BSCharacter : BSPhysObject
set { _throttleUpdates = value; } set { _throttleUpdates = value; }
} }
public override bool IsColliding { public override bool IsColliding {
get { return (_collidingStep == Scene.SimulationStep); } get { return (CollidingStep == PhysicsScene.SimulationStep); }
set { _isColliding = value; } set { _isColliding = value; }
} }
public override bool CollidingGround { public override bool CollidingGround {
get { return (_collidingGroundStep == Scene.SimulationStep); } get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
set { _collidingGround = value; } set { CollidingGround = value; }
} }
public override bool CollidingObj { public override bool CollidingObj {
get { return _collidingObj; } get { return _collidingObj; }
@ -378,7 +380,7 @@ public class BSCharacter : BSPhysObject
public override bool FloatOnWater { public override bool FloatOnWater {
set { _floatOnWater = value; } set { _floatOnWater = value; }
} }
public override Vector3 RotationalVelocity { public override OMV.Vector3 RotationalVelocity {
get { return _rotationalVelocity; } get { return _rotationalVelocity; }
set { _rotationalVelocity = value; } set { _rotationalVelocity = value; }
} }
@ -390,16 +392,16 @@ public class BSCharacter : BSPhysObject
public override float Buoyancy { public override float Buoyancy {
get { return _buoyancy; } get { return _buoyancy; }
set { _buoyancy = value; set { _buoyancy = value;
Scene.TaintedObject("BSCharacter.setBuoyancy", delegate() PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
{ {
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy); BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
}); });
} }
} }
// Used for MoveTo // Used for MoveTo
public override Vector3 PIDTarget { public override OMV.Vector3 PIDTarget {
set { _PIDTarget = value; } set { _PIDTarget = value; }
} }
public override bool PIDActive { public override bool PIDActive {
@ -425,22 +427,22 @@ public class BSCharacter : BSPhysObject
} }
// For RotLookAt // For RotLookAt
public override Quaternion APIDTarget { set { return; } } public override OMV.Quaternion APIDTarget { set { return; } }
public override bool APIDActive { set { return; } } public override bool APIDActive { set { return; } }
public override float APIDStrength { set { return; } } public override float APIDStrength { set { return; } }
public override float APIDDamping { set { return; } } public override float APIDDamping { set { return; } }
public override void AddForce(Vector3 force, bool pushforce) { public override void AddForce(OMV.Vector3 force, bool pushforce) {
if (force.IsFinite()) if (force.IsFinite())
{ {
_force.X += force.X; _force.X += force.X;
_force.Y += force.Y; _force.Y += force.Y;
_force.Z += force.Z; _force.Z += force.Z;
// m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
Scene.TaintedObject("BSCharacter.AddForce", delegate() PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
{ {
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
BulletSimAPI.SetObjectForce2(BSBody.Ptr, _force); BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
}); });
} }
else else
@ -450,42 +452,19 @@ public class BSCharacter : BSPhysObject
//m_lastUpdateSent = false; //m_lastUpdateSent = false;
} }
public override void AddAngularForce(Vector3 force, bool pushforce) { public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
} }
public override void SetMomentum(Vector3 momentum) { public override void SetMomentum(OMV.Vector3 momentum) {
} }
// Turn on collision events at a rate no faster than one every the given milliseconds private void ComputeAvatarScale(OMV.Vector3 size)
public override void SubscribeEvents(int ms) {
_subscribedEventsMs = ms;
if (ms > 0)
{ {
// make sure first collision happens _scale.X = PhysicsScene.Params.avatarCapsuleRadius;
_nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; _scale.Y = PhysicsScene.Params.avatarCapsuleRadius;
Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate() // The 1.15 came from ODE but it seems to cause the avatar to float off the ground
{ // _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); _scale.Z = (_size.Z) - (_scale.X + _scale.Y);
});
}
}
public override void ZeroMotion()
{
return;
}
// Stop collision events
public override void UnSubscribeEvents() {
_subscribedEventsMs = 0;
Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate()
{
BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
// Return 'true' if someone has subscribed to events
public override bool SubscribedEvents() {
return (_subscribedEventsMs > 0);
} }
// set _avatarVolume and _mass based on capsule size, _density and _scale // set _avatarVolume and _mass based on capsule size, _density and _scale
@ -502,7 +481,7 @@ public class BSCharacter : BSPhysObject
* Math.Min(_scale.X, _scale.Y) * Math.Min(_scale.X, _scale.Y)
* _scale.Y // plus the volume of the capsule end caps * _scale.Y // plus the volume of the capsule end caps
); );
_mass = _density * _avatarVolume; _mass = _avatarDensity * _avatarVolume;
} }
// The physics engine says that properties have updated. Update same and inform // The physics engine says that properties have updated. Update same and inform
@ -520,67 +499,9 @@ public class BSCharacter : BSPhysObject
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds. // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
PositionSanityCheck2(); PositionSanityCheck2();
float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug float heightHere = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}", DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere); LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere);
} }
// Called by the scene when a collision with this object is reported
// The collision, if it should be reported to the character, is placed in a collection
// that will later be sent to the simulator when SendCollisions() is called.
CollisionEventUpdate collisionCollection = null;
public override bool Collide(uint collidingWith, BSPhysObject collidee, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
{
bool ret = false;
// The following makes IsColliding() and IsCollidingGround() work
_collidingStep = Scene.SimulationStep;
if (collidingWith <= Scene.TerrainManager.HighestTerrainID)
{
_collidingGroundStep = Scene.SimulationStep;
}
// DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
// throttle collisions to the rate specified in the subscription
if (SubscribedEvents()) {
int nowTime = Scene.SimulationNowTime;
if (nowTime >= _nextCollisionOkTime) {
_nextCollisionOkTime = nowTime + _subscribedEventsMs;
if (collisionCollection == null)
collisionCollection = new CollisionEventUpdate();
collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
ret = true;
}
}
return ret;
}
public override void SendCollisions()
{
/*
if (collisionCollection != null && collisionCollection.Count > 0)
{
base.SendCollisionUpdate(collisionCollection);
collisionCollection = null;
}
*/
// Kludge to make a collision call even if there are no collisions.
// This causes the avatar animation to get updated.
if (collisionCollection == null)
collisionCollection = new CollisionEventUpdate();
base.SendCollisionUpdate(collisionCollection);
// If there were any collisions in the collection, make sure we don't use the
// same instance next time.
if (collisionCollection.Count > 0)
collisionCollection = null;
// End kludge
}
// Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args)
{
Scene.PhysicsLogging.Write(msg, args);
}
} }
} }

View File

@ -49,20 +49,23 @@ public abstract class BSConstraint : IDisposable
if (m_enabled) if (m_enabled)
{ {
m_enabled = false; m_enabled = false;
bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr); bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
m_constraint.Ptr = System.IntPtr.Zero; m_constraint.ptr = System.IntPtr.Zero;
} }
} }
public BulletBody Body1 { get { return m_body1; } } public BulletBody Body1 { get { return m_body1; } }
public BulletBody Body2 { get { return m_body2; } } public BulletBody Body2 { get { return m_body2; } }
public BulletConstraint Constraint { get { return m_constraint; } }
public abstract ConstraintType Type { get; }
public virtual bool SetLinearLimits(Vector3 low, Vector3 high) public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
{ {
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high); ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
return ret; return ret;
} }
@ -70,7 +73,7 @@ public abstract class BSConstraint : IDisposable
{ {
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high); ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
return ret; return ret;
} }
@ -79,7 +82,7 @@ public abstract class BSConstraint : IDisposable
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
{ {
BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.Ptr, cnt); BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
ret = true; ret = true;
} }
return ret; return ret;
@ -91,7 +94,7 @@ public abstract class BSConstraint : IDisposable
if (m_enabled) if (m_enabled)
{ {
// Recompute the internal transforms // Recompute the internal transforms
BulletSimAPI.CalculateTransforms2(m_constraint.Ptr); BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
ret = true; ret = true;
} }
return ret; return ret;
@ -110,11 +113,11 @@ public abstract class BSConstraint : IDisposable
// Setting an object's mass to zero (making it static like when it's selected) // Setting an object's mass to zero (making it static like when it's selected)
// automatically disables the constraints. // automatically disables the constraints.
// If the link is enabled, be sure to set the constraint itself to enabled. // If the link is enabled, be sure to set the constraint itself to enabled.
BulletSimAPI.SetConstraintEnable2(m_constraint.Ptr, m_world.scene.NumericBool(true)); BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
} }
else else
{ {
m_world.scene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID);
} }
} }
return ret; return ret;

View File

@ -54,18 +54,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSDynamics public class BSDynamics
{ {
private int frcount = 0; // Used to limit dynamics debug output to private BSScene PhysicsScene { get; set; }
// every 100th frame // the prim this dynamic controller belongs to
private BSPrim Prim { get; set; }
private BSScene m_physicsScene;
private BSPrim m_prim; // the prim this dynamic controller belongs to
// Vehicle properties // Vehicle properties
private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind public Vehicle Type { get; set; }
public Vehicle Type
{
get { return m_type; }
}
// private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
// HOVER_TERRAIN_ONLY // HOVER_TERRAIN_ONLY
@ -126,14 +121,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
public BSDynamics(BSScene myScene, BSPrim myPrim) public BSDynamics(BSScene myScene, BSPrim myPrim)
{ {
m_physicsScene = myScene; PhysicsScene = myScene;
m_prim = myPrim; Prim = myPrim;
m_type = Vehicle.TYPE_NONE; Type = Vehicle.TYPE_NONE;
}
// Return 'true' if this vehicle is doing vehicle things
public bool IsActive
{
get { return Type != Vehicle.TYPE_NONE; }
} }
internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
{ {
VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
switch (pParam) switch (pParam)
{ {
case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
@ -232,7 +233,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
{ {
VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
switch (pParam) switch (pParam)
{ {
case Vehicle.ANGULAR_FRICTION_TIMESCALE: case Vehicle.ANGULAR_FRICTION_TIMESCALE:
@ -267,7 +268,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
{ {
VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
switch (pParam) switch (pParam)
{ {
case Vehicle.REFERENCE_FRAME: case Vehicle.REFERENCE_FRAME:
@ -281,7 +282,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessVehicleFlags(int pParam, bool remove) internal void ProcessVehicleFlags(int pParam, bool remove)
{ {
VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove); VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
VehicleFlag parm = (VehicleFlag)pParam; VehicleFlag parm = (VehicleFlag)pParam;
if (remove) if (remove)
{ {
@ -301,9 +302,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessTypeChange(Vehicle pType) internal void ProcessTypeChange(Vehicle pType)
{ {
VDetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType); VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
// Set Defaults For Type // Set Defaults For Type
m_type = pType; Type = pType;
switch (pType) switch (pType)
{ {
case Vehicle.TYPE_NONE: case Vehicle.TYPE_NONE:
@ -465,26 +466,37 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
}//end SetDefaultsForType }//end SetDefaultsForType
// Some of the properties of this prim may have changed.
// Do any updating needed for a vehicle
public void Refresh()
{
if (Type == Vehicle.TYPE_NONE) return;
// Set the prim's inertia to zero. The vehicle code handles that and this
// removes the torque action introduced by Bullet.
Vector3 inertia = Vector3.Zero;
BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
}
// One step of the vehicle properties for the next 'pTimestep' seconds. // One step of the vehicle properties for the next 'pTimestep' seconds.
internal void Step(float pTimestep) internal void Step(float pTimestep)
{ {
if (m_type == Vehicle.TYPE_NONE) return; if (!IsActive) return;
frcount++; // used to limit debug comment output
if (frcount > 100)
frcount = 0;
MoveLinear(pTimestep); MoveLinear(pTimestep);
MoveAngular(pTimestep); MoveAngular(pTimestep);
LimitRotation(pTimestep); LimitRotation(pTimestep);
// remember the position so next step we can limit absolute movement effects // remember the position so next step we can limit absolute movement effects
m_lastPositionVector = m_prim.Position; m_lastPositionVector = Prim.Position;
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity); Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity);
}// end Step }// end Step
// Apply the effect of the linear motor.
// Also does hover and float.
private void MoveLinear(float pTimestep) private void MoveLinear(float pTimestep)
{ {
// m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates
@ -520,18 +532,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_linearMotorDirection *= keepfraction; m_linearMotorDirection *= keepfraction;
VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}", VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
m_prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector); Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
} }
else else
{ {
// if what remains of direction is very small, zero it. // if what remains of direction is very small, zero it.
m_linearMotorDirection = Vector3.Zero; m_linearMotorDirection = Vector3.Zero;
m_lastLinearVelocityVector = Vector3.Zero; m_lastLinearVelocityVector = Vector3.Zero;
VDetailLog("{0},MoveLinear,zeroed", m_prim.LocalID); VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
} }
// convert requested object velocity to object relative vector // convert requested object velocity to object relative vector
Quaternion rotq = m_prim.Orientation; Quaternion rotq = Prim.Orientation;
m_newVelocity = m_lastLinearVelocityVector * rotq; m_newVelocity = m_lastLinearVelocityVector * rotq;
// Add the various forces into m_dir which will be our new direction vector (velocity) // Add the various forces into m_dir which will be our new direction vector (velocity)
@ -539,7 +551,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// add Gravity and Buoyancy // add Gravity and Buoyancy
// There is some gravity, make a gravity force vector that is applied after object velocity. // There is some gravity, make a gravity force vector that is applied after object velocity.
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
Vector3 grav = m_prim.Scene.DefaultGravity * (m_prim.Mass * (1f - m_VehicleBuoyancy)); Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy));
/* /*
* RA: Not sure why one would do this * RA: Not sure why one would do this
@ -548,11 +560,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
*/ */
Vector3 pos = m_prim.Position; Vector3 pos = Prim.Position;
// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
// If below the terrain, move us above the ground a little. // If below the terrain, move us above the ground a little.
float terrainHeight = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos); float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
// Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
// Vector3 rotatedSize = m_prim.Size * m_prim.Orientation; // Vector3 rotatedSize = m_prim.Size * m_prim.Orientation;
@ -560,8 +572,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if (pos.Z < terrainHeight) if (pos.Z < terrainHeight)
{ {
pos.Z = terrainHeight + 2; pos.Z = terrainHeight + 2;
m_prim.Position = pos; Prim.Position = pos;
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", m_prim.LocalID, terrainHeight, pos); VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
} }
// Check if hovering // Check if hovering
@ -570,7 +582,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// We should hover, get the target height // We should hover, get the target height
if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
{ {
m_VhoverTargetHeight = m_prim.Scene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
} }
if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{ {
@ -590,7 +602,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
{ {
m_prim.Position = pos; Prim.Position = pos;
} }
} }
else else
@ -608,7 +620,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
} }
VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
} }
Vector3 posChange = pos - m_lastPositionVector; Vector3 posChange = pos - m_lastPositionVector;
@ -642,9 +654,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
if (changed) if (changed)
{ {
m_prim.Position = pos; Prim.Position = pos;
VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
m_prim.LocalID, m_BlockingEndPoint, posChange, pos); Prim.LocalID, m_BlockingEndPoint, posChange, pos);
} }
} }
@ -664,7 +676,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
float postemp = (pos.Z - terrainHeight); float postemp = (pos.Z - terrainHeight);
if (postemp > 2.5f) if (postemp > 2.5f)
grav.Z = (float)(grav.Z * 1.037125); grav.Z = (float)(grav.Z * 1.037125);
VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav); VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav);
} }
if ((m_flags & (VehicleFlag.NO_X)) != 0) if ((m_flags & (VehicleFlag.NO_X)) != 0)
m_newVelocity.X = 0; m_newVelocity.X = 0;
@ -674,7 +686,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_newVelocity.Z = 0; m_newVelocity.Z = 0;
// Apply velocity // Apply velocity
m_prim.Velocity = m_newVelocity; Prim.Velocity = m_newVelocity;
// apply gravity force // apply gravity force
// Why is this set here? The physics engine already does gravity. // Why is this set here? The physics engine already does gravity.
// m_prim.AddForce(grav, false); // m_prim.AddForce(grav, false);
@ -684,10 +696,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_lastLinearVelocityVector *= keepFraction; m_lastLinearVelocityVector *= keepFraction;
VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}", VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
m_prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction); Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
} // end MoveLinear() } // end MoveLinear()
// Apply the effect of the angular motor.
private void MoveAngular(float pTimestep) private void MoveAngular(float pTimestep)
{ {
// m_angularMotorDirection // angular velocity requested by LSL motor // m_angularMotorDirection // angular velocity requested by LSL motor
@ -699,7 +712,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// m_lastAngularVelocity // what was last applied to body // m_lastAngularVelocity // what was last applied to body
// Get what the body is doing, this includes 'external' influences // Get what the body is doing, this includes 'external' influences
Vector3 angularVelocity = m_prim.RotationalVelocity; Vector3 angularVelocity = Prim.RotationalVelocity;
if (m_angularMotorApply > 0) if (m_angularMotorApply > 0)
{ {
@ -716,7 +729,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}", VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}",
m_prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity); Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity);
// This is done so that if script request rate is less than phys frame rate the expected // This is done so that if script request rate is less than phys frame rate the expected
// velocity may still be acheived. // velocity may still be acheived.
@ -737,7 +750,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep); float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep);
// get present body rotation // get present body rotation
Quaternion rotq = m_prim.Orientation; Quaternion rotq = Prim.Orientation;
// make a vector pointing up // make a vector pointing up
Vector3 verterr = Vector3.Zero; Vector3 verterr = Vector3.Zero;
verterr.Z = 1.0f; verterr.Z = 1.0f;
@ -767,7 +780,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
vertattr.Y += bounce * angularVelocity.Y; vertattr.Y += bounce * angularVelocity.Y;
VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
m_prim.LocalID, verterr, bounce, vertattr); Prim.LocalID, verterr, bounce, vertattr);
} // else vertical attractor is off } // else vertical attractor is off
@ -784,13 +797,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
m_lastAngularVelocity.X = 0; m_lastAngularVelocity.X = 0;
m_lastAngularVelocity.Y = 0; m_lastAngularVelocity.Y = 0;
VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
} }
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
{ {
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
} }
// apply friction // apply friction
@ -798,14 +811,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
// Apply to the body // Apply to the body
m_prim.RotationalVelocity = m_lastAngularVelocity; Prim.RotationalVelocity = m_lastAngularVelocity;
VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity); VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
} //end MoveAngular } //end MoveAngular
internal void LimitRotation(float timestep) internal void LimitRotation(float timestep)
{ {
Quaternion rotq = m_prim.Orientation; Quaternion rotq = Prim.Orientation;
Quaternion m_rot = rotq; Quaternion m_rot = rotq;
bool changed = false; bool changed = false;
if (m_RollreferenceFrame != Quaternion.Identity) if (m_RollreferenceFrame != Quaternion.Identity)
@ -840,8 +853,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
if (changed) if (changed)
{ {
m_prim.Orientation = m_rot; Prim.Orientation = m_rot;
VDetailLog("{0},LimitRotation,done,orig={1},new={2}", m_prim.LocalID, rotq, m_rot); VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
} }
} }
@ -849,8 +862,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Invoke the detailed logger and output something if it's enabled. // Invoke the detailed logger and output something if it's enabled.
private void VDetailLog(string msg, params Object[] args) private void VDetailLog(string msg, params Object[] args)
{ {
if (m_prim.Scene.VehicleLoggingEnabled) if (Prim.PhysicsScene.VehicleLoggingEnabled)
m_prim.Scene.PhysicsLogging.Write(msg, args); Prim.PhysicsScene.PhysicsLogging.Write(msg, args);
} }
} }
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
@ -34,6 +34,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
class BSHingeConstraint : BSConstraint class BSHingeConstraint : BSConstraint
{ {
public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 pivotInA, Vector3 pivotInB, Vector3 pivotInA, Vector3 pivotInB,
Vector3 axisInA, Vector3 axisInB, Vector3 axisInA, Vector3 axisInB,
@ -43,7 +45,7 @@ class BSHingeConstraint : BSConstraint
m_body1 = obj1; m_body1 = obj1;
m_body2 = obj2; m_body2 = obj2;
m_constraint = new BulletConstraint( m_constraint = new BulletConstraint(
BulletSimAPI.CreateHingeConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
pivotInA, pivotInB, pivotInA, pivotInB,
axisInA, axisInB, axisInA, axisInB,
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));

View File

@ -36,17 +36,24 @@ public class BSLinkset
{ {
private static string LogHeader = "[BULLETSIM LINKSET]"; private static string LogHeader = "[BULLETSIM LINKSET]";
private BSPhysObject m_linksetRoot; public BSPhysObject LinksetRoot { get; protected set; }
public BSPhysObject LinksetRoot { get { return m_linksetRoot; } }
private BSScene m_physicsScene; public BSScene PhysicsScene { get; private set; }
public BSScene PhysicsScene { get { return m_physicsScene; } }
static int m_nextLinksetID = 1; static int m_nextLinksetID = 1;
public int LinksetID { get; private set; } public int LinksetID { get; private set; }
// The children under the root in this linkset // The children under the root in this linkset.
// There are two lists of children: the current children at runtime
// and the children at taint-time. For instance, if you delink a
// child from the linkset, the child is removed from m_children
// but the constraint won't be removed until taint time.
// Two lists lets this track the 'current' children and
// the physical 'taint' children separately.
// After taint processing and before the simulation step, these
// two lists must be the same.
private List<BSPhysObject> m_children; private List<BSPhysObject> m_children;
private List<BSPhysObject> m_taintChildren;
// We lock the diddling of linkset classes to prevent any badness. // We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes // This locks the modification of the instances of this class. Changes
@ -79,21 +86,25 @@ public class BSLinkset
// A simple linkset of one (no children) // A simple linkset of one (no children)
LinksetID = m_nextLinksetID++; LinksetID = m_nextLinksetID++;
// We create LOTS of linksets. // We create LOTS of linksets.
if (m_nextLinksetID < 0) if (m_nextLinksetID <= 0)
m_nextLinksetID = 1; m_nextLinksetID = 1;
m_physicsScene = scene; PhysicsScene = scene;
m_linksetRoot = parent; LinksetRoot = parent;
m_children = new List<BSPhysObject>(); m_children = new List<BSPhysObject>();
m_taintChildren = new List<BSPhysObject>();
m_mass = parent.MassRaw; m_mass = parent.MassRaw;
} }
// Link to a linkset where the child knows the parent. // Link to a linkset where the child knows the parent.
// Parent changing should not happen so do some sanity checking. // Parent changing should not happen so do some sanity checking.
// We return the parent's linkset so the child can track its membership. // We return the parent's linkset so the child can track its membership.
// Called at runtime.
public BSLinkset AddMeToLinkset(BSPhysObject child) public BSLinkset AddMeToLinkset(BSPhysObject child)
{ {
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
// Don't add the root to its own linkset
if (!IsRoot(child))
AddChildToLinkset(child); AddChildToLinkset(child);
} }
return this; return this;
@ -102,27 +113,19 @@ public class BSLinkset
// Remove a child from a linkset. // Remove a child from a linkset.
// Returns a new linkset for the child which is a linkset of one (just the // Returns a new linkset for the child which is a linkset of one (just the
// orphened child). // orphened child).
// Called at runtime.
public BSLinkset RemoveMeFromLinkset(BSPhysObject child) public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
{ {
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
if (IsRoot(child)) if (IsRoot(child))
{ {
// if root of linkset, take the linkset apart // Cannot remove the root from a linkset.
while (m_children.Count > 0) return this;
{
// Note that we don't do a foreach because the remove routine
// takes it out of the list.
RemoveChildFromOtherLinkset(m_children[0]);
} }
m_children.Clear(); // just to make sure
}
else
{
// Just removing a child from an existing linkset
RemoveChildFromLinkset(child); RemoveChildFromLinkset(child);
} }
}
// The child is down to a linkset of just itself // The child is down to a linkset of just itself
return new BSLinkset(PhysicsScene, child); return new BSLinkset(PhysicsScene, child);
@ -131,7 +134,7 @@ public class BSLinkset
// Return 'true' if the passed object is the root object of this linkset // Return 'true' if the passed object is the root object of this linkset
public bool IsRoot(BSPhysObject requestor) public bool IsRoot(BSPhysObject requestor)
{ {
return (requestor.LocalID == m_linksetRoot.LocalID); return (requestor.LocalID == LinksetRoot.LocalID);
} }
public int NumberOfChildren { get { return m_children.Count; } } public int NumberOfChildren { get { return m_children.Count; } }
@ -157,51 +160,6 @@ public class BSLinkset
return ret; return ret;
} }
private float ComputeLinksetMass()
{
float mass = m_linksetRoot.MassRaw;
foreach (BSPhysObject bp in m_children)
{
mass += bp.MassRaw;
}
return mass;
}
private OMV.Vector3 ComputeLinksetCenterOfMass()
{
OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
float totalMass = m_linksetRoot.MassRaw;
lock (m_linksetActivityLock)
{
foreach (BSPhysObject bp in m_children)
{
com += bp.Position * bp.MassRaw;
totalMass += bp.MassRaw;
}
if (totalMass != 0f)
com /= totalMass;
}
return com;
}
private OMV.Vector3 ComputeLinksetGeometricCenter()
{
OMV.Vector3 com = m_linksetRoot.Position;
lock (m_linksetActivityLock)
{
foreach (BSPhysObject bp in m_children)
{
com += bp.Position * bp.MassRaw;
}
com /= (m_children.Count + 1);
}
return com;
}
// The object is going dynamic (physical). Do any setup necessary // The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset. // for a dynamic linkset.
// Only the state of the passed object can be modified. The rest of the linkset // Only the state of the passed object can be modified. The rest of the linkset
@ -210,8 +168,8 @@ public class BSLinkset
// Called at taint-time! // Called at taint-time!
public bool MakeDynamic(BSPhysObject child) public bool MakeDynamic(BSPhysObject child)
{ {
bool ret = false; // What is done for each object in BSPrim is what we want.
return ret; return false;
} }
// The object is going static (non-physical). Do any setup necessary // The object is going static (non-physical). Do any setup necessary
@ -226,6 +184,7 @@ public class BSLinkset
// When physical properties are changed the linkset needs to recalculate // When physical properties are changed the linkset needs to recalculate
// its internal properties. // its internal properties.
// Called at runtime.
public void Refresh(BSPhysObject requestor) public void Refresh(BSPhysObject requestor)
{ {
// If there are no children, there can't be any constraints to recompute // If there are no children, there can't be any constraints to recompute
@ -242,58 +201,125 @@ public class BSLinkset
} }
} }
// Call each of the constraints that make up this linkset and recompute the // Routine used when rebuilding the body of the root of the linkset
// various transforms and variables. Used when objects are added or removed // Destroy all the constraints have have been made to root.
// from a linkset to make sure the constraints know about the new mass and // This is called when the root body is changing.
// geometry. // Returns 'true' of something eas actually removed and would need restoring
// Must only be called at taint time!! // Called at taint-time!!
private void RecomputeLinksetConstraintVariables() public bool RemoveBodyDependencies(BSPrim child)
{ {
float linksetMass = LinksetMass; bool ret = false;
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
bool somethingMissing = false; if (IsRoot(child))
foreach (BSPhysObject child in m_children)
{ {
BSConstraint constrain; // If the one with the dependency is root, must undo all children
if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain)) DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}",
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
foreach (BSPhysObject bpo in m_taintChildren)
{ {
// DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}", PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID); ret = true;
constrain.RecomputeConstraintVariables(linksetMass); }
} }
else else
{ {
// Non-fatal error that happens when children are being added to the linkset but DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
// their constraints have not been created yet. child.LocalID,
// Caused by the fact that m_children is built at run time but building constraints LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
// happens at taint time. child.LocalID, child.BSBody.ptr.ToString("X"));
somethingMissing = true; // Remove the dependency on the body of this one
break; if (m_taintChildren.Contains(child))
{
PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
ret = true;
}
}
}
return ret;
}
// Routine used when rebuilding the body of the root of the linkset
// This is called after RemoveAllLinksToRoot() to restore all the constraints.
// This is called when the root body has been changed.
// Called at taint-time!!
public void RestoreBodyDependencies(BSPrim child)
{
lock (m_linksetActivityLock)
{
if (IsRoot(child))
{
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
foreach (BSPhysObject bpo in m_taintChildren)
{
PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
}
}
else
{
DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
LinksetRoot.LocalID,
LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
child.LocalID, child.BSBody.ptr.ToString("X"));
PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
}
} }
} }
// If the whole linkset is not here, doesn't make sense to recompute linkset wide values // ================================================================
if (!somethingMissing) // Below this point is internal magic
private float ComputeLinksetMass()
{ {
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass float mass;
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); lock (m_linksetActivityLock)
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity);
foreach (BSPhysObject child in m_children)
{ {
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity); mass = LinksetRoot.MassRaw;
} foreach (BSPhysObject bp in m_taintChildren)
/* {
// The root prim takes on the weight of the whole linkset mass += bp.MassRaw;
OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(LinksetRoot.BSShape.Ptr, linksetMass);
BulletSimAPI.SetMassProps2(LinksetRoot.BSBody.Ptr, linksetMass, inertia);
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity);
BulletSimAPI.UpdateInertiaTensor2(LinksetRoot.BSBody.Ptr);
*/
} }
} }
return; return mass;
}
private OMV.Vector3 ComputeLinksetCenterOfMass()
{
OMV.Vector3 com;
lock (m_linksetActivityLock)
{
com = LinksetRoot.Position * LinksetRoot.MassRaw;
float totalMass = LinksetRoot.MassRaw;
foreach (BSPhysObject bp in m_taintChildren)
{
com += bp.Position * bp.MassRaw;
totalMass += bp.MassRaw;
}
if (totalMass != 0f)
com /= totalMass;
}
return com;
}
private OMV.Vector3 ComputeLinksetGeometricCenter()
{
OMV.Vector3 com;
lock (m_linksetActivityLock)
{
com = LinksetRoot.Position;
foreach (BSPhysObject bp in m_taintChildren)
{
com += bp.Position * bp.MassRaw;
}
com /= (m_taintChildren.Count + 1);
}
return com;
} }
// I am the root of a linkset and a new child is being added // I am the root of a linkset and a new child is being added
@ -304,12 +330,22 @@ public class BSLinkset
{ {
m_children.Add(child); m_children.Add(child);
BSPhysObject rootx = LinksetRoot; // capture the root as of now BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BulletBody rootBodyx = LinksetRoot.BSBody;
BSPhysObject childx = child; BSPhysObject childx = child;
m_physicsScene.TaintedObject("AddChildToLinkset", delegate() BulletBody childBodyx = child.BSBody;
DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
rootx.LocalID,
rootx.LocalID, rootBodyx.ptr.ToString("X"),
childx.LocalID, childBodyx.ptr.ToString("X"));
PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
{ {
DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child // build the physical binding between me and the child
m_taintChildren.Add(childx);
PhysicallyLinkAChildToRoot(rootx, rootBodyx, childx, childBodyx);
}); });
} }
return; return;
@ -319,10 +355,10 @@ public class BSLinkset
// This is not being called by the child so we have to make sure the child doesn't think // This is not being called by the child so we have to make sure the child doesn't think
// it's still connected to the linkset. // it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information // Normal OpenSimulator operation will never do this because other SceneObjectPart information
// has to be updated also (like pointer to prim's parent). // also has to be updated (like pointer to prim's parent).
private void RemoveChildFromOtherLinkset(BSPhysObject pchild) private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
{ {
pchild.Linkset = new BSLinkset(m_physicsScene, pchild); pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
RemoveChildFromLinkset(pchild); RemoveChildFromLinkset(pchild);
} }
@ -332,13 +368,22 @@ public class BSLinkset
{ {
if (m_children.Remove(child)) if (m_children.Remove(child))
{ {
BSPhysObject rootx = LinksetRoot; // capture the root as of now BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BulletBody rootBodyx = LinksetRoot.BSBody;
BSPhysObject childx = child; BSPhysObject childx = child;
m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() BulletBody childBodyx = child.BSBody;
{
DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
PhysicallyUnlinkAChildFromRoot(rootx, childx); DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
childx.LocalID,
rootx.LocalID, rootBodyx.ptr.ToString("X"),
childx.LocalID, childBodyx.ptr.ToString("X"));
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
{
if (m_taintChildren.Contains(childx))
m_taintChildren.Remove(childx);
PhysicallyUnlinkAChildFromRoot(rootx, rootBodyx, childx, childBodyx);
RecomputeLinksetConstraintVariables(); RecomputeLinksetConstraintVariables();
}); });
@ -353,7 +398,8 @@ public class BSLinkset
// Create a constraint between me (root of linkset) and the passed prim (the child). // Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time! // Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
BSPhysObject childPrim, BulletBody childBody)
{ {
// Zero motion for children so they don't interpolate // Zero motion for children so they don't interpolate
childPrim.ZeroMotion(); childPrim.ZeroMotion();
@ -365,18 +411,36 @@ public class BSLinkset
// real world coordinate of midpoint between the two objects // real world coordinate of midpoint between the two objects
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID,
rootPrim.LocalID, rootBody.ptr.ToString("X"),
childPrim.LocalID, childBody.ptr.ToString("X"),
rootPrim.Position, childPrim.Position, midPoint);
// create a constraint that allows no freedom of movement between the two objects // create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}",
rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint); // There is great subtlty in these paramters. Notice the check for a ptr of zero.
// We pass the BulletBody structure into the taint in order to capture the pointer
// of the body at the time of constraint creation. This doesn't work for the very first
// construction because there is no body yet. The body
// is constructed later at taint time. Thus we use the body address at time of the
// taint creation but, if it is zero, use what's in the prim at the moment.
// There is a possible race condition since shape can change without a taint call
// (like changing to a mesh that is already constructed). The fix for that would be
// to only change BSShape at taint time thus syncronizing these operations at
// the cost of efficiency and lag.
BS6DofConstraint constrain = new BS6DofConstraint( BS6DofConstraint constrain = new BS6DofConstraint(
m_physicsScene.World, rootPrim.BSBody, childPrim.BSBody, PhysicsScene.World,
rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
midPoint, midPoint,
true, true,
true true
); );
/* NOTE: below is an attempt to build constraint with full frame computation, etc. /* NOTE: below is an attempt to build constraint with full frame computation, etc.
* Using the midpoint is easier since it lets the Bullet code use the transforms * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
* of the objects. * of the objects.
* Code left as a warning to future programmers. * Code left as a warning to future programmers.
// ================================================================================== // ==================================================================================
@ -408,7 +472,7 @@ public class BSLinkset
// ================================================================================== // ==================================================================================
*/ */
m_physicsScene.Constraints.AddConstraint(constrain); PhysicsScene.Constraints.AddConstraint(constrain);
// zero linear and angular limits makes the objects unable to move in relation to each other // 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.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@ -429,31 +493,79 @@ public class BSLinkset
} }
// Remove linkage between myself and a particular child // Remove linkage between myself and a particular child
// The root and child bodies are passed in because we need to remove the constraint between
// the bodies that were at unlink time.
// Called at taint time! // Called at taint time!
private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
BSPhysObject childPrim, BulletBody childBody)
{ {
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
rootPrim.LocalID,
rootPrim.LocalID, rootBody.ptr.ToString("X"),
childPrim.LocalID, childBody.ptr.ToString("X"));
// Find the constraint for this link and get rid of it from the overall collection and from my list // Find the constraint for this link and get rid of it from the overall collection and from my list
m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody); PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);
// Make the child refresh its location // Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.Ptr); BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
} }
// Remove linkage between myself and any possible children I might have /*
// Remove linkage between myself and any possible children I might have.
// Called at taint time! // Called at taint time!
private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
{ {
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
} }
*/
// Call each of the constraints that make up this linkset and recompute the
// various transforms and variables. Used when objects are added or removed
// from a linkset to make sure the constraints know about the new mass and
// geometry.
// Must only be called at taint time!!
private void RecomputeLinksetConstraintVariables()
{
float linksetMass = LinksetMass;
foreach (BSPhysObject child in m_taintChildren)
{
BSConstraint constrain;
if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
{
// DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
// LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
constrain.RecomputeConstraintVariables(linksetMass);
}
else
{
// Non-fatal error that happens when children are being added to the linkset but
// their constraints have not been created yet.
break;
}
}
// If the whole linkset is not here, doesn't make sense to recompute linkset wide values
if (m_children.Count == m_taintChildren.Count)
{
// If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
foreach (BSPhysObject child in m_taintChildren)
{
BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
}
}
return;
}
// Invoke the detailed logger and output something if it's enabled. // Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args) private void DetailLog(string msg, params Object[] args)
{ {
m_physicsScene.PhysicsLogging.Write(msg, args); PhysicsScene.PhysicsLogging.Write(msg, args);
} }
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
@ -39,26 +39,171 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// unless the difference is significant. // unless the difference is significant.
public abstract class BSPhysObject : PhysicsActor public abstract class BSPhysObject : PhysicsActor
{ {
public abstract BSLinkset Linkset { get; set; } protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
{
PhysicsScene = parentScene;
LocalID = localID;
PhysObjectName = name;
TypeName = typeName;
public abstract bool Collide(uint collidingWith, BSPhysObject collidee, Linkset = new BSLinkset(PhysicsScene, this);
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
public abstract void SendCollisions();
// Return the object mass without calculating it or side effects CollisionCollection = new CollisionEventUpdate();
SubscribedEventsMs = 0;
CollidingStep = 0;
CollidingGroundStep = 0;
}
public BSScene PhysicsScene { get; protected set; }
// public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
public string PhysObjectName { get; protected set; }
public string TypeName { get; protected set; }
public BSLinkset Linkset { get; set; }
// Return the object mass without calculating it or having side effects
public abstract float MassRaw { get; } public abstract float MassRaw { get; }
// Reference to the physical body (btCollisionObject) of this object // Reference to the physical body (btCollisionObject) of this object
public abstract BulletBody BSBody { get; set; } public BulletBody BSBody;
// Reference to the physical shape (btCollisionShape) of this object // Reference to the physical shape (btCollisionShape) of this object
public abstract BulletShape BSShape { get; set; } public BulletShape BSShape;
// Stop all physical motion.
public abstract void ZeroMotion(); public abstract void ZeroMotion();
// Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
public virtual void StepVehicle(float timeStep) { } public virtual void StepVehicle(float timeStep) { }
// Update the physical location and motion of the object. Called with data from Bullet.
public abstract void UpdateProperties(EntityProperties entprop); public abstract void UpdateProperties(EntityProperties entprop);
// Tell the object to clean up.
public abstract void Destroy(); public abstract void Destroy();
#region Collisions
// Requested number of milliseconds between collision events. Zero means disabled.
protected int SubscribedEventsMs { get; set; }
// Given subscription, the time that a collision may be passed up
protected int NextCollisionOkTime { get; set; }
// The simulation step that last had a collision
protected long CollidingStep { get; set; }
// The simulation step that last had a collision with the ground
protected long CollidingGroundStep { get; set; }
// The collision flags we think are set in Bullet
protected CollisionFlags CurrentCollisionFlags { get; set; }
// The collisions that have been collected this tick
protected CollisionEventUpdate CollisionCollection;
// The simulation step is telling this object about a collision.
// Return 'true' if a collision was processed and should be sent up.
// Called at taint time from within the Step() function
public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
{
bool ret = false;
// The following lines make IsColliding() and IsCollidingGround() work
CollidingStep = PhysicsScene.SimulationStep;
if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
{
CollidingGroundStep = PhysicsScene.SimulationStep;
}
// prims in the same linkset cannot collide with each other
if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
{
return ret;
}
// if someone has subscribed for collision events....
if (SubscribedEvents()) {
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
// DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
// LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
ret = true;
}
return ret;
}
// Routine to send the collected collisions into the simulator.
// Also handles removal of this from the collection of objects with collisions if
// there are no collisions from this object. Mechanism is create one last
// collision event to make collision_end work.
// Called at taint time from within the Step() function thus no locking problems
// with CollisionCollection and ObjectsWithNoMoreCollisions.
// Return 'true' if there were some actual collisions passed up
public virtual bool SendCollisions()
{
bool ret = true;
// throttle the collisions to the number of milliseconds specified in the subscription
int nowTime = PhysicsScene.SimulationNowTime;
if (nowTime >= NextCollisionOkTime)
{
NextCollisionOkTime = nowTime + SubscribedEventsMs;
// We are called if we previously had collisions. If there are no collisions
// this time, send up one last empty event so OpenSim can sense collision end.
if (CollisionCollection.Count == 0)
{
// If I have no collisions this time, remove me from the list of objects with collisions.
ret = false;
}
// DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
base.SendCollisionUpdate(CollisionCollection);
// The collisionCollection structure is passed around in the simulator.
// Make sure we don't have a handle to that one and that a new one is used for next time.
CollisionCollection = new CollisionEventUpdate();
}
return ret;
}
// Subscribe for collision events.
// Parameter is the millisecond rate the caller wishes collision events to occur.
public override void SubscribeEvents(int ms) {
// DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
SubscribedEventsMs = ms;
if (ms > 0)
{
// make sure first collision happens
NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
{
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
else
{
// Subscribing for zero or less is the same as unsubscribing
UnSubscribeEvents();
}
}
public override void UnSubscribeEvents() {
// DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
SubscribedEventsMs = 0;
PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
{
CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
}
// Return 'true' if the simulator wants collision events
public override bool SubscribedEvents() {
return (SubscribedEventsMs > 0);
}
#endregion // Collisions
// High performance detailed logging routine used by the physical objects.
protected void DetailLog(string msg, params Object[] args)
{
PhysicsScene.PhysicsLogging.Write(msg, args);
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -39,20 +39,20 @@ using log4net;
using OpenMetaverse; using OpenMetaverse;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) // Move all logic out of the C++ code and into the C# code for easier future modifications.
// Test sculpties // Test sculpties (verified that they don't work)
// Compute physics FPS reasonably // Compute physics FPS reasonably
// Based on material, set density and friction // Based on material, set density and friction
// More efficient memory usage when passing hull information from BSPrim to BulletSim // Don't use constraints in linksets of non-physical objects. Means having to move children manually.
// Move all logic out of the C++ code and into the C# code for easier future modifications.
// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
// At the moment, physical and phantom causes object to drop through the terrain // At the moment, physical and phantom causes object to drop through the terrain
// Physical phantom objects and related typing (collision options ) // Physical phantom objects and related typing (collision options )
// Use collision masks for collision with terrain and phantom objects
// Check out llVolumeDetect. Must do something for that. // Check out llVolumeDetect. Must do something for that.
// Use collision masks for collision with terrain and phantom objects
// More efficient memory usage when passing hull information from BSPrim to BulletSim
// Should prim.link() and prim.delink() membership checking happen at taint time? // Should prim.link() and prim.delink() membership checking happen at taint time?
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
// Implement LockAngularMotion // Implement LockAngularMotion
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
@ -73,12 +73,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public string BulletSimVersion = "?"; public string BulletSimVersion = "?";
public Dictionary<uint, BSPhysObject> PhysObjects = new Dictionary<uint, BSPhysObject>(); public Dictionary<uint, BSPhysObject> PhysObjects;
public BSShapeCollection Shapes;
private HashSet<BSPhysObject> m_objectsWithCollisions = new HashSet<BSPhysObject>(); // Keeping track of the objects with collisions so we can report begin and end of a collision
// Following is a kludge and can be removed when avatar animation updating is public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
// moved to a better place. public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
private HashSet<BSPhysObject> m_avatarsWithCollisions = new HashSet<BSPhysObject>(); // Keep track of all the avatars so we can send them a collision event
// every tick so OpenSim will update its animation.
private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
// List of all the objects that have vehicle properties and should be called // List of all the objects that have vehicle properties and should be called
// to update each physics step. // to update each physics step.
@ -202,6 +205,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public override void Initialise(IMesher meshmerizer, IConfigSource config) public override void Initialise(IMesher meshmerizer, IConfigSource config)
{ {
mesher = meshmerizer;
_taintedObjects = new List<TaintCallbackEntry>();
PhysObjects = new Dictionary<uint, BSPhysObject>();
Shapes = new BSShapeCollection(this);
// Allocate pinned memory to pass parameters. // Allocate pinned memory to pass parameters.
m_params = new ConfigurationParameters[1]; m_params = new ConfigurationParameters[1];
m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
@ -215,9 +223,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
mesher = meshmerizer;
_taintedObjects = new List<TaintCallbackEntry>();
// Enable very detailed logging. // Enable very detailed logging.
// By creating an empty logger when not logging, the log message invocation code // By creating an empty logger when not logging, the log message invocation code
// can be left in and every call doesn't have to check for null. // can be left in and every call doesn't have to check for null.
@ -251,7 +256,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// a child in a mega-region. // a child in a mega-region.
// Turns out that Bullet really doesn't care about the extents of the simulated // Turns out that Bullet really doesn't care about the extents of the simulated
// area. It tracks active objects no matter where they are. // area. It tracks active objects no matter where they are.
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
@ -351,6 +356,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
Constraints = null; Constraints = null;
} }
if (Shapes != null)
{
Shapes.Dispose();
Shapes = null;
}
// Anything left in the unmanaged code should be cleaned out // Anything left in the unmanaged code should be cleaned out
BulletSimAPI.Shutdown(WorldID); BulletSimAPI.Shutdown(WorldID);
@ -379,7 +390,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// TODO: Remove kludge someday. // TODO: Remove kludge someday.
// We must generate a collision for avatars whether they collide or not. // We must generate a collision for avatars whether they collide or not.
// This is required by OpenSim to update avatar animations, etc. // This is required by OpenSim to update avatar animations, etc.
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor); lock (m_avatars) m_avatars.Add(actor);
return actor; return actor;
} }
@ -397,7 +408,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{ {
lock (PhysObjects) PhysObjects.Remove(actor.LocalID); lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
// Remove kludge someday // Remove kludge someday
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Remove(bsactor); lock (m_avatars) m_avatars.Remove(bsactor);
} }
catch (Exception e) catch (Exception e)
{ {
@ -464,6 +475,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int collidersCount = 0; int collidersCount = 0;
IntPtr collidersPtr; IntPtr collidersPtr;
int beforeTime = 0;
int simTime = 0;
// prevent simulation until we've been initialized // prevent simulation until we've been initialized
if (!m_initialized) return 5.0f; if (!m_initialized) return 5.0f;
@ -481,10 +495,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int numSubSteps = 0; int numSubSteps = 0;
try try
{ {
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep, numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
DetailLog("{0},Simulate,call, nTaints= {1}, substeps={2}, updates={3}, colliders={4}",
DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}",
DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
} }
catch (Exception e) catch (Exception e)
{ {
@ -502,12 +520,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Get a value for 'now' so all the collision and update routines don't have to get their own // Get a value for 'now' so all the collision and update routines don't have to get their own
SimulationNowTime = Util.EnvironmentTickCount(); SimulationNowTime = Util.EnvironmentTickCount();
// This is a kludge to get avatar movement updates.
// ODE sends collisions for avatars even if there are have been no collisions. This updates
// avatar animations and stuff.
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
m_objectsWithCollisions = new HashSet<BSPhysObject>(m_avatarsWithCollisions);
// If there were collisions, process them by sending the event to the prim. // If there were collisions, process them by sending the event to the prim.
// Collisions must be processed before updates. // Collisions must be processed before updates.
if (collidersCount > 0) if (collidersCount > 0)
@ -523,11 +535,34 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
} }
// This is a kludge to get avatar movement updates.
// ODE sends collisions for avatars even if there are have been no collisions. This updates
// avatar animations and stuff.
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
foreach (BSPhysObject bsp in m_avatars)
bsp.SendCollisions();
// The above SendCollision's batch up the collisions on the objects. // The above SendCollision's batch up the collisions on the objects.
// Now push the collisions into the simulator. // Now push the collisions into the simulator.
foreach (BSPhysObject bsp in m_objectsWithCollisions) if (ObjectsWithCollisions.Count > 0)
bsp.SendCollisions(); {
m_objectsWithCollisions.Clear(); foreach (BSPhysObject bsp in ObjectsWithCollisions)
if (!m_avatars.Contains(bsp)) // don't call avatars twice
if (!bsp.SendCollisions())
{
// If the object is done colliding, see that it's removed from the colliding list
ObjectsWithNoMoreCollisions.Add(bsp);
}
}
// Objects that are done colliding are removed from the ObjectsWithCollisions list.
// This can't be done by SendCollisions because it is inside an iteration of ObjectWithCollisions.
if (ObjectsWithNoMoreCollisions.Count > 0)
{
foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
ObjectsWithCollisions.Remove(po);
ObjectsWithNoMoreCollisions.Clear();
}
// If any of the objects had updated properties, tell the object it has been changed by the physics engine // If any of the objects had updated properties, tell the object it has been changed by the physics engine
if (updatedEntityCount > 0) if (updatedEntityCount > 0)
@ -555,7 +590,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// The physics engine returns the number of milliseconds it simulated this call. // The physics engine returns the number of milliseconds it simulated this call.
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
// Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS. // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
return numSubSteps * m_fixedTimeStep; return numSubSteps * m_fixedTimeStep * 1000;
} }
// Something has collided // Something has collided
@ -570,20 +605,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
if (!PhysObjects.TryGetValue(localID, out collider)) if (!PhysObjects.TryGetValue(localID, out collider))
{ {
// If the object that is colliding cannot be found, just ignore the collision. // If the object that is colliding cannot be found, just ignore the collision.
DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
return; return;
} }
// The terrain is not in the physical object list so 'collidee' // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
// can be null when Collide() is called.
BSPhysObject collidee = null; BSPhysObject collidee = null;
PhysObjects.TryGetValue(collidingWith, out collidee); PhysObjects.TryGetValue(collidingWith, out collidee);
// DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
{ {
// If a collision was posted, remember to send it to the simulator // If a collision was posted, remember to send it to the simulator
m_objectsWithCollisions.Add(collider); ObjectsWithCollisions.Add(collider);
} }
return; return;
@ -998,7 +1033,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
(s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
ConfigurationParameters.numericFalse, ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldSplitSimulationIslands; }, (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
(s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),

View File

@ -0,0 +1,735 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OMV = OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
using OpenSim.Region.Physics.ConvexDecompositionDotNet;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSShapeCollection : IDisposable
{
private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
protected BSScene PhysicsScene { get; set; }
private Object m_collectionActivityLock = new Object();
// Description of a Mesh
private struct MeshDesc
{
public IntPtr ptr;
public int referenceCount;
public DateTime lastReferenced;
}
// Description of a hull.
// Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects
private struct HullDesc
{
public IntPtr ptr;
public int referenceCount;
public DateTime lastReferenced;
}
private struct BodyDesc
{
public IntPtr ptr;
// Bodies are only used once so reference count is always either one or zero
public int referenceCount;
public DateTime lastReferenced;
}
private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>();
private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>();
private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
public BSShapeCollection(BSScene physScene)
{
PhysicsScene = physScene;
}
public void Dispose()
{
// TODO!!!!!!!!!
}
// Callbacks called just before either the body or shape is destroyed.
// Mostly used for changing bodies out from under Linksets.
// Useful for other cases where parameters need saving.
// Passing 'null' says no callback.
public delegate void ShapeDestructionCallback(BulletShape shape);
public delegate void BodyDestructionCallback(BulletBody body);
// Called to update/change the body and shape for an object.
// First checks the shape and updates that if necessary then makes
// sure the body is of the right type.
// Return 'true' if either the body or the shape changed.
// Called at taint-time!!
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim,
ShapeData shapeData, PrimitiveBaseShape pbs,
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
{
bool ret = false;
// This lock could probably be pushed down lower but building shouldn't take long
lock (m_collectionActivityLock)
{
// Do we have the correct geometry for this type of object?
// Updates prim.BSShape with information/pointers to requested shape
bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
// If we had to select a new shape geometry for the object,
// rebuild the body around it.
// Updates prim.BSBody with information/pointers to requested body
bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, prim.BSShape, shapeData, bodyCallback);
ret = newGeom || newBody;
}
DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
return ret;
}
// Track another user of a body
// We presume the caller has allocated the body.
// Bodies only have one user so the reference count is either 1 or 0.
public void ReferenceBody(BulletBody body, bool atTaintTime)
{
lock (m_collectionActivityLock)
{
BodyDesc bodyDesc;
if (Bodies.TryGetValue(body.ID, out bodyDesc))
{
bodyDesc.referenceCount++;
DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
}
else
{
// New entry
bodyDesc.ptr = body.ptr;
bodyDesc.referenceCount = 1;
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount);
}
bodyDesc.lastReferenced = System.DateTime.Now;
Bodies[body.ID] = bodyDesc;
}
}
// Release the usage of a body.
// Called when releasing use of a BSBody. BSShape is handled separately.
public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
{
if (body.ptr == IntPtr.Zero)
return;
lock (m_collectionActivityLock)
{
BodyDesc bodyDesc;
if (Bodies.TryGetValue(body.ID, out bodyDesc))
{
bodyDesc.referenceCount--;
bodyDesc.lastReferenced = System.DateTime.Now;
Bodies[body.ID] = bodyDesc;
DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
// If body is no longer being used, free it -- bodies are never shared.
if (bodyDesc.referenceCount == 0)
{
Bodies.Remove(body.ID);
BSScene.TaintCallback removeOperation = delegate()
{
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}",
body.ID, body.ptr.ToString("X"));
// If the caller needs to know, pass the event up.
if (bodyCallback != null) bodyCallback(body);
// Zero any reference to the shape so it is not freed when the body is deleted.
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
// It may have already been removed from the world in which case the next is a NOOP.
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
};
// If already in taint-time, do the operations now. Otherwise queue for later.
if (inTaintTime)
removeOperation();
else
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
}
}
else
{
DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
}
}
}
// Track the datastructures and use count for a shape.
// When creating a hull, this is called first to reference the mesh
// and then again to reference the hull.
// Meshes and hulls for the same shape have the same hash key.
// NOTE that native shapes are not added to the mesh list or removed.
// Returns 'true' if this is the initial reference to the shape. Otherwise reused.
private bool ReferenceShape(BulletShape shape)
{
bool ret = false;
switch (shape.type)
{
case ShapeData.PhysicsShapeType.SHAPE_MESH:
MeshDesc meshDesc;
if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
{
// There is an existing instance of this mesh.
meshDesc.referenceCount++;
DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
}
else
{
// This is a new reference to a mesh
meshDesc.ptr = shape.ptr;
// We keep a reference to the underlying IMesh data so a hull can be built
meshDesc.referenceCount = 1;
DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
ret = true;
}
meshDesc.lastReferenced = System.DateTime.Now;
Meshes[shape.shapeKey] = meshDesc;
break;
case ShapeData.PhysicsShapeType.SHAPE_HULL:
HullDesc hullDesc;
if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
{
// There is an existing instance of this hull.
hullDesc.referenceCount++;
DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
}
else
{
// This is a new reference to a hull
hullDesc.ptr = shape.ptr;
hullDesc.referenceCount = 1;
DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
ret = true;
}
hullDesc.lastReferenced = System.DateTime.Now;
Hulls[shape.shapeKey] = hullDesc;
break;
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
break;
default:
// Native shapes are not tracked and they don't go into any list
break;
}
return ret;
}
// Release the usage of a shape.
// The collisionObject is released since it is a copy of the real collision shape.
public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback)
{
if (shape.ptr == IntPtr.Zero)
return;
BSScene.TaintCallback dereferenceOperation = delegate()
{
switch (shape.type)
{
case ShapeData.PhysicsShapeType.SHAPE_HULL:
DereferenceHull(shape, shapeCallback);
break;
case ShapeData.PhysicsShapeType.SHAPE_MESH:
DereferenceMesh(shape, shapeCallback);
break;
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
break;
default:
// Native shapes are not tracked and are released immediately
if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
{
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime);
if (shapeCallback != null) shapeCallback(shape);
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
}
break;
}
};
if (atTaintTime)
{
lock (m_collectionActivityLock)
{
dereferenceOperation();
}
}
else
{
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
}
}
// Count down the reference count for a mesh shape
// Called at taint-time.
private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
{
MeshDesc meshDesc;
if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
{
meshDesc.referenceCount--;
// TODO: release the Bullet storage
if (shapeCallback != null) shapeCallback(shape);
meshDesc.lastReferenced = System.DateTime.Now;
Meshes[shape.shapeKey] = meshDesc;
DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
}
}
// Count down the reference count for a hull shape
// Called at taint-time.
private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
{
HullDesc hullDesc;
if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
{
hullDesc.referenceCount--;
// TODO: release the Bullet storage (aging old entries?)
if (shapeCallback != null) shapeCallback(shape);
hullDesc.lastReferenced = System.DateTime.Now;
Hulls[shape.shapeKey] = hullDesc;
DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
}
}
// Create the geometry information in Bullet for later use.
// The objects needs a hull if it's physical otherwise a mesh is enough.
// No locking here because this is done when we know physics is not simulating.
// if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
// Returns 'true' if the geometry was rebuilt.
// Called at taint-time!
private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData,
PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
{
bool ret = false;
bool haveShape = false;
bool nativeShapePossible = true;
// If the prim attributes are simple, this could be a simple Bullet native shape
if (nativeShapePossible
&& ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
&& pbs.ProfileHollow == 0
&& pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
&& pbs.PathBegin == 0 && pbs.PathEnd == 0
&& pbs.PathTaperX == 0 && pbs.PathTaperY == 0
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
&& pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
{
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
{
haveShape = true;
if (forceRebuild
|| prim.Scale != shapeData.Size
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
)
{
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.BSShape);
}
}
else
{
haveShape = true;
if (forceRebuild
|| prim.Scale != shapeData.Size
|| prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
)
{
ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
prim.LocalID, forceRebuild, prim.BSShape);
}
}
}
// If a simple shape is not happening, create a mesh and possibly a hull.
// Note that if it's a native shape, the check for physical/non-physical is not
// made. Native shapes are best used in either case.
if (!haveShape)
{
if (prim.IsPhysical)
{
// Update prim.BSShape to reference a hull of this shape.
ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
}
else
{
ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback);
DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
}
}
return ret;
}
// Creates a native shape and assignes it to prim.BSShape
private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
ShapeDestructionCallback shapeCallback)
{
BulletShape newShape;
shapeData.Type = shapeType;
// Bullet native objects are scaled by the Bullet engine so pass the size in
prim.Scale = shapeData.Size;
shapeData.Scale = shapeData.Size;
// release any previous shape
DereferenceShape(prim.BSShape, true, shapeCallback);
// Native shapes are always built independently.
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
newShape.shapeKey = (ulong)shapeKey;
newShape.isNativeShape = true;
// Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
// DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
prim.BSShape = newShape;
return true;
}
// Builds a mesh shape in the physical world and updates prim.BSShape.
// Dereferences previous shape in BSShape and adds a reference for this new shape.
// Returns 'true' of a mesh was actually built. Otherwise .
// Called at taint-time!
private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
ShapeDestructionCallback shapeCallback)
{
BulletShape newShape = new BulletShape(IntPtr.Zero);
float lod;
ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
// if this new shape is the same as last time, don't recreate the mesh
if (prim.BSShape.shapeKey == newMeshKey) return false;
DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}",
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
// Since we're recreating new, get rid of the reference to the previous shape
DereferenceShape(prim.BSShape, true, shapeCallback);
newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
ReferenceShape(newShape);
// meshes are already scaled by the meshmerizer
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
prim.BSShape = newShape;
return true; // 'true' means a new shape has been added to this prim
}
private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
{
IMesh meshData = null;
IntPtr meshPtr;
MeshDesc meshDesc;
if (Meshes.TryGetValue(newMeshKey, out meshDesc))
{
// If the mesh has already been built just use it.
meshPtr = meshDesc.ptr;
}
else
{
// Pass false for physicalness as this creates some sort of bounding box which we don't need
meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
int[] indices = meshData.getIndexListAsInt();
List<OMV.Vector3> vertices = meshData.getVertexList();
float[] verticesAsFloats = new float[vertices.Count * 3];
int vi = 0;
foreach (OMV.Vector3 vv in vertices)
{
verticesAsFloats[vi++] = vv.X;
verticesAsFloats[vi++] = vv.Y;
verticesAsFloats[vi++] = vv.Z;
}
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
}
BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
newShape.shapeKey = newMeshKey;
return newShape;
}
// See that hull shape exists in the physical world and update prim.BSShape.
// We could be creating the hull because scale changed or whatever.
private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
ShapeDestructionCallback shapeCallback)
{
BulletShape newShape;
float lod;
ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
// if the hull hasn't changed, don't rebuild it
if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
return false;
DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
// Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull.
DereferenceShape(prim.BSShape, true, shapeCallback);
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
ReferenceShape(newShape);
// hulls are already scaled by the meshmerizer
prim.Scale = new OMV.Vector3(1f, 1f, 1f);
prim.BSShape = newShape;
return true; // 'true' means a new shape has been added to this prim
}
List<ConvexResult> m_hulls;
private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
{
IntPtr hullPtr;
HullDesc hullDesc;
if (Hulls.TryGetValue(newHullKey, out hullDesc))
{
// If the hull shape already is created, just use it.
hullPtr = hullDesc.ptr;
}
else
{
// Build a new hull in the physical world
// Pass false for physicalness as this creates some sort of bounding box which we don't need
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
int[] indices = meshData.getIndexListAsInt();
List<OMV.Vector3> vertices = meshData.getVertexList();
//format conversion from IMesh format to DecompDesc format
List<int> convIndices = new List<int>();
List<float3> convVertices = new List<float3>();
for (int ii = 0; ii < indices.GetLength(0); ii++)
{
convIndices.Add(indices[ii]);
}
foreach (OMV.Vector3 vv in vertices)
{
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
}
// setup and do convex hull conversion
m_hulls = new List<ConvexResult>();
DecompDesc dcomp = new DecompDesc();
dcomp.mIndices = convIndices;
dcomp.mVertices = convVertices;
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
// create the hull into the _hulls variable
convexBuilder.process(dcomp);
// Convert the vertices and indices for passing to unmanaged.
// The hull information is passed as a large floating point array.
// The format is:
// convHulls[0] = number of hulls
// convHulls[1] = number of vertices in first hull
// convHulls[2] = hull centroid X coordinate
// convHulls[3] = hull centroid Y coordinate
// convHulls[4] = hull centroid Z coordinate
// convHulls[5] = first hull vertex X
// convHulls[6] = first hull vertex Y
// convHulls[7] = first hull vertex Z
// convHulls[8] = second hull vertex X
// ...
// convHulls[n] = number of vertices in second hull
// convHulls[n+1] = second hull centroid X coordinate
// ...
//
// TODO: is is very inefficient. Someday change the convex hull generator to return
// data structures that do not need to be converted in order to pass to Bullet.
// And maybe put the values directly into pinned memory rather than marshaling.
int hullCount = m_hulls.Count;
int totalVertices = 1; // include one for the count of the hulls
foreach (ConvexResult cr in m_hulls)
{
totalVertices += 4; // add four for the vertex count and centroid
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
}
float[] convHulls = new float[totalVertices];
convHulls[0] = (float)hullCount;
int jj = 1;
foreach (ConvexResult cr in m_hulls)
{
// copy vertices for index access
float3[] verts = new float3[cr.HullVertices.Count];
int kk = 0;
foreach (float3 ff in cr.HullVertices)
{
verts[kk++] = ff;
}
// add to the array one hull's worth of data
convHulls[jj++] = cr.HullIndices.Count;
convHulls[jj++] = 0f; // centroid x,y,z
convHulls[jj++] = 0f;
convHulls[jj++] = 0f;
foreach (int ind in cr.HullIndices)
{
convHulls[jj++] = verts[ind].x;
convHulls[jj++] = verts[ind].y;
convHulls[jj++] = verts[ind].z;
}
}
// create the hull data structure in Bullet
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
}
BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
newShape.shapeKey = newHullKey;
return newShape; // 'true' means a new shape has been added to this prim
}
// Callback from convex hull creater with a newly created hull.
// Just add it to our collection of hulls for this shape.
private void HullReturn(ConvexResult result)
{
m_hulls.Add(result);
return;
}
// Create a hash of all the shape parameters to be used as a key
// for this particular shape.
private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
{
// level of detail based on size and type of the object
float lod = PhysicsScene.MeshLOD;
if (pbs.SculptEntry)
lod = PhysicsScene.SculptLOD;
float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
lod = PhysicsScene.MeshMegaPrimLOD;
retLod = lod;
return (ulong)pbs.GetMeshKey(shapeData.Size, lod);
}
// For those who don't want the LOD
private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
{
float lod;
return ComputeShapeKey(shapeData, pbs, out lod);
}
// Create a body object in Bullet.
// Updates prim.BSBody with the information about the new body if one is created.
// Returns 'true' if an object was actually created.
// Called at taint-time.
private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape,
ShapeData shapeData, BodyDestructionCallback bodyCallback)
{
bool ret = false;
// the mesh, hull or native shape must have already been created in Bullet
bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero);
// If there is an existing body, verify it's of an acceptable type.
// If not a solid object, body is a GhostObject. Otherwise a RigidBody.
if (!mustRebuild)
{
CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr);
if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
|| !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
{
// If the collisionObject is not the correct type for solidness, rebuild what's there
mustRebuild = true;
}
}
if (mustRebuild || forceRebuild)
{
DereferenceBody(prim.BSBody, true, bodyCallback);
BulletBody aBody;
IntPtr bodyPtr = IntPtr.Zero;
if (prim.IsSolid)
{
bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
shapeData.ID, shapeData.Position, shapeData.Rotation);
// DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
}
else
{
bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
shapeData.ID, shapeData.Position, shapeData.Rotation);
// DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
}
aBody = new BulletBody(shapeData.ID, bodyPtr);
ReferenceBody(aBody, true);
prim.BSBody = aBody;
ret = true;
}
return ret;
}
private void DetailLog(string msg, params Object[] args)
{
PhysicsScene.PhysicsLogging.Write(msg, args);
}
}
}

View File

@ -57,10 +57,10 @@ public class BSTerrainManager
public const float TERRAIN_COLLISION_MARGIN = 0.0f; public const float TERRAIN_COLLISION_MARGIN = 0.0f;
// Until the whole simulator is changed to pass us the region size, we rely on constants. // Until the whole simulator is changed to pass us the region size, we rely on constants.
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, 0f); public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
// The scene that I am part of // The scene that I am part of
private BSScene m_physicsScene; private BSScene PhysicsScene { get; set; }
// The ground plane created to keep thing from falling to infinity. // The ground plane created to keep thing from falling to infinity.
private BulletBody m_groundPlane; private BulletBody m_groundPlane;
@ -84,18 +84,18 @@ public class BSTerrainManager
// If the parent region (region 0), this is the extent of the combined regions // If the parent region (region 0), this is the extent of the combined regions
// relative to the origin of region zero // relative to the origin of region zero
private Vector3 m_worldMax; private Vector3 m_worldMax;
private PhysicsScene m_parentScene; private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
public BSTerrainManager(BSScene physicsScene) public BSTerrainManager(BSScene physicsScene)
{ {
m_physicsScene = physicsScene; PhysicsScene = physicsScene;
m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
m_terrainModified = false; m_terrainModified = false;
// Assume one region of default size // Assume one region of default size
m_worldOffset = Vector3.Zero; m_worldOffset = Vector3.Zero;
m_worldMax = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, 4096f); m_worldMax = new Vector3(DefaultRegionSize);
m_parentScene = null; MegaRegionParentPhysicsScene = null;
} }
// Create the initial instance of terrain and the underlying ground plane. // Create the initial instance of terrain and the underlying ground plane.
@ -107,10 +107,16 @@ public class BSTerrainManager
public void CreateInitialGroundPlaneAndTerrain() public void CreateInitialGroundPlaneAndTerrain()
{ {
// The ground plane is here to catch things that are trying to drop to negative infinity // The ground plane is here to catch things that are trying to drop to negative infinity
BulletShape groundPlaneShape = new BulletShape(BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN)); BulletShape groundPlaneShape = new BulletShape(
BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE);
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.Ptr, Vector3.Zero, Quaternion.Identity)); BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); Vector3.Zero, Quaternion.Identity));
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
// Everything collides with the ground plane.
BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
(uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION); Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
@ -126,13 +132,13 @@ public class BSTerrainManager
// Release all the terrain structures we might have allocated // Release all the terrain structures we might have allocated
public void ReleaseGroundPlaneAndTerrain() public void ReleaseGroundPlaneAndTerrain()
{ {
if (m_groundPlane.Ptr != IntPtr.Zero) if (m_groundPlane.ptr != IntPtr.Zero)
{ {
if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr)) if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
{ {
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
} }
m_groundPlane.Ptr = IntPtr.Zero; m_groundPlane.ptr = IntPtr.Zero;
} }
ReleaseTerrain(); ReleaseTerrain();
@ -143,9 +149,9 @@ public class BSTerrainManager
{ {
foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps) foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
{ {
if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr)) if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr))
{ {
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr); BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr); BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
} }
} }
@ -155,19 +161,19 @@ public class BSTerrainManager
// The simulator wants to set a new heightmap for the terrain. // The simulator wants to set a new heightmap for the terrain.
public void SetTerrain(float[] heightMap) { public void SetTerrain(float[] heightMap) {
float[] localHeightMap = heightMap; float[] localHeightMap = heightMap;
m_physicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
{ {
if (m_worldOffset != Vector3.Zero && m_parentScene != null) if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
{ {
// If a child of a mega-region, we shouldn't have any terrain allocated for us // If a child of a mega-region, we shouldn't have any terrain allocated for us
ReleaseGroundPlaneAndTerrain(); ReleaseGroundPlaneAndTerrain();
// If doing the mega-prim stuff and we are the child of the zero region, // If doing the mega-prim stuff and we are the child of the zero region,
// the terrain is added to our parent // the terrain is added to our parent
if (m_parentScene is BSScene) if (MegaRegionParentPhysicsScene is BSScene)
{ {
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
BSScene.DetailLogZero, m_worldOffset, m_worldMax); BSScene.DetailLogZero, m_worldOffset, m_worldMax);
((BSScene)m_parentScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID, ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
} }
} }
@ -176,7 +182,8 @@ public class BSTerrainManager
// If not doing the mega-prim thing, just change the terrain // If not doing the mega-prim thing, just change the terrain
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
m_worldOffset, m_worldOffset + DefaultRegionSize, true);
} }
}); });
} }
@ -194,10 +201,10 @@ public class BSTerrainManager
// The 'doNow' boolean says whether to do all the unmanaged activities right now (like when // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
// calling this routine from initialization or taint-time routines) or whether to delay // calling this routine from initialization or taint-time routines) or whether to delay
// all the unmanaged activities to taint-time. // all the unmanaged activities to taint-time.
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool doNow) private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime)
{ {
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},doNow={3}", DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}",
BSScene.DetailLogZero, minCoords, maxCoords, doNow); BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime);
float minZ = float.MaxValue; float minZ = float.MaxValue;
float maxZ = float.MinValue; float maxZ = float.MinValue;
@ -232,7 +239,7 @@ public class BSTerrainManager
BSScene.TaintCallback rebuildOperation = delegate() BSScene.TaintCallback rebuildOperation = delegate()
{ {
if (m_parentScene != null) if (MegaRegionParentPhysicsScene != null)
{ {
// It's possible that Combine() was called after this code was queued. // It's possible that Combine() was called after this code was queued.
// If we are a child of combined regions, we don't create any terrain for us. // If we are a child of combined regions, we don't create any terrain for us.
@ -245,17 +252,17 @@ public class BSTerrainManager
return; return;
} }
if (mapInfo.terrainBody.Ptr != IntPtr.Zero) if (mapInfo.terrainBody.ptr != IntPtr.Zero)
{ {
// Updating an existing terrain. // Updating an existing terrain.
DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
// Remove from the dynamics world because we're going to mangle this object // Remove from the dynamics world because we're going to mangle this object
BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr); BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
// Get rid of the old terrain // Get rid of the old terrain
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr); BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr); BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
mapInfo.Ptr = IntPtr.Zero; mapInfo.Ptr = IntPtr.Zero;
@ -286,7 +293,7 @@ public class BSTerrainManager
BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ); BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
mapInfo.ID = id; mapInfo.ID = id;
mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.ID, mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
// The terrain object initial position is at the center of the object // The terrain object initial position is at the center of the object
@ -296,43 +303,49 @@ public class BSTerrainManager
centerPos.Z = minZ + ((maxZ - minZ) / 2f); centerPos.Z = minZ + ((maxZ - minZ) / 2f);
// Create the terrain shape from the mapInfo // Create the terrain shape from the mapInfo
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr)); mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
mapInfo.terrainBody = new BulletBody(mapInfo.ID, mapInfo.terrainBody = new BulletBody(mapInfo.ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.Ptr, BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
centerPos, Quaternion.Identity)); id, centerPos, Quaternion.Identity));
} }
// Make sure the entry is in the heightmap table // Make sure the entry is in the heightmap table
m_heightMaps[terrainRegionBase] = mapInfo; m_heightMaps[terrainRegionBase] = mapInfo;
// Set current terrain attributes // Set current terrain attributes
BulletSimAPI.SetFriction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainFriction); BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction); BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
BulletSimAPI.SetRestitution2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainRestitution); BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT); BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
BulletSimAPI.SetMassProps2(mapInfo.terrainBody.Ptr, 0f, Vector3.Zero); BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.Ptr); BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
// Return the new terrain to the world of physical objects // Return the new terrain to the world of physical objects
BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr); BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
// redo its bounding box now that it is in the world // redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr); BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
(uint)CollisionFilterGroups.TerrainFilter,
(uint)CollisionFilterGroups.TerrainMask);
// Make sure the new shape is processed. // Make sure the new shape is processed.
BulletSimAPI.Activate2(mapInfo.terrainBody.Ptr, true); // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
m_terrainModified = true; m_terrainModified = true;
}; };
// There is the option to do the changes now (we're already in 'taint time'), or // There is the option to do the changes now (we're already in 'taint time'), or
// to do the Bullet operations later. // to do the Bullet operations later.
if (doNow) if (atTaintTime)
rebuildOperation(); rebuildOperation();
else else
m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation); PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
} }
else else
{ {
@ -357,7 +370,7 @@ public class BSTerrainManager
DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
// Create a new mapInfo that will be filled with the new info // Create a new mapInfo that will be filled with the new info
mapInfo = new BulletHeightMapInfo(id, heightMapX, mapInfo = new BulletHeightMapInfo(id, heightMapX,
BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, newTerrainID, BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN)); minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
// Put the unfilled heightmap info into the collection of same // Put the unfilled heightmap info into the collection of same
m_heightMaps.Add(terrainRegionBase, mapInfo); m_heightMaps.Add(terrainRegionBase, mapInfo);
@ -368,10 +381,10 @@ public class BSTerrainManager
}; };
// If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time. // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
if (doNow) if (atTaintTime)
createOperation(); createOperation();
else else
m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation); PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
} }
} }
@ -419,7 +432,7 @@ public class BSTerrainManager
catch catch
{ {
// Sometimes they give us wonky values of X and Y. Give a warning and return something. // Sometimes they give us wonky values of X and Y. Give a warning and return something.
m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}", PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
LogHeader, terrainBaseXY, regionX, regionY); LogHeader, terrainBaseXY, regionX, regionY);
ret = HEIGHT_GETHEIGHT_RET; ret = HEIGHT_GETHEIGHT_RET;
} }
@ -428,8 +441,8 @@ public class BSTerrainManager
} }
else else
{ {
m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
LogHeader, m_physicsScene.RegionName, tX, tY); LogHeader, PhysicsScene.RegionName, tX, tY);
} }
m_terrainModified = false; m_terrainModified = false;
lastHeight = ret; lastHeight = ret;
@ -453,7 +466,7 @@ public class BSTerrainManager
{ {
m_worldOffset = offset; m_worldOffset = offset;
m_worldMax = extents; m_worldMax = extents;
m_parentScene = pScene; MegaRegionParentPhysicsScene = pScene;
if (pScene != null) if (pScene != null)
{ {
// We are a child. // We are a child.
@ -474,7 +487,7 @@ public class BSTerrainManager
private void DetailLog(string msg, params Object[] args) private void DetailLog(string msg, params Object[] args)
{ {
m_physicsScene.PhysicsLogging.Write(msg, args); PhysicsScene.PhysicsLogging.Write(msg, args);
} }
} }
} }

View File

@ -38,35 +38,112 @@ namespace OpenSim.Region.Physics.BulletSPlugin {
// The physics engine controller class created at initialization // The physics engine controller class created at initialization
public struct BulletSim public struct BulletSim
{ {
public BulletSim(uint worldId, BSScene bss, IntPtr xx) { worldID = worldId; scene = bss; Ptr = xx; } public BulletSim(uint worldId, BSScene bss, IntPtr xx)
{
ptr = xx;
worldID = worldId;
physicsScene = bss;
}
public IntPtr ptr;
public uint worldID; public uint worldID;
// The scene is only in here so very low level routines have a handle to print debug/error messages // The scene is only in here so very low level routines have a handle to print debug/error messages
public BSScene scene; public BSScene physicsScene;
public IntPtr Ptr;
}
public struct BulletShape
{
public BulletShape(IntPtr xx) { Ptr = xx; }
public IntPtr Ptr;
} }
// An allocated Bullet btRigidBody // An allocated Bullet btRigidBody
public struct BulletBody public struct BulletBody
{ {
public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } public BulletBody(uint id, IntPtr xx)
public IntPtr Ptr; {
ID = id;
ptr = xx;
collisionFilter = 0;
collisionMask = 0;
}
public IntPtr ptr;
public uint ID; public uint ID;
public CollisionFilterGroups collisionFilter;
public CollisionFilterGroups collisionMask;
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<id=");
buff.Append(ID.ToString());
buff.Append(",p=");
buff.Append(ptr.ToString("X"));
if (collisionFilter != 0 && collisionMask != 0)
{
buff.Append(",f=");
buff.Append(collisionFilter.ToString("X"));
buff.Append(",m=");
buff.Append(collisionMask.ToString("X"));
}
buff.Append(">");
return buff.ToString();
}
}
public struct BulletShape
{
public BulletShape(IntPtr xx)
{
ptr = xx;
type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
shapeKey = 0;
isNativeShape = false;
}
public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
{
ptr = xx;
type = typ;
shapeKey = 0;
isNativeShape = false;
}
public IntPtr ptr;
public ShapeData.PhysicsShapeType type;
public ulong shapeKey;
public bool isNativeShape;
// Hulls have an underlying mesh. A pointer to it is hidden here.
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<p=");
buff.Append(ptr.ToString("X"));
buff.Append(",s=");
buff.Append(type.ToString());
buff.Append(",k=");
buff.Append(shapeKey.ToString("X"));
buff.Append(",n=");
buff.Append(isNativeShape.ToString());
buff.Append(">");
return buff.ToString();
}
}
// Constraint type values as defined by Bullet
public enum ConstraintType : int
{
POINT2POINT_CONSTRAINT_TYPE = 3,
HINGE_CONSTRAINT_TYPE,
CONETWIST_CONSTRAINT_TYPE,
D6_CONSTRAINT_TYPE,
SLIDER_CONSTRAINT_TYPE,
CONTACT_CONSTRAINT_TYPE,
D6_SPRING_CONSTRAINT_TYPE,
MAX_CONSTRAINT_TYPE
} }
// An allocated Bullet btConstraint // An allocated Bullet btConstraint
public struct BulletConstraint public struct BulletConstraint
{ {
public BulletConstraint(IntPtr xx) { Ptr = xx; } public BulletConstraint(IntPtr xx)
public IntPtr Ptr; {
ptr = xx;
}
public IntPtr ptr;
} }
// An allocated HeightMapThing which hold various heightmap info // An allocated HeightMapThing which holds various heightmap info.
// Made a class rather than a struct so there would be only one // Made a class rather than a struct so there would be only one
// instance of this and C# will pass around pointers rather // instance of this and C# will pass around pointers rather
// than making copies. // than making copies.
@ -114,7 +191,9 @@ public struct ShapeData
SHAPE_CYLINDER = 4, SHAPE_CYLINDER = 4,
SHAPE_SPHERE = 5, SHAPE_SPHERE = 5,
SHAPE_MESH = 6, SHAPE_MESH = 6,
SHAPE_HULL = 7 SHAPE_HULL = 7,
SHAPE_GROUNDPLANE = 8,
SHAPE_TERRAIN = 9,
}; };
public uint ID; public uint ID;
public PhysicsShapeType Type; public PhysicsShapeType Type;
@ -130,10 +209,21 @@ public struct ShapeData
public float Restitution; public float Restitution;
public float Collidable; // true of things bump into this public float Collidable; // true of things bump into this
public float Static; // true if a static object. Otherwise gravity, etc. public float Static; // true if a static object. Otherwise gravity, etc.
public float Solid; // true if object cannot be passed through
public Vector3 Size;
// note that bools are passed as floats since bool size changes by language and architecture // note that bools are passed as floats since bool size changes by language and architecture
public const float numericTrue = 1f; public const float numericTrue = 1f;
public const float numericFalse = 0f; public const float numericFalse = 0f;
// The native shapes have predefined shape hash keys
public enum FixedShapeKey : ulong
{
KEY_BOX = 1,
KEY_SPHERE = 2,
KEY_CONE = 3,
KEY_CYLINDER = 4,
}
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct SweepHit public struct SweepHit
@ -227,7 +317,17 @@ public enum ActivationState : uint
ISLAND_SLEEPING, ISLAND_SLEEPING,
WANTS_DEACTIVATION, WANTS_DEACTIVATION,
DISABLE_DEACTIVATION, DISABLE_DEACTIVATION,
DISABLE_SIMULATION DISABLE_SIMULATION,
}
public enum CollisionObjectTypes : int
{
CO_COLLISION_OBJECT = 1 << 0,
CO_RIGID_BODY = 1 << 1,
CO_GHOST_OBJECT = 1 << 2,
CO_SOFT_BODY = 1 << 3,
CO_HF_FLUID = 1 << 4,
CO_USER_TYPE = 1 << 5,
} }
// Values used by Bullet and BulletSim to control object properties. // Values used by Bullet and BulletSim to control object properties.
@ -244,77 +344,60 @@ public enum CollisionFlags : uint
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
// Following used by BulletSim to control collisions // Following used by BulletSim to control collisions
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
BS_VOLUME_DETECT_OBJECT = 1 << 11, // BS_VOLUME_DETECT_OBJECT = 1 << 11,
BS_PHANTOM_OBJECT = 1 << 12, // BS_PHANTOM_OBJECT = 1 << 12,
BS_PHYSICAL_OBJECT = 1 << 13, // BS_PHYSICAL_OBJECT = 1 << 13,
BS_TERRAIN_OBJECT = 1 << 14, // BS_TERRAIN_OBJECT = 1 << 14,
BS_NONE = 0, BS_NONE = 0,
BS_ALL = 0xFFFFFFFF BS_ALL = 0xFFFFFFFF,
// These are the collision flags switched depending on physical state.
// The other flags are used for other things and should not be fooled with.
BS_ACTIVE = CF_STATIC_OBJECT
| CF_KINEMATIC_OBJECT
| CF_NO_CONTACT_RESPONSE
// | BS_VOLUME_DETECT_OBJECT
// | BS_PHANTOM_OBJECT
// | BS_PHYSICAL_OBJECT,
}; };
// Values for collisions groups and masks // Values for collisions groups and masks
public enum CollisionFilterGroups : uint public enum CollisionFilterGroups : uint
{ {
NoneFilter = 0, // Don't use the bit definitions!! Define the use in a
DefaultFilter = 1 << 0, // filter/mask definition below. This way collision interactions
StaticFilter = 1 << 1, // are more easily debugged.
KinematicFilter = 1 << 2, BNoneFilter = 0,
DebrisFilter = 1 << 3, BDefaultFilter = 1 << 0,
SensorTrigger = 1 << 4, BStaticFilter = 1 << 1,
CharacterFilter = 1 << 5, BKinematicFilter = 1 << 2,
AllFilter = 0xFFFFFFFF, BDebrisFilter = 1 << 3,
BSensorTrigger = 1 << 4,
BCharacterFilter = 1 << 5,
BAllFilter = 0xFFFFFFFF,
// Filter groups defined by BulletSim // Filter groups defined by BulletSim
GroundPlaneFilter = 1 << 10, BGroundPlaneFilter = 1 << 10,
TerrainFilter = 1 << 11, BTerrainFilter = 1 << 11,
RaycastFilter = 1 << 12, BRaycastFilter = 1 << 12,
SolidFilter = 1 << 13, BSolidFilter = 1 << 13,
// The collsion filters and masked are defined in one place -- don't want them scattered
AvatarFilter = BCharacterFilter,
AvatarMask = BAllFilter,
ObjectFilter = BSolidFilter,
ObjectMask = BAllFilter,
StaticObjectFilter = BStaticFilter,
StaticObjectMask = BAllFilter,
VolumeDetectFilter = BSensorTrigger,
VolumeDetectMask = ~BSensorTrigger,
TerrainFilter = BTerrainFilter,
TerrainMask = BAllFilter & ~BStaticFilter,
GroundPlaneFilter = BAllFilter,
GroundPlaneMask = BAllFilter
}; };
// For each type, we first clear and then set the collision flags
public enum ClearCollisionFlag : uint
{
Terrain = CollisionFlags.BS_ALL,
Phantom = CollisionFlags.BS_ALL,
VolumeDetect = CollisionFlags.BS_ALL,
PhysicalObject = CollisionFlags.BS_ALL,
StaticObject = CollisionFlags.BS_ALL
}
public enum SetCollisionFlag : uint
{
Terrain = CollisionFlags.CF_STATIC_OBJECT
| CollisionFlags.BS_TERRAIN_OBJECT,
Phantom = CollisionFlags.CF_STATIC_OBJECT
| CollisionFlags.BS_PHANTOM_OBJECT
| CollisionFlags.CF_NO_CONTACT_RESPONSE,
VolumeDetect = CollisionFlags.CF_STATIC_OBJECT
| CollisionFlags.BS_VOLUME_DETECT_OBJECT
| CollisionFlags.CF_NO_CONTACT_RESPONSE,
PhysicalObject = CollisionFlags.BS_PHYSICAL_OBJECT,
StaticObject = CollisionFlags.CF_STATIC_OBJECT,
}
// Collision filters used for different types of objects
public enum SetCollisionFilter : uint
{
Terrain = CollisionFilterGroups.AllFilter,
Phantom = CollisionFilterGroups.GroundPlaneFilter
| CollisionFilterGroups.TerrainFilter,
VolumeDetect = CollisionFilterGroups.AllFilter,
PhysicalObject = CollisionFilterGroups.AllFilter,
StaticObject = CollisionFilterGroups.AllFilter,
}
// Collision masks used for different types of objects
public enum SetCollisionMask : uint
{
Terrain = CollisionFilterGroups.AllFilter,
Phantom = CollisionFilterGroups.GroundPlaneFilter
| CollisionFilterGroups.TerrainFilter,
VolumeDetect = CollisionFilterGroups.AllFilter,
PhysicalObject = CollisionFilterGroups.AllFilter,
StaticObject = CollisionFilterGroups.AllFilter
}
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
@ -516,11 +599,10 @@ public static extern IntPtr CreateHullShape2(IntPtr world,
int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr BuildHullShape2(IntPtr world, IntPtr meshShape); public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr BuildNativeShape2(IntPtr world, public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
float shapeType, float collisionMargin, Vector3 scale);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool IsNativeShape2(IntPtr shape); public static extern bool IsNativeShape2(IntPtr shape);
@ -535,16 +617,25 @@ public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShap
public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape); public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, IntPtr constructionInfo); public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, Vector3 pos, Quaternion rot); public static extern int GetBodyType2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, Vector3 pos, Quaternion rot); public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr AllocateBodyInfo2(IntPtr obj); public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
@ -963,6 +1054,9 @@ public static extern Vector3 GetPushVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetTurnVelocity2(IntPtr obj); public static extern Vector3 GetTurnVelocity2(IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
// ===================================================================================== // =====================================================================================
// btCollisionShape entries // btCollisionShape entries
@ -1014,9 +1108,6 @@ public static extern void SetMargin2(IntPtr shape, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern float GetMargin2(IntPtr shape); public static extern float GetMargin2(IntPtr shape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetCollisionFilterMask(IntPtr shape, uint filter, uint mask);
// ===================================================================================== // =====================================================================================
// Debugging // Debugging
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]

View File

@ -5465,27 +5465,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
/// Returns the index of the first occurrence of test /// Returns the index of the first occurrence of test
/// in src. /// in src.
/// </summary> /// </summary>
/// <param name="src">Source list</param>
/// <param name="test">List to search for</param>
/// <returns>
/// The index number of the point in src where test was found if it was found.
/// Otherwise returns -1
/// </returns>
public LSL_Integer llListFindList(LSL_List src, LSL_List test) public LSL_Integer llListFindList(LSL_List src, LSL_List test)
{ {
int index = -1; int index = -1;
int length = src.Length - test.Length + 1; int length = src.Length - test.Length + 1;
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
// If either list is empty, do not match // If either list is empty, do not match
if (src.Length != 0 && test.Length != 0) if (src.Length != 0 && test.Length != 0)
{ {
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
if (src.Data[i].Equals(test.Data[0])) // Why this piece of insanity? This is because most script constants are C# value types (e.g. int)
// rather than wrapped LSL types. Such a script constant does not have int.Equal(LSL_Integer) code
// and so the comparison fails even if the LSL_Integer conceptually has the same value.
// Therefore, here we test Equals on both the source and destination objects.
// However, a future better approach may be use LSL struct script constants (e.g. LSL_Integer(1)).
if (src.Data[i].Equals(test.Data[0]) || test.Data[0].Equals(src.Data[i]))
{ {
int j; int j;
for (j = 1; j < test.Length; j++) for (j = 1; j < test.Length; j++)
if (!src.Data[i+j].Equals(test.Data[j])) if (!(src.Data[i+j].Equals(test.Data[j]) || test.Data[j].Equals(src.Data[i+j])))
break; break;
if (j == test.Length) if (j == test.Length)
{ {
index = i; index = i;
@ -5496,19 +5505,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
} }
return index; return index;
} }
public LSL_String llGetObjectName() public LSL_String llGetObjectName()
{ {
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
return m_host.Name!=null?m_host.Name:String.Empty; return m_host.Name !=null ? m_host.Name : String.Empty;
} }
public void llSetObjectName(string name) public void llSetObjectName(string name)
{ {
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
m_host.Name = name!=null?name:String.Empty; m_host.Name = name != null ? name : String.Empty;
} }
public LSL_String llGetDate() public LSL_String llGetDate()

View File

@ -0,0 +1,134 @@
/*
* 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 NUnit.Framework;
using OpenSim.Framework;
using OpenSim.Tests.Common;
using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.Framework.Scenes;
using Nini.Config;
using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenMetaverse;
using OpenSim.Tests.Common.Mock;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
namespace OpenSim.Region.ScriptEngine.Shared.Tests
{
[TestFixture]
public class LSL_ApiListTests
{
private LSL_Api m_lslApi;
[SetUp]
public void SetUp()
{
IConfigSource initConfigSource = new IniConfigSource();
IConfig config = initConfigSource.AddConfig("XEngine");
config.Set("Enabled", "true");
Scene scene = new SceneHelpers().SetupScene();
SceneObjectPart part = SceneHelpers.AddSceneObject(scene).RootPart;
XEngine.XEngine engine = new XEngine.XEngine();
engine.Initialise(initConfigSource);
engine.AddRegion(scene);
m_lslApi = new LSL_Api();
m_lslApi.Initialize(engine, part, null);
}
[Test]
public void TestllListFindList()
{
TestHelpers.InMethod();
LSL_List src = new LSL_List(new LSL_Integer(1), new LSL_Integer(2), new LSL_Integer(3));
{
// Test for a single item that should be found
int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(4)));
Assert.That(result, Is.EqualTo(-1));
}
{
// Test for a single item that should be found
int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(2)));
Assert.That(result, Is.EqualTo(1));
}
{
// Test for a constant that should be found
int result = m_lslApi.llListFindList(src, new LSL_List(ScriptBaseClass.AGENT));
Assert.That(result, Is.EqualTo(0));
}
{
// Test for a list that should be found
int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(2), new LSL_Integer(3)));
Assert.That(result, Is.EqualTo(1));
}
{
// Test for a single item not in the list
int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_Integer(4)));
Assert.That(result, Is.EqualTo(-1));
}
{
// Test for something that should not be cast
int result = m_lslApi.llListFindList(src, new LSL_List(new LSL_String("4")));
Assert.That(result, Is.EqualTo(-1));
}
{
// Test for a list not in the list
int result
= m_lslApi.llListFindList(
src, new LSL_List(new LSL_Integer(2), new LSL_Integer(3), new LSL_Integer(4)));
Assert.That(result, Is.EqualTo(-1));
}
{
LSL_List srcWithConstants
= new LSL_List(new LSL_Integer(3), ScriptBaseClass.AGENT, ScriptBaseClass.OS_NPC_LAND_AT_TARGET);
// Test for constants that appears in the source list that should be found
int result
= m_lslApi.llListFindList(srcWithConstants, new LSL_List(new LSL_Integer(1), new LSL_Integer(2)));
Assert.That(result, Is.EqualTo(1));
}
}
}
}

View File

@ -108,7 +108,7 @@ namespace OpenSim.Services.Connectors
if (asset == null) if (asset == null)
{ {
asset = SynchronousRestObjectRequester. asset = SynchronousRestObjectRequester.
MakeRequest<int, AssetBase>("GET", uri, 0); MakeRequest<int, AssetBase>("GET", uri, 0, 30);
if (m_Cache != null) if (m_Cache != null)
m_Cache.Cache(asset); m_Cache.Cache(asset);
@ -221,7 +221,7 @@ namespace OpenSim.Services.Connectors
m_AssetHandlers.Remove(id); m_AssetHandlers.Remove(id);
} }
handlers.Invoke(a); handlers.Invoke(a);
}); }, 30);
success = true; success = true;
} }

View File

@ -57,10 +57,13 @@ namespace OpenSim.Services.HypergridService
private static IUserAccountService m_UserAccountService; private static IUserAccountService m_UserAccountService;
private static IUserAgentService m_UserAgentService; private static IUserAgentService m_UserAgentService;
private static ISimulationService m_SimulationService; private static ISimulationService m_SimulationService;
private static IGridUserService m_GridUserService;
protected string m_AllowedClients = string.Empty; private static string m_AllowedClients = string.Empty;
protected string m_DeniedClients = string.Empty; private static string m_DeniedClients = string.Empty;
private static bool m_ForeignAgentsAllowed = true; private static bool m_ForeignAgentsAllowed = true;
private static List<string> m_ForeignsAllowedExceptions = new List<string>();
private static List<string> m_ForeignsDisallowedExceptions = new List<string>();
private static UUID m_ScopeID; private static UUID m_ScopeID;
private static bool m_AllowTeleportsToAnyRegion; private static bool m_AllowTeleportsToAnyRegion;
@ -82,8 +85,9 @@ namespace OpenSim.Services.HypergridService
string gridService = serverConfig.GetString("GridService", String.Empty); string gridService = serverConfig.GetString("GridService", String.Empty);
string presenceService = serverConfig.GetString("PresenceService", String.Empty); string presenceService = serverConfig.GetString("PresenceService", String.Empty);
string simulationService = serverConfig.GetString("SimulationService", String.Empty); string simulationService = serverConfig.GetString("SimulationService", String.Empty);
string gridUserService = serverConfig.GetString("GridUserService", String.Empty);
// These 3 are mandatory, the others aren't // These are mandatory, the others aren't
if (gridService == string.Empty || presenceService == string.Empty) if (gridService == string.Empty || presenceService == string.Empty)
throw new Exception("Incomplete specifications, Gatekeeper Service cannot function."); throw new Exception("Incomplete specifications, Gatekeeper Service cannot function.");
@ -103,6 +107,8 @@ namespace OpenSim.Services.HypergridService
m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args); m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args);
if (homeUsersService != string.Empty) if (homeUsersService != string.Empty)
m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args); m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args);
if (gridUserService != string.Empty)
m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args);
if (simService != null) if (simService != null)
m_SimulationService = simService; m_SimulationService = simService;
@ -113,6 +119,9 @@ namespace OpenSim.Services.HypergridService
m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty); m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty);
m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true); m_ForeignAgentsAllowed = serverConfig.GetBoolean("ForeignAgentsAllowed", true);
LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_ForeignsAllowedExceptions);
LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_ForeignsDisallowedExceptions);
if (m_GridService == null || m_PresenceService == null || m_SimulationService == null) if (m_GridService == null || m_PresenceService == null || m_SimulationService == null)
throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function."); throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function.");
@ -125,6 +134,15 @@ namespace OpenSim.Services.HypergridService
{ {
} }
protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, List<string> exceptions)
{
string value = config.GetString(variable, string.Empty);
string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in parts)
exceptions.Add(s.Trim());
}
public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason) public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason)
{ {
regionID = UUID.Zero; regionID = UUID.Zero;
@ -260,17 +278,26 @@ namespace OpenSim.Services.HypergridService
m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok"); m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok");
// //
// Foreign agents allowed // Foreign agents allowed? Exceptions?
// //
if (account == null && !m_ForeignAgentsAllowed) if (account == null)
{ {
reason = "Unauthorized"; bool allowed = m_ForeignAgentsAllowed;
m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1}. Refusing service.",
aCircuit.firstname, aCircuit.lastname); if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions))
allowed = false;
if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions))
allowed = true;
if (!allowed)
{
reason = "Destination does not allow visitors from your world";
m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agents are not permitted {0} {1} @ {2}. Refusing service.",
aCircuit.firstname, aCircuit.lastname, aCircuit.ServiceURLs["HomeURI"]);
return false; return false;
} }
}
// May want to authorize
bool isFirstLogin = false; bool isFirstLogin = false;
// //
@ -281,6 +308,7 @@ namespace OpenSim.Services.HypergridService
isFirstLogin = true; isFirstLogin = true;
else else
{
if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID)) if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID))
{ {
reason = "Unable to login presence"; reason = "Unable to login presence";
@ -290,6 +318,26 @@ namespace OpenSim.Services.HypergridService
} }
m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok"); m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok");
// Also login foreigners with GridUser service
if (m_GridUserService != null && account == null)
{
string userId = aCircuit.AgentID.ToString();
string first = aCircuit.firstname, last = aCircuit.lastname;
if (last.StartsWith("@"))
{
string[] parts = aCircuit.firstname.Split('.');
if (parts.Length >= 2)
{
first = parts[0];
last = parts[1];
}
}
userId += ";" + aCircuit.ServiceURLs["HomeURI"] + ";" + first + " " + last;
m_GridUserService.LoggedIn(userId);
}
}
// //
// Get the region // Get the region
// //
@ -393,6 +441,27 @@ namespace OpenSim.Services.HypergridService
#region Misc #region Misc
private bool IsException(AgentCircuitData aCircuit, List<string> exceptions)
{
bool exception = false;
if (exceptions.Count > 0) // we have exceptions
{
// Retrieve the visitor's origin
string userURL = aCircuit.ServiceURLs["HomeURI"].ToString();
if (!userURL.EndsWith("/"))
userURL += "/";
if (exceptions.Find(delegate(string s)
{
if (!s.EndsWith("/"))
s += "/";
return s == userURL;
}) != null)
exception = true;
}
return exception;
}
#endregion #endregion
} }

View File

@ -58,6 +58,8 @@ namespace OpenSim.Services.HypergridService
private UserAccountCache m_Cache; private UserAccountCache m_Cache;
private AssetPermissions m_AssetPerms;
public HGAssetService(IConfigSource config, string configName) : base(config, configName) public HGAssetService(IConfigSource config, string configName) : base(config, configName)
{ {
m_log.Debug("[HGAsset Service]: Starting"); m_log.Debug("[HGAsset Service]: Starting");
@ -80,6 +82,10 @@ namespace OpenSim.Services.HypergridService
m_HomeURL = assetConfig.GetString("HomeURI", m_HomeURL); m_HomeURL = assetConfig.GetString("HomeURI", m_HomeURL);
m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
// Permissions
m_AssetPerms = new AssetPermissions(assetConfig);
} }
#region IAssetService overrides #region IAssetService overrides
@ -90,6 +96,9 @@ namespace OpenSim.Services.HypergridService
if (asset == null) if (asset == null)
return null; return null;
if (!m_AssetPerms.AllowedExport(asset.Type))
return null;
if (asset.Metadata.Type == (sbyte)AssetType.Object) if (asset.Metadata.Type == (sbyte)AssetType.Object)
asset.Data = AdjustIdentifiers(asset.Data); ; asset.Data = AdjustIdentifiers(asset.Data); ;
@ -112,16 +121,27 @@ namespace OpenSim.Services.HypergridService
public override byte[] GetData(string id) public override byte[] GetData(string id)
{ {
byte[] data = base.GetData(id); AssetBase asset = Get(id);
if (data == null) if (asset == null)
return null; return null;
return AdjustIdentifiers(data); if (!m_AssetPerms.AllowedExport(asset.Type))
return null;
return asset.Data;
} }
//public virtual bool Get(string id, Object sender, AssetRetrieved handler) //public virtual bool Get(string id, Object sender, AssetRetrieved handler)
public override string Store(AssetBase asset)
{
if (!m_AssetPerms.AllowedImport(asset.Type))
return string.Empty;
return base.Store(asset);
}
public override bool Delete(string id) public override bool Delete(string id)
{ {
// NOGO // NOGO

View File

@ -77,6 +77,10 @@ namespace OpenSim.Services.HypergridService
protected static bool m_BypassClientVerification; protected static bool m_BypassClientVerification;
private static Dictionary<int, bool> m_ForeignTripsAllowed = new Dictionary<int, bool>();
private static Dictionary<int, List<string>> m_TripsAllowedExceptions = new Dictionary<int, List<string>>();
private static Dictionary<int, List<string>> m_TripsDisallowedExceptions = new Dictionary<int, List<string>>();
public UserAgentService(IConfigSource config) : this(config, null) public UserAgentService(IConfigSource config) : this(config, null)
{ {
} }
@ -121,6 +125,12 @@ namespace OpenSim.Services.HypergridService
m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args); m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountService, args); m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountService, args);
m_LevelOutsideContacts = serverConfig.GetInt("LevelOutsideContacts", 0);
LoadTripPermissionsFromConfig(serverConfig, "ForeignTripsAllowed");
LoadDomainExceptionsFromConfig(serverConfig, "AllowExcept", m_TripsAllowedExceptions);
LoadDomainExceptionsFromConfig(serverConfig, "DisallowExcept", m_TripsDisallowedExceptions);
m_GridName = serverConfig.GetString("ExternalName", string.Empty); m_GridName = serverConfig.GetString("ExternalName", string.Empty);
if (m_GridName == string.Empty) if (m_GridName == string.Empty)
{ {
@ -130,10 +140,43 @@ namespace OpenSim.Services.HypergridService
if (!m_GridName.EndsWith("/")) if (!m_GridName.EndsWith("/"))
m_GridName = m_GridName + "/"; m_GridName = m_GridName + "/";
m_LevelOutsideContacts = serverConfig.GetInt("LevelOutsideContacts", 0);
} }
} }
protected void LoadTripPermissionsFromConfig(IConfig config, string variable)
{
foreach (string keyName in config.GetKeys())
{
if (keyName.StartsWith(variable + "_Level_"))
{
int level = 0;
if (Int32.TryParse(keyName.Replace(variable + "_Level_", ""), out level))
m_ForeignTripsAllowed.Add(level, config.GetBoolean(keyName, true));
}
}
}
protected void LoadDomainExceptionsFromConfig(IConfig config, string variable, Dictionary<int, List<string>> exceptions)
{
foreach (string keyName in config.GetKeys())
{
if (keyName.StartsWith(variable + "_Level_"))
{
int level = 0;
if (Int32.TryParse(keyName.Replace(variable + "_Level_", ""), out level) && !exceptions.ContainsKey(level))
{
exceptions.Add(level, new List<string>());
string value = config.GetString(keyName, string.Empty);
string[] parts = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in parts)
exceptions[level].Add(s.Trim());
}
}
}
}
public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt) public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt)
{ {
position = new Vector3(128, 128, 0); lookAt = Vector3.UnitY; position = new Vector3(128, 128, 0); lookAt = Vector3.UnitY;
@ -166,13 +209,39 @@ namespace OpenSim.Services.HypergridService
m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}", m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}",
agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI); agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI);
if (m_UserAccountService.GetUserAccount(UUID.Zero, agentCircuit.AgentID) == null) string gridName = gatekeeper.ServerURI;
UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, agentCircuit.AgentID);
if (account == null)
{ {
m_log.WarnFormat("[USER AGENT SERVICE]: Someone attempted to lauch a foreign user from here {0} {1}", agentCircuit.firstname, agentCircuit.lastname); m_log.WarnFormat("[USER AGENT SERVICE]: Someone attempted to lauch a foreign user from here {0} {1}", agentCircuit.firstname, agentCircuit.lastname);
reason = "Forbidden to launch your agents from here"; reason = "Forbidden to launch your agents from here";
return false; return false;
} }
// Is this user allowed to go there?
if (m_GridName != gridName)
{
if (m_ForeignTripsAllowed.ContainsKey(account.UserLevel))
{
bool allowed = m_ForeignTripsAllowed[account.UserLevel];
if (m_ForeignTripsAllowed[account.UserLevel] && IsException(gridName, account.UserLevel, m_TripsAllowedExceptions))
allowed = false;
if (!m_ForeignTripsAllowed[account.UserLevel] && IsException(gridName, account.UserLevel, m_TripsDisallowedExceptions))
allowed = true;
if (!allowed)
{
reason = "Your world does not allow you to visit the destination";
m_log.InfoFormat("[USER AGENT SERVICE]: Agents not permitted to visit {0}. Refusing service.", gridName);
return false;
}
}
}
// Take the IP address + port of the gatekeeper (reg) plus the info of finalDestination // Take the IP address + port of the gatekeeper (reg) plus the info of finalDestination
GridRegion region = new GridRegion(gatekeeper); GridRegion region = new GridRegion(gatekeeper);
region.ServerURI = gatekeeper.ServerURI; region.ServerURI = gatekeeper.ServerURI;
@ -189,7 +258,6 @@ namespace OpenSim.Services.HypergridService
bool success = false; bool success = false;
string myExternalIP = string.Empty; string myExternalIP = string.Empty;
string gridName = gatekeeper.ServerURI;
m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName); m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName);
@ -588,6 +656,35 @@ namespace OpenSim.Services.HypergridService
else else
return UUID.Zero; return UUID.Zero;
} }
#region Misc
private bool IsException(string dest, int level, Dictionary<int, List<string>> exceptions)
{
if (!exceptions.ContainsKey(level))
return false;
bool exception = false;
if (exceptions[level].Count > 0) // we have exceptions
{
string destination = dest;
if (!destination.EndsWith("/"))
destination += "/";
if (exceptions[level].Find(delegate(string s)
{
if (!s.EndsWith("/"))
s += "/";
return s == destination;
}) != null)
exception = true;
}
return exception;
}
#endregion
} }
class TravelingAgentInfo class TravelingAgentInfo

View File

@ -97,7 +97,6 @@ namespace OpenSim.Services.Interfaces
result["Login"] = Login.ToString(); result["Login"] = Login.ToString();
result["Logout"] = Logout.ToString(); result["Logout"] = Logout.ToString();
return result; return result;
} }
} }

View File

@ -49,7 +49,7 @@ namespace OpenSim.Services.UserAccountService
m_log.Debug("[USER GRID SERVICE]: Starting user grid service"); m_log.Debug("[USER GRID SERVICE]: Starting user grid service");
} }
public GridUserInfo GetGridUserInfo(string userID) public virtual GridUserInfo GetGridUserInfo(string userID)
{ {
GridUserData d = m_Database.Get(userID); GridUserData d = m_Database.Get(userID);
@ -122,17 +122,6 @@ namespace OpenSim.Services.UserAccountService
return m_Database.Store(d); return m_Database.Store(d);
} }
protected bool StoreGridUserInfo(GridUserInfo info)
{
GridUserData d = new GridUserData();
d.Data["HomeRegionID"] = info.HomeRegionID.ToString();
d.Data["HomePosition"] = info.HomePosition.ToString();
d.Data["HomeLookAt"] = info.HomeLookAt.ToString();
return m_Database.Store(d);
}
public bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt) public bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt)
{ {
GridUserData d = m_Database.Get(userID); GridUserData d = m_Database.Get(userID);

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,5 @@
<configuration> <configuration>
<dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet-2.1.3.0-dotnet-1.dylib" /> <dllmap os="osx" dll="openjpeg-dotnet.dll" target="lib64/libopenjpeg-dotnet-2.1.5.0-dotnet-1.dylib" />
<dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet-2.1.3.0-dotnet-1-x86_64" /> <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-x86_64" />
<dllmap os="!windows,osx" cpu="x86-64,ia64" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-2.1.3.0-dotnet-1-x86_64" /> <dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet" />
<dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet.dll" target="lib32/libopenjpeg-dotnet-2.1.3.0-dotnet-1-i686" />
<dllmap os="!windows,osx" cpu="x86" dll="openjpeg-dotnet-x86_64.dll" target="lib64/libopenjpeg-dotnet-2.1.3.0-dotnet-1-i686" />
</configuration> </configuration>

Binary file not shown.

View File

@ -97,6 +97,10 @@
;; from the selected region_info_source. ;; from the selected region_info_source.
; allow_regionless = false ; allow_regionless = false
;# {MaxPrimUndos} {} {Maximum number of undos avialable for position, rotation and scale changes of each prim} {} 20
;; Increasing the number of undos available number will increase memory usage.
MaxPrimUndos = 20
;# {NonPhysicalPrimMin} {} {Minimum size of nonphysical prims?} {} 0.001 ;# {NonPhysicalPrimMin} {} {Minimum size of nonphysical prims?} {} 0.001
;; Minimum size for non-physical prims. Affects resizing of existing ;; Minimum size for non-physical prims. Affects resizing of existing
;; prims. This can be overriden in the region config file (as ;; prims. This can be overriden in the region config file (as

View File

@ -85,6 +85,10 @@
;; from the selected region_info_source. ;; from the selected region_info_source.
allow_regionless = false allow_regionless = false
; Maximum number of position, rotation and scale changes for each prim that the simulator will store for later undos
; Increasing this number will increase memory usage.
MaxPrimUndos = 20
; Maximum size of non physical prims. Affects resizing of existing prims. This can be overriden in the region config file (as NonPhysicalPrimMax!). ; Maximum size of non physical prims. Affects resizing of existing prims. This can be overriden in the region config file (as NonPhysicalPrimMax!).
NonPhysicalPrimMax = 256 NonPhysicalPrimMax = 256
@ -673,8 +677,7 @@
; If true, avatar appearance information is resent to other avatars in the simulator every 60 seconds. ; If true, avatar appearance information is resent to other avatars in the simulator every 60 seconds.
; This may help with some situations where avatars are persistently grey, though it will not help ; This may help with some situations where avatars are persistently grey, though it will not help
; in other situations (e.g. appearance baking failures where the avatar only appears as a cloud to others). ; in other situations (e.g. appearance baking failures where the avatar only appears as a cloud to others).
; This setting is experimental. ResendAppearanceUpdates = true
ResendAppearanceUpdates = false
[Attachments] [Attachments]
@ -933,10 +936,10 @@
MaxPersistantManifoldPoolSize = 0 MaxPersistantManifoldPoolSize = 0
ShouldDisableContactPoolDynamicAllocation = False ShouldDisableContactPoolDynamicAllocation = False
ShouldForceUpdateAllAabbs = False ShouldForceUpdateAllAabbs = False
ShouldRandomizeSolverOrder = False ShouldRandomizeSolverOrder = True
ShouldSplitSimulationIslands = False ShouldSplitSimulationIslands = True
ShouldEnableFrictionCaching = False ShouldEnableFrictionCaching = False
NumberOfSolverIterations = 0; NumberOfSolverIterations = 0
; Linkset constraint parameters ; Linkset constraint parameters
LinkConstraintUseFrameOffset = False LinkConstraintUseFrameOffset = False
@ -1034,30 +1037,31 @@
;default_appearance = default_appearance.xml ;default_appearance = default_appearance.xml
[RestPlugins] ; RestPlugins are not currently operational.
; Change this to true to enable REST Plugins. This must be true if you wish to use ;[RestPlugins]
; REST Region or REST Asset and Inventory Plugins ; ; Change this to true to enable REST Plugins. This must be true if you wish to use
enabled = false ; ; REST Region or REST Asset and Inventory Plugins
god_key = SECRET ; enabled = false
prefix = /admin ; god_key = SECRET
; prefix = /admin
[RestRegionPlugin] ;[RestRegionPlugin]
; Change this to true to enable the REST Region Plugin ; ; Change this to true to enable the REST Region Plugin
enabled = false ; enabled = false
[RestHandler] ;[RestHandler]
; Change this to true to enable the REST Asset and Inventory Plugin ; ; Change this to true to enable the REST Asset and Inventory Plugin
enabled = false ; enabled = false
authenticate = true ; authenticate = true
secured = true ; secured = true
extended-escape = true ; extended-escape = true
realm = OpenSim REST ; realm = OpenSim REST
dump-asset = false ; dump-asset = false
path-fill = true ; path-fill = true
dump-line-size = 32 ; dump-line-size = 32
flush-on-error = true ; flush-on-error = true
; IRC bridge is experimental, so if it breaks... keep both parts... yada yada ; IRC bridge is experimental, so if it breaks... keep both parts... yada yada

View File

@ -396,6 +396,18 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003
;AllowedClients = "" ;AllowedClients = ""
;DeniedClients = "" ;DeniedClients = ""
;; Are foreign visitors allowed?
;ForeignAgentsAllowed = true
;;
;; If ForeignAgentsAllowed is true, make exceptions using AllowExcept.
;; Leave blank or commented for no exceptions.
; AllowExcept = "http://griefer.com:8002, http://enemy.com:8002"
;;
;; If ForeignAgentsAllowed is false, make exceptions using DisallowExcept
;; Leave blank or commented for no exceptions.
; DisallowExcept = "http://myfriendgrid.com:8002, http://myboss.com:8002"
[UserAgentService] [UserAgentService]
LocalServiceModule = "OpenSim.Services.HypergridService.dll:UserAgentService" LocalServiceModule = "OpenSim.Services.HypergridService.dll:UserAgentService"
;; for the service ;; for the service
@ -416,6 +428,24 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003
; User level required to be contacted from other grids ; User level required to be contacted from other grids
;LevelOutsideContacts = 0 ;LevelOutsideContacts = 0
;; Restrictions on destinations of local users.
;; Are local users allowed to visit other grids?
;; What user level? Use variables of this forrm:
;; ForeignTripsAllowed_Level_<UserLevel> = true | false
;; (the default is true)
;; For example:
; ForeignTripsAllowed_Level_0 = false
; ForeignTripsAllowed_Level_200 = true ; true is default, no need to say it
;;
;; If ForeignTripsAllowed is false, make exceptions using DisallowExcept
;; Leave blank or commented for no exceptions.
; DisallowExcept_Level_0 = "http://myothergrid.com:8002, http://boss.com:8002"
;;
;; If ForeignTripsAllowed is true, make exceptions using AllowExcept.
;; Leave blank or commented for no exceptions.
; AllowExcept_Level_200 = "http://griefer.com:8002, http://enemy.com:8002"
; * The interface that local users get when they are in other grids. ; * The interface that local users get when they are in other grids.
; * This restricts the inventory operations while in other grids. ; * This restricts the inventory operations while in other grids.
; * Still not completely safe, especially if users perform inventory operations ; * Still not completely safe, especially if users perform inventory operations
@ -437,6 +467,18 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
HomeURI = "http://127.0.0.1:8002" HomeURI = "http://127.0.0.1:8002"
;; The asset types that this grid can export to / import from other grids.
;; Comma separated.
;; Valid values are all the asset types in OpenMetaverse.AssetType, namely:
;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText,
;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh
;;
;; Leave blank or commented if you don't want to apply any restrictions.
;; A more strict, but still reasonable, policy may be to disallow the exchange
;; of scripts, like so:
; DisallowExport ="LSLText"
; DisallowImport ="LSLBytecode"
[HGFriendsService] [HGFriendsService]
LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGFriendsService" LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGFriendsService"
UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService"

View File

@ -137,6 +137,26 @@
;; uncomment the next line. You may want to do this on sims that have licensed content. ;; uncomment the next line. You may want to do this on sims that have licensed content.
; OutboundPermission = False ; OutboundPermission = False
[HGAssetService]
;
; === HG ONLY ===
; Change this to your server
; accessible from other grids
;
HomeURI = "http://mygridserver.com:8002"
;; The asset types that this grid can export to / import from other grids.
;; Comma separated.
;; Valid values are all the asset types in OpenMetaverse.AssetType, namely:
;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText,
;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh
;;
;; Leave blank or commented if you don't want to apply any restrictions.
;; A more strict, but still reasonable, policy may be to disallow the exchange
;; of scripts, like so:
; DisallowExport ="LSLText"
; DisallowImport ="LSLBytecode"
[HGFriendsModule] [HGFriendsModule]
; User level required to be able to send friendship invitations to foreign users ; User level required to be able to send friendship invitations to foreign users
;LevelHGFriends = 0; ;LevelHGFriends = 0;

View File

@ -53,6 +53,19 @@
[HGAssetService] [HGAssetService]
HomeURI = "http://127.0.0.1:9000" HomeURI = "http://127.0.0.1:9000"
;; The asset types that this grid can export to / import from other grids.
;; Comma separated.
;; Valid values are all the asset types in OpenMetaverse.AssetType, namely:
;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText,
;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh
;;
;; Leave blank or commented if you don't want to apply any restrictions.
;; A more strict, but still reasonable, policy may be to disallow the exchange
;; of scripts, like so:
; DisallowExport ="LSLText"
; DisallowImport ="LSLBytecode"
[HGInventoryAccessModule] [HGInventoryAccessModule]
HomeURI = "http://127.0.0.1:9000" HomeURI = "http://127.0.0.1:9000"
Gatekeeper = "http://127.0.0.1:9000" Gatekeeper = "http://127.0.0.1:9000"
@ -151,8 +164,17 @@
;AllowedClients = "" ;AllowedClients = ""
;DeniedClients = "" ;DeniedClients = ""
;; Are foreign visitors allowed ;; Are foreign visitors allowed?
;ForeignAgentsAllowed = true ;ForeignAgentsAllowed = true
;;
;; If ForeignAgentsAllowed is true, make exceptions using AllowExcept.
;; Leave blank or commented for no exceptions.
; AllowExcept = "http://griefer.com:8002, http://enemy.com:8002"
;;
;; If ForeignAgentsAllowed is false, make exceptions using DisallowExcept
;; Leave blank or commented for no exceptions.
; DisallowExcept = "http://myfriendgrid.com:8002, http://myboss.com:8002"
[FreeswitchService] [FreeswitchService]
;; If FreeSWITCH is not being used then you don't need to set any of these parameters ;; If FreeSWITCH is not being used then you don't need to set any of these parameters
@ -258,5 +280,22 @@
; Region_Test_1 = "DisallowForeigners" ; Region_Test_1 = "DisallowForeigners"
[UserAgentService] [UserAgentService]
; User level required to be contacted from other grids ;; User level required to be contacted from other grids
;LevelOutsideContacts = 0 ;LevelOutsideContacts = 0
;; Restrictions on destinations of local users.
;; Are local users allowed to visit other grids?
;; What user level? Use variables of this forrm:
;; ForeignTripsAllowed_Level_<UserLevel> = true | false
;; (the default is true)
;; For example:
; ForeignTripsAllowed_Level_0 = false
; ForeignTripsAllowed_Level_200 = true ; true is default, no need to say it
;;
;; If ForeignTripsAllowed is false, make exceptions using DisallowExcept
;; Leave blank or commented for no exceptions.
; DisallowExcept_Level_0 = "http://myothergrid.com:8002, http://boss.com:8002"
;;
;; If ForeignTripsAllowed is true, make exceptions using AllowExcept.
;; Leave blank or commented for no exceptions.
; AllowExcept_Level_200 = "http://griefer.com:8002, http://enemy.com:8002"

View File

@ -130,6 +130,7 @@
LocalServiceModule = "OpenSim.Services.HypergridService.dll:GatekeeperService" LocalServiceModule = "OpenSim.Services.HypergridService.dll:GatekeeperService"
;; for the service ;; for the service
UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService" UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
GridUserService = "OpenSim.Services.UserAccountService.dll:GridUserService"
UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService"
PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService"
GridService = "OpenSim.Services.GridService.dll:GridService" GridService = "OpenSim.Services.GridService.dll:GridService"

Binary file not shown.

Binary file not shown.

BIN
bin/lib32/libopenjpeg-dotnet.so Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More