Merge branch 'master' of ssh://3dhosting.de/var/git/careminster

avinationmerge
Melanie 2013-03-31 20:27:46 +02:00
commit f142e1f394
31 changed files with 1094 additions and 401 deletions

View File

@ -141,6 +141,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
availableMethods["admin_save_heightmap"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcSaveHeightmapMethod); availableMethods["admin_save_heightmap"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcSaveHeightmapMethod);
// Agent management // Agent management
availableMethods["admin_get_agents"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcGetAgentsMethod);
availableMethods["admin_teleport_agent"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcTeleportAgentMethod); availableMethods["admin_teleport_agent"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcTeleportAgentMethod);
// User management // User management
@ -1901,6 +1902,71 @@ namespace OpenSim.ApplicationPlugins.RemoteController
m_log.Info("[RADMIN]: Access List List Request complete"); m_log.Info("[RADMIN]: Access List List Request complete");
} }
private void XmlRpcGetAgentsMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
{
Hashtable responseData = (Hashtable)response.Value;
Hashtable requestData = (Hashtable)request.Params[0];
bool includeChildren = false;
if (requestData.Contains("include_children"))
bool.TryParse((string)requestData["include_children"], out includeChildren);
Scene scene;
GetSceneFromRegionParams(requestData, responseData, out scene);
ArrayList xmlRpcRegions = new ArrayList();
responseData["regions"] = xmlRpcRegions;
Hashtable xmlRpcRegion = new Hashtable();
xmlRpcRegions.Add(xmlRpcRegion);
xmlRpcRegion["name"] = scene.Name;
xmlRpcRegion["id"] = scene.RegionInfo.RegionID.ToString();
List<ScenePresence> agents = scene.GetScenePresences();
ArrayList xmlrpcAgents = new ArrayList();
foreach (ScenePresence agent in agents)
{
if (agent.IsChildAgent && !includeChildren)
continue;
Hashtable xmlRpcAgent = new Hashtable();
xmlRpcAgent.Add("name", agent.Name);
xmlRpcAgent.Add("id", agent.UUID.ToString());
xmlRpcAgent.Add("type", agent.PresenceType.ToString());
xmlRpcAgent.Add("current_parcel_id", agent.currentParcelUUID.ToString());
Vector3 pos = agent.AbsolutePosition;
xmlRpcAgent.Add("pos_x", pos.X.ToString());
xmlRpcAgent.Add("pos_y", pos.Y.ToString());
xmlRpcAgent.Add("pos_z", pos.Z.ToString());
Vector3 lookAt = agent.Lookat;
xmlRpcAgent.Add("lookat_x", lookAt.X.ToString());
xmlRpcAgent.Add("lookat_y", lookAt.Y.ToString());
xmlRpcAgent.Add("lookat_z", lookAt.Z.ToString());
Vector3 vel = agent.Velocity;
xmlRpcAgent.Add("vel_x", vel.X.ToString());
xmlRpcAgent.Add("vel_y", vel.Y.ToString());
xmlRpcAgent.Add("vel_z", vel.Z.ToString());
xmlRpcAgent.Add("is_flying", agent.Flying.ToString());
xmlRpcAgent.Add("is_sat_on_ground", agent.SitGround.ToString());
xmlRpcAgent.Add("is_sat_on_object", agent.IsSatOnObject.ToString());
xmlrpcAgents.Add(xmlRpcAgent);
}
m_log.DebugFormat(
"[REMOTE ADMIN]: XmlRpcGetAgents found {0} agents in {1}", xmlrpcAgents.Count, scene.Name);
xmlRpcRegion["agents"] = xmlrpcAgents;
responseData["success"] = true;
}
private void XmlRpcTeleportAgentMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) private void XmlRpcTeleportAgentMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
{ {
Hashtable responseData = (Hashtable)response.Value; Hashtable responseData = (Hashtable)response.Value;

View File

@ -97,6 +97,14 @@ namespace OpenSim.Region.ClientStack.Linden
+ " >= 1 - turns on outgoing event logging\n" + " >= 1 - turns on outgoing event logging\n"
+ " >= 2 - turns on poll notification", + " >= 2 - turns on poll notification",
HandleDebugEq); HandleDebugEq);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"show eq",
"show eq",
"Show contents of event queues for logged in avatars. Used for debugging.",
HandleShowEq);
} }
public void RemoveRegion(Scene scene) public void RemoveRegion(Scene scene)
@ -138,7 +146,7 @@ namespace OpenSim.Region.ClientStack.Linden
if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel))) if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel)))
{ {
MainConsole.Instance.OutputFormat("Usage: debug eq [0|1]"); MainConsole.Instance.OutputFormat("Usage: debug eq [0|1|2]");
} }
else else
{ {
@ -148,6 +156,21 @@ namespace OpenSim.Region.ClientStack.Linden
} }
} }
protected void HandleShowEq(string module, string[] args)
{
MainConsole.Instance.OutputFormat("For scene {0}", m_scene.Name);
lock (queues)
{
foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues)
{
MainConsole.Instance.OutputFormat(
"For agent {0} there are {1} messages queued for send.",
kvp.Key, kvp.Value.Count);
}
}
}
/// <summary> /// <summary>
/// Always returns a valid queue /// Always returns a valid queue
/// </summary> /// </summary>

View File

@ -70,6 +70,7 @@ namespace OpenSim.Region.ClientStack.Linden
private string m_MapImageServerURL = string.Empty; private string m_MapImageServerURL = string.Empty;
private string m_SearchURL = string.Empty; private string m_SearchURL = string.Empty;
private bool m_ExportSupported = false;
#region ISharedRegionModule Members #region ISharedRegionModule Members
@ -87,6 +88,8 @@ namespace OpenSim.Region.ClientStack.Linden
} }
m_SearchURL = config.GetString("SearchServerURI", string.Empty); m_SearchURL = config.GetString("SearchServerURI", string.Empty);
m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported);
} }
AddDefaultFeatures(); AddDefaultFeatures();
@ -152,6 +155,9 @@ namespace OpenSim.Region.ClientStack.Linden
if (m_SearchURL != string.Empty) if (m_SearchURL != string.Empty)
gridServicesMap["search"] = m_SearchURL; gridServicesMap["search"] = m_SearchURL;
m_features["GridServices"] = gridServicesMap; m_features["GridServices"] = gridServicesMap;
if (m_ExportSupported)
m_features["ExportSupported"] = true;
} }
} }

View File

@ -50,6 +50,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
#region INonSharedRegionModule #region INonSharedRegionModule
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public int DebugLevel { get; set; }
private Scene m_scene; private Scene m_scene;
private IInventoryAccessModule m_invAccessModule; private IInventoryAccessModule m_invAccessModule;
@ -76,11 +78,67 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
m_scene.RegisterModuleInterface<IAttachmentsModule>(this); m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
if (Enabled) if (Enabled)
{
m_scene.EventManager.OnNewClient += SubscribeToClientEvents; m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true);
m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false);
MainConsole.Instance.Commands.AddCommand(
"Debug",
false,
"debug attachments",
"debug attachments [0|1]",
"Turn on attachments debugging\n"
+ " <= 0 - turns off debugging\n"
+ " >= 1 - turns on attachment message logging\n",
HandleDebugAttachments);
}
// TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
} }
private void HandleDebugAttachments(string module, string[] args)
{
int debugLevel;
if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel)))
{
MainConsole.Instance.OutputFormat("Usage: debug attachments [0|1]");
}
else
{
DebugLevel = debugLevel;
MainConsole.Instance.OutputFormat(
"Set event queue debug level to {0} in {1}", DebugLevel, m_scene.Name);
}
}
/// <summary>
/// Listen for client triggered running state changes so that we can persist the script's object if necessary.
/// </summary>
/// <param name='localID'></param>
/// <param name='itemID'></param>
private void HandleScriptStateChange(uint localID, bool started)
{
SceneObjectGroup sog = m_scene.GetGroupByPrim(localID);
if (sog != null && sog.IsAttachment)
{
if (!started)
{
// FIXME: This is a convoluted way for working out whether the script state has changed to stop
// because it has been manually stopped or because the stop was called in UpdateDetachedObject() below
// This needs to be handled in a less tangled way.
ScenePresence sp = m_scene.GetScenePresence(sog.AttachedAvatar);
if (sp.ControllingClient.IsActive)
sog.HasGroupChanged = true;
}
else
{
sog.HasGroupChanged = true;
}
}
}
public void RemoveRegion(Scene scene) public void RemoveRegion(Scene scene)
{ {
m_scene.UnregisterModuleInterface<IAttachmentsModule>(this); m_scene.UnregisterModuleInterface<IAttachmentsModule>(this);
@ -153,10 +211,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
} }
} }
/// <summary>
/// RezAttachments. This should only be called upon login on the first region.
/// Attachment rezzings on crossings and TPs are done in a different way.
/// </summary>
public void RezAttachments(IScenePresence sp) public void RezAttachments(IScenePresence sp)
{ {
if (!Enabled) if (!Enabled)
@ -165,10 +219,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (null == sp.Appearance) if (null == sp.Appearance)
{ {
m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID); m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID);
return; return;
} }
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0}", sp.Name); if (sp.GetAttachments().Count > 0)
{
if (DebugLevel > 0)
m_log.DebugFormat(
"[ATTACHMENTS MODULE]: Not doing simulator-side attachment rez for {0} in {1} as their viewer has already rezzed attachments",
m_scene.Name, sp.Name);
return;
}
if (DebugLevel > 0)
m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0} from simulator-side", sp.Name);
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
string stateData = String.Empty; string stateData = String.Empty;
@ -235,10 +301,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
// If we're an NPC then skip all the item checks and manipulations since we don't have an // If we're an NPC then skip all the item checks and manipulations since we don't have an
// inventory right now. // inventory right now.
if (sp.PresenceType == PresenceType.Npc) RezSingleAttachmentFromInventoryInternal(
RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null, true); sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, p, true, null);
else
RezSingleAttachmentFromInventory(sp, attach.ItemID, p | (uint)0x80, d);
} }
catch (Exception e) catch (Exception e)
{ {
@ -254,7 +318,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled) if (!Enabled)
return; return;
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); if (DebugLevel > 0)
m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
List<SceneObjectGroup> attachments = sp.GetAttachments(); List<SceneObjectGroup> attachments = sp.GetAttachments();
@ -287,9 +352,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled) if (!Enabled)
return; return;
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", m_log.DebugFormat(
// m_scene.RegionInfo.RegionName, sp.Name, silent); "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
m_scene.RegionInfo.RegionName, sp.Name, silent);
foreach (SceneObjectGroup sop in sp.GetAttachments()) foreach (SceneObjectGroup sop in sp.GetAttachments())
{ {
@ -299,12 +365,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
sp.ClearAttachments(); sp.ClearAttachments();
} }
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp, bool append) public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool addToInventory, bool append)
{ {
if (!Enabled) if (!Enabled)
return false; return false;
return AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp, false, append); return AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, addToInventory, false, append);
} }
/// <summary> /// <summary>
@ -315,9 +381,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
/// <param name='group'>The object to attach.</param> /// <param name='group'>The object to attach.</param>
/// <param name='attachmentPt'></param> /// <param name='attachmentPt'></param>
/// <param name='silent'></param> /// <param name='silent'></param>
/// <param name='temp'></param> /// <param name='addToInventory'>If true then add object to user inventory.</param>
/// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param> /// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param>
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp, bool resumeScripts, bool append) private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool addToInventory, bool resumeScripts, bool append)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
@ -334,9 +400,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (group.GetSittingAvatarsCount() != 0) if (group.GetSittingAvatarsCount() != 0)
{ {
// m_log.WarnFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", m_log.WarnFormat(
// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
return false; return false;
} }
@ -372,6 +439,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt); List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
if (attachments.Contains(group))
{
if (DebugLevel > 0)
m_log.WarnFormat(
"[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
group.Name, group.LocalId, sp.Name, attachmentPt);
return false;
}
// If we already have 5, remove the oldest until only 4 are left. Skip over temp ones // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones
while (attachments.Count >= 5) while (attachments.Count >= 5)
{ {
@ -395,8 +472,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
group.AttachmentPoint = attachmentPt; group.AttachmentPoint = attachmentPt;
group.AbsolutePosition = attachPos; group.AbsolutePosition = attachPos;
if (sp.PresenceType != PresenceType.Npc) if (addToInventory && sp.PresenceType != PresenceType.Npc)
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append); UpdateUserInventoryWithAttachment(sp, group, attachmentPt, append);
AttachToAgent(sp, group, attachmentPt, attachPos, silent); AttachToAgent(sp, group, attachmentPt, attachPos, silent);
@ -415,17 +492,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return true; return true;
} }
private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp, bool append) private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool append)
{ {
// Add the new attachment to inventory if we don't already have it. // Add the new attachment to inventory if we don't already have it.
if (!temp) UUID newAttachmentItemID = group.FromItemID;
{ if (newAttachmentItemID == UUID.Zero)
UUID newAttachmentItemID = group.FromItemID; newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
if (newAttachmentItemID == UUID.Zero)
newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group, append); ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group, append);
}
} }
public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
@ -438,40 +512,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled) if (!Enabled)
return null; return null;
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}", m_log.DebugFormat(
// (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name); "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
(AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
bool append = (AttachmentPt & 0x80) != 0; // We check the attachments in the avatar appearance here rather than the objects attached to the
AttachmentPt &= 0x7f; // ScenePresence itself so that we can ignore calls by viewer 2/3 to attach objects on startup. We are
// already doing this in ScenePresence.MakeRootAgent(). Simulator-side attaching needs to be done
// Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such). // because pre-outfit folder viewers (most version 1 viewers) require it.
// This often happens during login - not sure the exact reason.
// For now, we will ignore the request. Unfortunately, this means that we need to dig through all the
// ScenePresence attachments. We can't use the data in AvatarAppearance because that's present at login
// before anything has actually been attached.
bool alreadyOn = false; bool alreadyOn = false;
List<SceneObjectGroup> existingAttachments = sp.GetAttachments(); List<AvatarAttachment> existingAttachments = sp.Appearance.GetAttachments();
foreach (SceneObjectGroup so in existingAttachments) foreach (AvatarAttachment existingAttachment in existingAttachments)
{ {
if (so.FromItemID == itemID) if (existingAttachment.ItemID == itemID)
{ {
alreadyOn = true; alreadyOn = true;
break; break;
} }
} }
// if (sp.Appearance.GetAttachmentForItem(itemID) != null)
if (alreadyOn) if (alreadyOn)
{ {
// m_log.WarnFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn", m_log.DebugFormat(
// sp.Name, itemID, AttachmentPt); "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn",
sp.Name, itemID, AttachmentPt);
return null; return null;
} }
return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc, append); bool append = (AttachmentPt & 0x80) != 0;
AttachmentPt &= 0x7f;
return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, append, doc);
} }
public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist)
@ -479,7 +553,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled) if (!Enabled)
return; return;
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); if (DebugLevel > 0)
m_log.DebugFormat(
"[ATTACHMENTS MODULE]: Rezzing {0} attachments from inventory for {1} in {2}",
rezlist.Count, sp.Name, m_scene.Name);
foreach (KeyValuePair<UUID, uint> rez in rezlist) foreach (KeyValuePair<UUID, uint> rez in rezlist)
{ {
@ -497,9 +574,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled) if (!Enabled)
return; return;
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", m_log.DebugFormat(
// sp.UUID, soLocalId); "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}",
sp.UUID, soLocalId);
SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId);
@ -515,9 +593,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (inventoryID == UUID.Zero) if (inventoryID == UUID.Zero)
return; return;
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", m_log.DebugFormat(
// so.Name, so.LocalId, inventoryID); "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
so.Name, so.LocalId, inventoryID);
lock (sp.AttachmentsSyncLock) lock (sp.AttachmentsSyncLock)
{ {
@ -572,9 +651,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return; return;
} }
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}", m_log.DebugFormat(
// so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name); "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}",
so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name);
// Scripts MUST be snapshotted before the object is // Scripts MUST be snapshotted before the object is
// removed from the scene because doing otherwise will // removed from the scene because doing otherwise will
@ -700,12 +780,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
grp.HasGroupChanged = false; // Prevent it being saved over and over grp.HasGroupChanged = false; // Prevent it being saved over and over
} }
// else else if (DebugLevel > 0)
// { {
// m_log.DebugFormat( m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
// grp.UUID, grp.AttachmentPoint); grp.UUID, grp.AttachmentPoint);
// } }
} }
/// <summary> /// <summary>
@ -723,9 +803,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
private void AttachToAgent( private void AttachToAgent(
IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
{ {
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", m_log.DebugFormat(
// so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}",
so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos);
so.DetachFromBackup(); so.DetachFromBackup();
@ -750,9 +831,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
{ {
if (so.HasPrivateAttachmentPoint) if (so.HasPrivateAttachmentPoint)
{ {
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", m_log.DebugFormat(
// so.Name, sp.Name, so.AttachmentPoint); "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
so.Name, sp.Name, so.AttachmentPoint);
// As this scene object can now only be seen by the attaching avatar, tell everybody else in the // As this scene object can now only be seen by the attaching avatar, tell everybody else in the
// scene that it's no longer in their awareness. // scene that it's no longer in their awareness.
@ -786,9 +868,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (m_invAccessModule == null) if (m_invAccessModule == null)
return null; return null;
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", m_log.DebugFormat(
// grp.Name, grp.LocalId, remoteClient.Name); "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
grp.Name, grp.LocalId, sp.Name);
InventoryItemBase newItem InventoryItemBase newItem
= m_invAccessModule.CopyToInventory( = m_invAccessModule.CopyToInventory(
@ -872,7 +955,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
} }
protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc, bool append) IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append, XmlDocument doc)
{ {
if (m_invAccessModule == null) if (m_invAccessModule == null)
return null; return null;
@ -897,6 +980,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return null; return null;
} }
if (DebugLevel > 0)
m_log.DebugFormat(
"[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
objatt.Name, sp.Name, attachmentPt, m_scene.Name);
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
objatt.HasGroupChanged = false; objatt.HasGroupChanged = false;
bool tainted = false; bool tainted = false;
@ -917,7 +1005,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
objatt.ResetOwnerChangeFlag(); objatt.ResetOwnerChangeFlag();
} }
AttachObjectInternal(sp, objatt, attachmentPt, false, true, false, true, append); AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, true, append);
} }
catch (Exception e) catch (Exception e)
{ {
@ -971,9 +1059,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
bool changed = sp.Appearance.SetAttachment((int)AttachmentPt | attFlag, itemID, item.AssetID); bool changed = sp.Appearance.SetAttachment((int)AttachmentPt | attFlag, itemID, item.AssetID);
if (changed && m_scene.AvatarFactory != null) if (changed && m_scene.AvatarFactory != null)
{ {
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()", m_log.DebugFormat(
// sp.Name, att.Name, AttachmentPt); "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()",
sp.Name, att.Name, AttachmentPt);
m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
} }
@ -988,9 +1077,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled) if (!Enabled)
return null; return null;
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", m_log.DebugFormat(
// (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}",
(AttachmentPoint)AttachmentPt, itemID, remoteClient.Name);
ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
@ -1021,9 +1111,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent)
{ {
// m_log.DebugFormat( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", m_log.DebugFormat(
// objectLocalID, remoteClient.Name, AttachmentPt, silent); "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})",
objectLocalID, remoteClient.Name, AttachmentPt, silent);
if (!Enabled) if (!Enabled)
return; return;
@ -1056,11 +1147,12 @@ 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, true, false, append)) if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, false, false, append))
{ {
// m_log.Debug( if (DebugLevel > 0)
// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId m_log.Debug(
// + ", AttachmentPoint: " + AttachmentPt); "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
+ ", AttachmentPoint: " + AttachmentPt);
// Save avatar attachment information // Save avatar attachment information
m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId); m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId);

View File

@ -130,7 +130,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
config.AddConfig("Modules"); config.AddConfig("Modules");
config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
modules.Add(new AttachmentsModule()); AttachmentsModule attMod = new AttachmentsModule();
attMod.DebugLevel = 1;
modules.Add(attMod);
modules.Add(new BasicInventoryAccessModule()); modules.Add(new BasicInventoryAccessModule());
} }
@ -197,7 +199,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; m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false, false); scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false, false);
// Check status on scene presence // Check status on scene presence
Assert.That(sp.HasAttachments(), Is.True); Assert.That(sp.HasAttachments(), Is.True);
@ -244,7 +246,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID); SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID);
m_numberOfAttachEventsFired = 0; m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, false, false, false); scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, true, false, false);
// Check status on scene presence // Check status on scene presence
Assert.That(sp.HasAttachments(), Is.True); Assert.That(sp.HasAttachments(), Is.True);
@ -277,7 +279,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
// Test wearing a different attachment from the ground. // Test wearing a different attachment from the ground.
{ {
scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false, false, false); scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false, false);
// Check status on scene presence // Check status on scene presence
Assert.That(sp.HasAttachments(), Is.True); Assert.That(sp.HasAttachments(), Is.True);
@ -310,7 +312,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
// Test rewearing an already worn attachment from ground. Nothing should happen. // Test rewearing an already worn attachment from ground. Nothing should happen.
{ {
scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false, false, false); scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, true, false, false);
// Check status on scene presence // Check status on scene presence
Assert.That(sp.HasAttachments(), Is.True); Assert.That(sp.HasAttachments(), Is.True);
@ -368,7 +370,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
sp2.AbsolutePosition = new Vector3(0, 0, 0); sp2.AbsolutePosition = new Vector3(0, 0, 0);
sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero);
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false, false, false); scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, true, false, false);
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));
@ -728,7 +730,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
public void TestRezAttachmentsOnAvatarEntrance() public void TestRezAttachmentsOnAvatarEntrance()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // TestHelpers.EnableLogging();
Scene scene = CreateTestScene(); Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);

View File

@ -154,7 +154,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
void OnIncomingInstantMessage(GridInstantMessage im) void OnIncomingInstantMessage(GridInstantMessage im)
{ {
if (im.dialog == (byte)InstantMessageDialog.RequestTeleport) if (im.dialog == (byte)InstantMessageDialog.RequestTeleport
|| im.dialog == (byte)InstantMessageDialog.GodLikeRequestTeleport)
{ {
UUID sessionID = new UUID(im.imSessionID); UUID sessionID = new UUID(im.imSessionID);

View File

@ -165,7 +165,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
(uint)presence.AbsolutePosition.Y, (uint)presence.AbsolutePosition.Y,
(uint)presence.AbsolutePosition.Z + 2); (uint)presence.AbsolutePosition.Z + 2);
m_log.DebugFormat("[LURE]: TP invite with message {0}", message); m_log.DebugFormat("TP invite with message {0}, type {1}", message, lureType);
GridInstantMessage m; GridInstantMessage m;

View File

@ -33,6 +33,7 @@ using System.Threading;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Capabilities; using OpenSim.Framework.Capabilities;
using OpenSim.Framework.Client; using OpenSim.Framework.Client;
using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
@ -77,6 +78,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// </remarks> /// </remarks>
public bool DisableInterRegionTeleportCancellation { get; set; } public bool DisableInterRegionTeleportCancellation { get; set; }
/// <summary>
/// Number of times inter-region teleport was attempted.
/// </summary>
private Stat m_interRegionTeleportAttempts;
/// <summary>
/// Number of times inter-region teleport was aborted (due to simultaneous client logout).
/// </summary>
private Stat m_interRegionTeleportAborts;
/// <summary>
/// Number of times inter-region teleport was successfully cancelled by the client.
/// </summary>
private Stat m_interRegionTeleportCancels;
/// <summary>
/// Number of times inter-region teleport failed due to server/client/network problems (e.g. viewer failed to
/// connect with destination region).
/// </summary>
/// <remarks>
/// This is not necessarily a problem for this simulator - in open-grid/hg conditions, viewer connectivity to
/// destination simulator is unknown.
/// </remarks>
private Stat m_interRegionTeleportFailures;
protected bool m_Enabled = false; protected bool m_Enabled = false;
public Scene Scene { get; private set; } public Scene Scene { get; private set; }
@ -91,6 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
private IEventQueue m_eqModule; private IEventQueue m_eqModule;
private IRegionCombinerModule m_regionCombinerModule;
#region ISharedRegionModule #region ISharedRegionModule
@ -156,6 +183,60 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
Scene = scene; Scene = scene;
m_interRegionTeleportAttempts =
new Stat(
"InterRegionTeleportAttempts",
"Number of inter-region teleports attempted.",
"This does not count attempts which failed due to pre-conditions (e.g. target simulator refused access).\n"
+ "You can get successfully teleports by subtracting aborts, cancels and teleport failures from this figure.",
"",
"entitytransfer",
Scene.Name,
StatType.Push,
null,
StatVerbosity.Debug);
m_interRegionTeleportAborts =
new Stat(
"InterRegionTeleportAborts",
"Number of inter-region teleports aborted due to client actions.",
"The chief action is simultaneous logout whilst teleporting.",
"",
"entitytransfer",
Scene.Name,
StatType.Push,
null,
StatVerbosity.Debug);
m_interRegionTeleportCancels =
new Stat(
"InterRegionTeleportCancels",
"Number of inter-region teleports cancelled by the client.",
null,
"",
"entitytransfer",
Scene.Name,
StatType.Push,
null,
StatVerbosity.Debug);
m_interRegionTeleportFailures =
new Stat(
"InterRegionTeleportFailures",
"Number of inter-region teleports that failed due to server/client/network issues.",
"This number may not be very helpful in open-grid/hg situations as the network connectivity/quality of destinations is uncontrollable.",
"",
"entitytransfer",
Scene.Name,
StatType.Push,
null,
StatVerbosity.Debug);
StatsManager.RegisterStat(m_interRegionTeleportAttempts);
StatsManager.RegisterStat(m_interRegionTeleportAborts);
StatsManager.RegisterStat(m_interRegionTeleportCancels);
StatsManager.RegisterStat(m_interRegionTeleportFailures);
scene.RegisterModuleInterface<IEntityTransferModule>(this); scene.RegisterModuleInterface<IEntityTransferModule>(this);
scene.EventManager.OnNewClient += OnNewClient; scene.EventManager.OnNewClient += OnNewClient;
} }
@ -173,7 +254,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
public virtual void Close() {} public virtual void Close() {}
public virtual void RemoveRegion(Scene scene) {} public virtual void RemoveRegion(Scene scene)
{
if (m_Enabled)
{
StatsManager.DeregisterStat(m_interRegionTeleportAttempts);
StatsManager.DeregisterStat(m_interRegionTeleportAborts);
StatsManager.DeregisterStat(m_interRegionTeleportCancels);
StatsManager.DeregisterStat(m_interRegionTeleportFailures);
}
}
public virtual void RegionLoaded(Scene scene) public virtual void RegionLoaded(Scene scene)
{ {
@ -181,6 +271,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return; return;
m_eqModule = Scene.RequestModuleInterface<IEventQueue>(); m_eqModule = Scene.RequestModuleInterface<IEventQueue>();
m_regionCombinerModule = Scene.RequestModuleInterface<IRegionCombinerModule>();
} }
#endregion #endregion
@ -291,8 +382,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
Vector3 emergencyPos = new Vector3(128, 128, 128); Vector3 emergencyPos = new Vector3(128, 128, 128);
m_log.WarnFormat( m_log.WarnFormat(
"[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2} in {3}. Substituting {4}",
position, sp.Name, sp.UUID, emergencyPos); position, sp.Name, sp.UUID, Scene.Name, emergencyPos);
position = emergencyPos; position = emergencyPos;
} }
@ -548,6 +639,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return; return;
} }
// Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
// simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
// as server attempts.
m_interRegionTeleportAttempts.Value++;
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version);
// Fixing a bug where teleporting while sitting results in the avatar ending up removed from // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
@ -600,6 +696,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
bool logout = false; bool logout = false;
if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
{ {
m_interRegionTeleportFailures.Value++;
sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason));
m_log.DebugFormat( m_log.DebugFormat(
@ -611,6 +709,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
{ {
m_interRegionTeleportCancels.Value++;
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
sp.Name, finalDestination.RegionName, sp.Scene.Name); sp.Name, finalDestination.RegionName, sp.Scene.Name);
@ -619,6 +719,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
} }
else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
{ {
m_interRegionTeleportAborts.Value++;
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
sp.Name, finalDestination.RegionName, sp.Scene.Name); sp.Name, finalDestination.RegionName, sp.Scene.Name);
@ -635,6 +737,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
IClientIPEndpoint ipepClient; IClientIPEndpoint ipepClient;
if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY))
{ {
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}",
finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name);
//sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent...");
#region IP Translation for NAT #region IP Translation for NAT
// Uses ipepClient above // Uses ipepClient above
@ -688,6 +794,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// establish th econnection to the destination which makes it return true. // establish th econnection to the destination which makes it return true.
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
{ {
m_interRegionTeleportAborts.Value++;
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
sp.Name, finalDestination.RegionName, sp.Scene.Name); sp.Name, finalDestination.RegionName, sp.Scene.Name);
@ -703,6 +811,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
{ {
m_interRegionTeleportAborts.Value++;
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
sp.Name, finalDestination.RegionName, sp.Scene.Name); sp.Name, finalDestination.RegionName, sp.Scene.Name);
@ -720,6 +830,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
{ {
m_interRegionTeleportCancels.Value++;
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
sp.Name, finalDestination.RegionName, sp.Scene.Name); sp.Name, finalDestination.RegionName, sp.Scene.Name);
@ -755,6 +867,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
{ {
m_interRegionTeleportAborts.Value++;
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
sp.Name, finalDestination.RegionName, sp.Scene.Name); sp.Name, finalDestination.RegionName, sp.Scene.Name);
@ -767,6 +881,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion."); Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion.");
return; return;
} }
@ -808,15 +923,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// now we have a child agent in this region. // now we have a child agent in this region.
sp.Reset(); sp.Reset();
} }
// Commented pending deletion since this method no longer appears to do anything at all
// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE!
// if (sp.Scene.NeedSceneCacheClear(sp.UUID))
// {
// m_log.DebugFormat(
// "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed",
// sp.UUID);
// }
} }
/// <summary> /// <summary>
@ -852,6 +958,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
CleanupFailedInterRegionTeleport(sp, finalDestination); CleanupFailedInterRegionTeleport(sp, finalDestination);
m_interRegionTeleportFailures.Value++;
sp.ControllingClient.SendTeleportFailed( sp.ControllingClient.SendTeleportFailed(
string.Format( string.Format(
"Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason)); "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
@ -907,7 +1015,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
{ {
return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
{
Vector2 swCorner, neCorner;
GetMegaregionViewRange(out swCorner, out neCorner);
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}",
Scene.Name, swCorner, neCorner, newRegionX, newRegionY);
return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y);
}
else
{
return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
}
} }
protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg)
@ -1011,6 +1133,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
version = String.Empty; version = String.Empty;
newpos = new Vector3(pos.X, pos.Y, pos.Z); newpos = new Vector3(pos.X, pos.Y, pos.Z);
// m_log.DebugFormat(
// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
uint neighbourx = scene.RegionInfo.RegionLocX; uint neighbourx = scene.RegionInfo.RegionLocX;
uint neighboury = scene.RegionInfo.RegionLocY; uint neighboury = scene.RegionInfo.RegionLocY;
const float boundaryDistance = 1.7f; const float boundaryDistance = 1.7f;
@ -1183,6 +1309,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
Thread.Sleep(10000); Thread.Sleep(10000);
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}",
agent.Name, regionX, regionY, position, initiatingScene.Name);
agent.Scene.RequestTeleportLocation(
agent.ControllingClient,
Utils.UIntsToLong(regionX * (uint)Constants.RegionSize, regionY * (uint)Constants.RegionSize),
position,
agent.Lookat,
(uint)Constants.TeleportFlags.ViaLocation);
/*
IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>(); IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
if (im != null) if (im != null)
{ {
@ -1217,6 +1355,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
}); });
} }
*/
} }
private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar)
@ -1724,6 +1863,37 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
reg.RegionName, sp.Name, sp.UUID, reason); reg.RegionName, sp.Name, sp.UUID, reason);
} }
/// <summary>
/// Gets the range considered in view of this megaregion (assuming this is a megaregion).
/// </summary>
/// <remarks>Expressed in 256m units</remarks>
/// <param name='swCorner'></param>
/// <param name='neCorner'></param>
private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
{
Border[] northBorders = Scene.NorthBorders.ToArray();
Border[] eastBorders = Scene.EastBorders.ToArray();
Vector2 extent = Vector2.Zero;
for (int i = 0; i < eastBorders.Length; i++)
{
extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
}
for (int i = 0; i < northBorders.Length; i++)
{
extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
}
// Loss of fraction on purpose
extent.X = ((int)extent.X / (int)Constants.RegionSize);
extent.Y = ((int)extent.Y / (int)Constants.RegionSize);
swCorner.X = Scene.RegionInfo.RegionLocX - 1;
swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
neCorner.X = Scene.RegionInfo.RegionLocX + extent.X;
neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y;
}
/// <summary> /// <summary>
/// Return the list of regions that are considered to be neighbours to the given scene. /// Return the list of regions that are considered to be neighbours to the given scene.
/// </summary> /// </summary>
@ -1736,15 +1906,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
Scene pScene = avatar.Scene; Scene pScene = avatar.Scene;
RegionInfo m_regionInfo = pScene.RegionInfo; RegionInfo m_regionInfo = pScene.RegionInfo;
Border[] northBorders = pScene.NorthBorders.ToArray();
Border[] southBorders = pScene.SouthBorders.ToArray();
Border[] eastBorders = pScene.EastBorders.ToArray();
Border[] westBorders = pScene.WestBorders.ToArray();
// Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't
// clear what should be done with a "far view" given that megaregions already extended the // clear what should be done with a "far view" given that megaregions already extended the
// view to include everything in the megaregion // view to include everything in the megaregion
if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
{ {
int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance;
@ -1762,27 +1927,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
} }
else else
{ {
Vector2 extent = Vector2.Zero; Vector2 swCorner, neCorner;
for (int i = 0; i < eastBorders.Length; i++) GetMegaregionViewRange(out swCorner, out neCorner);
{
extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
}
for (int i = 0; i < northBorders.Length; i++)
{
extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
}
// Loss of fraction on purpose List<GridRegion> neighbours
extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1; = pScene.GridService.GetRegionRange(
extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1; m_regionInfo.ScopeID,
(int)swCorner.X * (int)Constants.RegionSize,
(int)neCorner.X * (int)Constants.RegionSize,
(int)swCorner.Y * (int)Constants.RegionSize,
(int)neCorner.Y * (int)Constants.RegionSize);
int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize;
int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize;
int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize;
int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize;
List<GridRegion> neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY);
neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; });
return neighbours; return neighbours;

View File

@ -199,7 +199,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
public override void RemoveRegion(Scene scene) public override void RemoveRegion(Scene scene)
{ {
base.AddRegion(scene); base.RemoveRegion(scene);
if (m_Enabled) if (m_Enabled)
scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this); scene.UnregisterModuleInterface<IUserAgentVerificationModule>(this);

View File

@ -189,6 +189,45 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
case (int)HttpRequestConstants.HTTP_VERIFY_CERT: case (int)HttpRequestConstants.HTTP_VERIFY_CERT:
htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0); htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0);
break; break;
case (int)HttpRequestConstants.HTTP_VERBOSE_THROTTLE:
// TODO implement me
break;
case (int)HttpRequestConstants.HTTP_CUSTOM_HEADER:
//Parameters are in pairs and custom header takes
//arguments in pairs so adjust for header marker.
++i;
//Maximum of 8 headers are allowed based on the
//Second Life documentation for llHTTPRequest.
for (int count = 1; count <= 8; ++count)
{
//Not enough parameters remaining for a header?
if (parms.Length - i < 2)
break;
//Have we reached the end of the list of headers?
//End is marked by a string with a single digit.
//We already know we have at least one parameter
//so it is safe to do this check at top of loop.
if (Char.IsDigit(parms[i][0]))
break;
if (htc.HttpCustomHeaders == null)
htc.HttpCustomHeaders = new List<string>();
htc.HttpCustomHeaders.Add(parms[i]);
htc.HttpCustomHeaders.Add(parms[i+1]);
i += 2;
}
break;
case (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE:
htc.HttpPragmaNoCache = (int.Parse(parms[i + 1]) != 0);
break;
} }
} }
} }
@ -353,6 +392,9 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
// public const int HTTP_METHOD = 0; // public const int HTTP_METHOD = 0;
// public const int HTTP_MIMETYPE = 1; // public const int HTTP_MIMETYPE = 1;
// public const int HTTP_VERIFY_CERT = 3; // public const int HTTP_VERIFY_CERT = 3;
// public const int HTTP_VERBOSE_THROTTLE = 4;
// public const int HTTP_CUSTOM_HEADER = 5;
// public const int HTTP_PRAGMA_NO_CACHE = 6;
private bool _finished; private bool _finished;
public bool Finished public bool Finished
{ {
@ -367,6 +409,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
public bool HttpVerifyCert = true; public bool HttpVerifyCert = true;
public IWorkItemResult WorkItem = null; public IWorkItemResult WorkItem = null;
//public bool HttpVerboseThrottle = true; // not implemented
public List<string> HttpCustomHeaders = null;
public bool HttpPragmaNoCache = true;
private Thread httpThread;
// Request info // Request info
private UUID _itemID; private UUID _itemID;
public UUID ItemID public UUID ItemID
@ -434,12 +481,26 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
Request.Method = HttpMethod; Request.Method = HttpMethod;
Request.ContentType = HttpMIMEType; Request.ContentType = HttpMIMEType;
if(!HttpVerifyCert) if (!HttpVerifyCert)
{ {
// We could hijack Connection Group Name to identify // We could hijack Connection Group Name to identify
// a desired security exception. But at the moment we'll use a dummy header instead. // a desired security exception. But at the moment we'll use a dummy header instead.
Request.Headers.Add("NoVerifyCert", "true"); Request.Headers.Add("NoVerifyCert", "true");
} }
// else
// {
// Request.ConnectionGroupName="Verify";
// }
if (!HttpPragmaNoCache)
{
Request.Headers.Add("Pragma", "no-cache");
}
if (HttpCustomHeaders != null)
{
for (int i = 0; i < HttpCustomHeaders.Count; i += 2)
Request.Headers.Add(HttpCustomHeaders[i],
HttpCustomHeaders[i+1]);
}
if (proxyurl != null && proxyurl.Length > 0) if (proxyurl != null && proxyurl.Length > 0)
{ {
if (proxyexcepts != null && proxyexcepts.Length > 0) if (proxyexcepts != null && proxyexcepts.Length > 0)

View File

@ -597,6 +597,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
cdl.AddRow("LightFalloff", s.LightFalloff); cdl.AddRow("LightFalloff", s.LightFalloff);
cdl.AddRow("LightIntensity", s.LightIntensity); cdl.AddRow("LightIntensity", s.LightIntensity);
cdl.AddRow("LightRadius", s.LightRadius); cdl.AddRow("LightRadius", s.LightRadius);
cdl.AddRow("Location (relative)", sop.RelativePosition);
cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
cdl.AddRow("PathBegin", s.PathBegin); cdl.AddRow("PathBegin", s.PathBegin);
cdl.AddRow("PathEnd", s.PathEnd); cdl.AddRow("PathEnd", s.PathEnd);
@ -619,6 +620,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
cdl.AddRow("ProjectionFocus", s.ProjectionFocus); cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
cdl.AddRow("ProjectionFOV", s.ProjectionFOV); cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
cdl.AddRow("Rotation (Relative)", sop.RotationOffset);
cdl.AddRow("Rotation (World)", sop.GetWorldRotation());
cdl.AddRow("Scale", s.Scale); cdl.AddRow("Scale", s.Scale);
cdl.AddRow( cdl.AddRow(
"SculptData", "SculptData",

View File

@ -54,6 +54,10 @@ namespace OpenSim.Region.Framework.Interfaces
/// RezAttachments. This should only be called upon login on the first region. /// RezAttachments. This should only be called upon login on the first region.
/// Attachment rezzings on crossings and TPs are done in a different way. /// Attachment rezzings on crossings and TPs are done in a different way.
/// </summary> /// </summary>
/// <remarks>
/// This is only actually necessary for viewers which do not have a current outfit folder (these viewers make
/// their own attachment calls on login) and agents which have attachments but no viewer (e.g. NPCs).
/// </remarks>
/// <param name="sp"></param> /// <param name="sp"></param>
void RezAttachments(IScenePresence sp); void RezAttachments(IScenePresence sp);
@ -77,14 +81,16 @@ namespace OpenSim.Region.Framework.Interfaces
void DeleteAttachmentsFromScene(IScenePresence sp, bool silent); void DeleteAttachmentsFromScene(IScenePresence sp, bool silent);
/// <summary> /// <summary>
/// Attach an object to an avatar /// Attach an object to an avatar.
/// </summary> /// </summary>
/// <param name="sp"></param> /// <param name="sp"></param>
/// <param name="grp"></param> /// <param name="grp"></param>
/// <param name="AttachmentPt"></param> /// <param name="AttachmentPt"></param>
/// <param name="silent"></param> /// <param name="silent"></param>
/// <param name="addToInventory">If true then add object to user inventory</param>
/// <param name="append">Append to attachment point rather than replace.</param>
/// <returns>true if the object was successfully attached, false otherwise</returns> /// <returns>true if the object was successfully attached, false otherwise</returns>
bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool temp, bool append); bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool useAttachmentInfo, bool addToInventory, bool append);
/// <summary> /// <summary>
/// Rez an attachment from user inventory and change inventory status to match. /// Rez an attachment from user inventory and change inventory status to match.

View File

@ -36,6 +36,9 @@ namespace OpenSim.Region.Framework.Interfaces
HTTP_MIMETYPE = 1, HTTP_MIMETYPE = 1,
HTTP_BODY_MAXLENGTH = 2, HTTP_BODY_MAXLENGTH = 2,
HTTP_VERIFY_CERT = 3, HTTP_VERIFY_CERT = 3,
HTTP_VERBOSE_THROTTLE = 4,
HTTP_CUSTOM_HEADER = 5,
HTTP_PRAGMA_NO_CACHE = 6
} }
public interface IHttpRequestModule public interface IHttpRequestModule

View File

@ -34,7 +34,6 @@ namespace OpenSim.Region.Framework.Scenes
{ {
public class Border public class Border
{ {
/// <summary> /// <summary>
/// Line perpendicular to the Direction Cardinal. Z value is the /// Line perpendicular to the Direction Cardinal. Z value is the
/// </summary> /// </summary>
@ -81,6 +80,10 @@ namespace OpenSim.Region.Framework.Scenes
TriggerRegionY = triggerRegionY; TriggerRegionY = triggerRegionY;
} }
/// <summary>
/// Tests to see if the given position would cross this border.
/// </summary>
/// <returns></returns>
public bool TestCross(Vector3 position) public bool TestCross(Vector3 position)
{ {
bool result = false; bool result = false;

View File

@ -2645,7 +2645,6 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
return null; return null;
} }
@ -2863,6 +2862,9 @@ namespace OpenSim.Region.Framework.Scenes
RootPrim.RemFlag(PrimFlags.TemporaryOnRez); RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
// We must currently not resume scripts at this stage since AttachmentsModule does not have the
// information that this is due to a teleport/border cross rather than an ordinary attachment.
// We currently do this in Scene.MakeRootAgent() instead.
if (AttachmentsModule != null) if (AttachmentsModule != null)
AttachmentsModule.AttachObject(sp, grp, 0, false, false, false, true); AttachmentsModule.AttachObject(sp, grp, 0, false, false, false, true);
} }
@ -2979,35 +2981,6 @@ namespace OpenSim.Region.Framework.Scenes
m_eventManager.TriggerOnNewPresence(sp); m_eventManager.TriggerOnNewPresence(sp);
sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
// The first agent upon login is a root agent by design.
// For this agent we will have to rez the attachments.
// All other AddNewClient calls find aCircuit.child to be true.
if (aCircuit.child == false)
{
// We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
// start the scripts again (since this is done in RezAttachments()).
// XXX: This is convoluted.
sp.IsChildAgent = false;
sp.IsLoggingIn = true;
// We leave a 5 second pause before attempting to rez attachments to avoid a clash with
// version 3 viewers that maybe doing their own attachment rezzing related to their current
// outfit folder on startup. If these operations do clash, then the symptoms are invisible
// attachments until one zooms in on the avatar.
//
// We do not pause if we are launching on the same thread anyway in order to avoid pointlessly
// delaying any attachment related regression tests.
if (AttachmentsModule != null)
Util.FireAndForget(
o =>
{
if (Util.FireAndForgetMethod != FireAndForgetMethod.None)
Thread.Sleep(5000);
AttachmentsModule.RezAttachments(sp);
});
}
} }
else else
{ {
@ -4344,33 +4317,33 @@ namespace OpenSim.Region.Framework.Scenes
// } // }
// } // }
/// <summary> // /// <summary>
/// Triggered when an agent crosses into this sim. Also happens on initial login. // /// Triggered when an agent crosses into this sim. Also happens on initial login.
/// </summary> // /// </summary>
/// <param name="agentID"></param> // /// <param name="agentID"></param>
/// <param name="position"></param> // /// <param name="position"></param>
/// <param name="isFlying"></param> // /// <param name="isFlying"></param>
public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying) // public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
{ // {
ScenePresence presence = GetScenePresence(agentID); // ScenePresence presence = GetScenePresence(agentID);
if (presence != null) // if (presence != null)
{ // {
try // try
{ // {
presence.MakeRootAgent(position, isFlying); // presence.MakeRootAgent(position, isFlying);
} // }
catch (Exception e) // catch (Exception e)
{ // {
m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace); // m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace);
} // }
} // }
else // else
{ // {
m_log.ErrorFormat( // m_log.ErrorFormat(
"[SCENE]: Could not find presence for agent {0} crossing into scene {1}", // "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
agentID, RegionInfo.RegionName); // agentID, RegionInfo.RegionName);
} // }
} // }
/// <summary> /// <summary>
/// We've got an update about an agent that sees into this region, /// We've got an update about an agent that sees into this region,

View File

@ -3743,6 +3743,10 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="events"></param> /// <param name="events"></param>
public void SetScriptEvents(UUID scriptid, int events) public void SetScriptEvents(UUID scriptid, int events)
{ {
// m_log.DebugFormat(
// "[SCENE OBJECT PART]: Set script events for script with id {0} on {1}/{2} to {3} in {4}",
// scriptid, Name, ParentGroup.Name, events, ParentGroup.Scene.Name);
// scriptEvents oldparts; // scriptEvents oldparts;
lock (m_scriptEvents) lock (m_scriptEvents)
{ {

View File

@ -456,9 +456,9 @@ namespace OpenSim.Region.Framework.Scenes
{ {
m_pos = PhysicsActor.Position; m_pos = PhysicsActor.Position;
//m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE PRESENCE]: Set position {0} for {1} in {2} via getting AbsolutePosition!", // "[SCENE PRESENCE]: Set position of {0} in {1} to {2} via getting AbsolutePosition!",
// m_pos, Name, Scene.RegionInfo.RegionName); // Name, Scene.Name, m_pos);
} }
else else
{ {
@ -485,6 +485,9 @@ namespace OpenSim.Region.Framework.Scenes
} }
set set
{ {
// m_log.DebugFormat("[SCENE PRESENCE]: Setting position of {0} in {1} to {2}", Name, Scene.Name, value);
// Util.PrintCallStack();
if (PhysicsActor != null) if (PhysicsActor != null)
{ {
try try
@ -938,8 +941,6 @@ namespace OpenSim.Region.Framework.Scenes
"[SCENE]: Upgrading child to root agent for {0} in {1}", "[SCENE]: Upgrading child to root agent for {0} in {1}",
Name, m_scene.RegionInfo.RegionName); Name, m_scene.RegionInfo.RegionName);
bool wasChild = IsChildAgent;
if (ParentUUID != UUID.Zero) if (ParentUUID != UUID.Zero)
{ {
m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID); m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID);
@ -972,6 +973,9 @@ namespace OpenSim.Region.Framework.Scenes
IsLoggingIn = false; IsLoggingIn = false;
} }
//m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
IsChildAgent = false;
IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
if (gm != null) if (gm != null)
@ -1065,6 +1069,13 @@ namespace OpenSim.Region.Framework.Scenes
else else
AddToPhysicalScene(isFlying); AddToPhysicalScene(isFlying);
// XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a
// location outside the 'root region' (the south-west 256x256 corner). This is the earlist we can do it
// since it requires a physics actor to be present. If it is left any later, then physics appears to reset
// the value to a negative position which does not trigger the border cross.
// This may not be the best location for this.
CheckForBorderCrossing();
if (ForceFly) if (ForceFly)
{ {
Flying = true; Flying = true;
@ -1085,22 +1096,43 @@ namespace OpenSim.Region.Framework.Scenes
// and it has already rezzed the attachments and started their scripts. // and it has already rezzed the attachments and started their scripts.
// We do the following only for non-login agents, because their scripts // We do the following only for non-login agents, because their scripts
// haven't started yet. // haven't started yet.
lock (m_attachments) if (PresenceType == PresenceType.Npc || (TeleportFlags & TeleportFlags.ViaLogin) != 0)
{ {
if (wasChild && HasAttachments()) // Viewers which have a current outfit folder will actually rez their own attachments. However,
{ // viewers without (e.g. v1 viewers) will not, so we still need to make this call.
m_log.DebugFormat( if (Scene.AttachmentsModule != null)
"[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); Util.FireAndForget(
o =>
// Resume scripts
Util.FireAndForget(delegate(object x) {
foreach (SceneObjectGroup sog in m_attachments)
{ {
sog.ScheduleGroupForFullUpdate(); // if (PresenceType != PresenceType.Npc && Util.FireAndForgetMethod != FireAndForgetMethod.None)
sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); // System.Threading.Thread.Sleep(7000);
sog.ResumeScripts();
} Scene.AttachmentsModule.RezAttachments(this);
}); });
}
else
{
// We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT
// and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
// be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
// not transporting the required data.
lock (m_attachments)
{
if (HasAttachments())
{
m_log.DebugFormat(
"[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
// Resume scripts
Util.FireAndForget(delegate(object x) {
foreach (SceneObjectGroup sog in m_attachments)
{
sog.ScheduleGroupForFullUpdate();
sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
sog.ResumeScripts();
}
});
}
} }
} }
@ -3121,6 +3153,10 @@ namespace OpenSim.Region.Framework.Scenes
if (!IsInTransit) if (!IsInTransit)
{ {
// m_log.DebugFormat(
// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}",
// pos2, Name, Scene.Name);
// Checks if where it's headed exists a region // Checks if where it's headed exists a region
bool needsTransit = false; bool needsTransit = false;
if (m_scene.TestBorderCross(pos2, Cardinals.W)) if (m_scene.TestBorderCross(pos2, Cardinals.W))

View File

@ -184,7 +184,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
hostPart.ParentGroup.RootPart.ScheduleFullUpdate(); hostPart.ParentGroup.RootPart.ScheduleFullUpdate();
} }
return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true, true, true) ? 1 : 0; return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, false, true, true) ? 1 : 0;
} }
} }
} }

View File

@ -116,6 +116,37 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
+ "If teleport is true then some extra teleport debug information is logged.\n" + "If teleport is true then some extra teleport debug information is logged.\n"
+ "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
HandleDebugSceneSetCommand); HandleDebugSceneSetCommand);
scene.AddCommand(
"Regions",
this, "show borders", "show borders", "Show border information for regions", HandleShowBordersCommand);
}
private void HandleShowBordersCommand(string module, string[] args)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Borders for {0}:\n", m_scene.Name);
ConsoleDisplayTable cdt = new ConsoleDisplayTable();
cdt.AddColumn("Cross Direction", 15);
cdt.AddColumn("Line", 34);
cdt.AddColumn("Trigger Region", 14);
foreach (Border b in m_scene.NorthBorders)
cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
foreach (Border b in m_scene.EastBorders)
cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
foreach (Border b in m_scene.SouthBorders)
cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
foreach (Border b in m_scene.WestBorders)
cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
cdt.AddToStringBuilder(sb);
MainConsole.Instance.Output(sb.ToString());
} }
private void HandleDebugSceneGetCommand(string module, string[] args) private void HandleDebugSceneGetCommand(string module, string[] args)

View File

@ -321,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
} }
internal void ProcessTypeChange(Vehicle pType) public void ProcessTypeChange(Vehicle pType)
{ {
VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
// Set Defaults For Type // Set Defaults For Type
@ -1301,14 +1301,52 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
public void ComputeAngularVerticalAttraction() public void ComputeAngularVerticalAttraction()
{ {
// If vertical attaction timescale is reasonable // If vertical attaction timescale is reasonable
if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
{ {
// Possible solution derived from a discussion at:
// http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
// Create a rotation that is only the vehicle's rotation around Z
Vector3 currentEuler = Vector3.Zero;
VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z);
Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z);
// Create the axis that is perpendicular to the up vector and the rotated up vector.
Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
// Compute the angle between those to vectors.
double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
// 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
// Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
// TODO: add 'efficiency'.
differenceAngle /= m_verticalAttractionTimescale;
// Create the quaterian representing the correction angle
Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle);
// Turn that quaternion into Euler values to make it into velocities to apply.
Vector3 vertContributionV = Vector3.Zero;
correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z);
vertContributionV *= -1f;
VehicleRotationalVelocity += vertContributionV;
VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
Prim.LocalID,
differenceAxis,
differenceAngle,
correctionRotation,
vertContributionV);
// ===================================================================
/*
Vector3 vertContributionV = Vector3.Zero; Vector3 vertContributionV = Vector3.Zero;
Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
// Take a vector pointing up and convert it from world to vehicle relative coords. // Take a vector pointing up and convert it from world to vehicle relative coords.
Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
// If vertical attraction correction is needed, the vector that was pointing up (UnitZ) // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
// is now: // is now:
@ -1334,13 +1372,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// 'vertContrbution' is now the necessary angular correction to correct tilt in one second. // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
// Correction happens over a number of seconds. // Correction happens over a number of seconds.
Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
// The correction happens over the user's time period
vertContributionV /= m_verticalAttractionTimescale; vertContributionV /= m_verticalAttractionTimescale;
VehicleRotationalVelocity += vertContributionV; // Rotate the vehicle rotation to the world coordinates.
VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
*/
} }
} }

View File

@ -180,11 +180,14 @@ public static class BSMaterials
// Use reflection to set the value in the attribute structure. // Use reflection to set the value in the attribute structure.
private static void SetAttributeValue(int matType, string attribName, float val) private static void SetAttributeValue(int matType, string attribName, float val)
{ {
// Get the current attribute values for this material
MaterialAttributes thisAttrib = Attributes[matType]; MaterialAttributes thisAttrib = Attributes[matType];
// Find the field for the passed attribute name (eg, find field named 'friction')
FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
if (fieldInfo != null) if (fieldInfo != null)
{ {
fieldInfo.SetValue(thisAttrib, val); fieldInfo.SetValue(thisAttrib, val);
// Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
Attributes[matType] = thisAttrib; Attributes[matType] = thisAttrib;
} }
} }

View File

@ -142,6 +142,14 @@ public static class BSParam
public static float VehicleAngularBankingTimescaleFudge { get; private set; } public static float VehicleAngularBankingTimescaleFudge { get; private set; }
public static bool VehicleDebuggingEnabled { get; private set; } public static bool VehicleDebuggingEnabled { get; private set; }
// Convex Hulls
public static int CSHullMaxDepthSplit { get; private set; }
public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
public static float CSHullConcavityThresholdPercent { get; private set; }
public static float CSHullVolumeConservationThresholdPercent { get; private set; }
public static int CSHullMaxVertices { get; private set; }
public static float CSHullMaxSkinWidth { get; private set; }
// Linkset implementation parameters // Linkset implementation parameters
public static float LinksetImplementation { get; private set; } public static float LinksetImplementation { get; private set; }
public static bool LinkConstraintUseFrameOffset { get; private set; } public static bool LinkConstraintUseFrameOffset { get; private set; }
@ -195,10 +203,10 @@ public static class BSParam
public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj); public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
public sealed class ParameterDefn<T> : ParameterDefnBase public sealed class ParameterDefn<T> : ParameterDefnBase
{ {
T defaultValue; private T defaultValue;
PSetValue<T> setter; private PSetValue<T> setter;
PGetValue<T> getter; private PGetValue<T> getter;
PSetOnObject<T> objectSet; private PSetOnObject<T> objectSet;
public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter) public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
: base(pName, pDesc) : base(pName, pDesc)
{ {
@ -215,13 +223,23 @@ public static class BSParam
getter = pGetter; getter = pGetter;
objectSet = pObjSetter; objectSet = pObjSetter;
} }
/* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work
public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc)
: base(pName, pDesc)
{
defaultValue = pDefault;
setter = (s, v) => { loc = v; };
getter = (s) => { return loc; };
objectSet = null;
}
*/
public override void AssignDefault(BSScene s) public override void AssignDefault(BSScene s)
{ {
setter(s, defaultValue); setter(s, defaultValue);
} }
public override string GetValue(BSScene s) public override string GetValue(BSScene s)
{ {
return String.Format("{0}", getter(s)); return getter(s).ToString();
} }
public override void SetValue(BSScene s, string valAsString) public override void SetValue(BSScene s, string valAsString)
{ {
@ -244,6 +262,7 @@ public static class BSParam
try try
{ {
T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
// Store the parsed value
setter(s, setValue); setter(s, setValue);
// s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
} }
@ -463,7 +482,7 @@ public static class BSParam
(s) => { return TerrainImplementation; }, (s) => { return TerrainImplementation; },
(s,v) => { TerrainImplementation = v; } ), (s,v) => { TerrainImplementation = v; } ),
new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
3, 2,
(s) => { return TerrainMeshMagnification; }, (s) => { return TerrainMeshMagnification; },
(s,v) => { TerrainMeshMagnification = v; } ), (s,v) => { TerrainMeshMagnification = v; } ),
new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
@ -623,6 +642,31 @@ public static class BSParam
(s) => { return GlobalContactBreakingThreshold; }, (s) => { return GlobalContactBreakingThreshold; },
(s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
7,
(s) => { return CSHullMaxDepthSplit; },
(s,v) => { CSHullMaxDepthSplit = v; } ),
new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
2,
(s) => { return CSHullMaxDepthSplitForSimpleShapes; },
(s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ),
new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
5f,
(s) => { return CSHullConcavityThresholdPercent; },
(s,v) => { CSHullConcavityThresholdPercent = v; } ),
new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
5f,
(s) => { return CSHullVolumeConservationThresholdPercent; },
(s,v) => { CSHullVolumeConservationThresholdPercent = v; } ),
new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
32,
(s) => { return CSHullMaxVertices; },
(s,v) => { CSHullMaxVertices = v; } ),
new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
0,
(s) => { return CSHullMaxSkinWidth; },
(s,v) => { CSHullMaxSkinWidth = v; } ),
new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
(float)BSLinkset.LinksetImplementation.Compound, (float)BSLinkset.LinksetImplementation.Compound,
(s) => { return LinksetImplementation; }, (s) => { return LinksetImplementation; },

View File

@ -86,7 +86,7 @@ public abstract class BSPhysObject : PhysicsActor
PhysBody = new BulletBody(localID); PhysBody = new BulletBody(localID);
PhysShape = new BulletShape(); PhysShape = new BulletShape();
LastAssetBuildFailed = false; PrimAssetState = PrimAssetCondition.Unknown;
// Default material type. Also sets Friction, Restitution and Density. // Default material type. Also sets Friction, Restitution and Density.
SetMaterial((int)MaterialAttributes.Material.Wood); SetMaterial((int)MaterialAttributes.Material.Wood);
@ -133,9 +133,13 @@ public abstract class BSPhysObject : PhysicsActor
// Reference to the physical shape (btCollisionShape) of this object // Reference to the physical shape (btCollisionShape) of this object
public BulletShape PhysShape; public BulletShape PhysShape;
// 'true' if the mesh's underlying asset failed to build. // The physical representation of the prim might require an asset fetch.
// This will keep us from looping after the first time the build failed. // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
public bool LastAssetBuildFailed { get; set; } public enum PrimAssetCondition
{
Unknown, Waiting, Failed, Fetched
}
public PrimAssetCondition PrimAssetState { get; set; }
// The objects base shape information. Null if not a prim type shape. // The objects base shape information. Null if not a prim type shape.
public PrimitiveBaseShape BaseShape { get; protected set; } public PrimitiveBaseShape BaseShape { get; protected set; }

View File

@ -155,7 +155,7 @@ public class BSPrim : BSPhysObject
public override PrimitiveBaseShape Shape { public override PrimitiveBaseShape Shape {
set { set {
BaseShape = value; BaseShape = value;
LastAssetBuildFailed = false; PrimAssetState = PrimAssetCondition.Unknown;
ForceBodyShapeRebuild(false); ForceBodyShapeRebuild(false);
} }
} }

View File

@ -447,17 +447,10 @@ public sealed class BSShapeCollection : IDisposable
// If the prim attributes are simple, this could be a simple Bullet native shape // If the prim attributes are simple, this could be a simple Bullet native shape
if (!haveShape if (!haveShape
&& nativeShapePossible
&& pbs != null && pbs != null
&& !pbs.SculptEntry && !pbs.SculptEntry
&& nativeShapePossible && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) )
&& ((pbs.SculptEntry && !BSParam.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) ) )
{ {
// Get the scale of any existing shape so we can see if the new shape is same native type and same size. // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
@ -508,6 +501,18 @@ public sealed class BSShapeCollection : IDisposable
return ret; return ret;
} }
// return 'true' if this shape description does not include any cutting or twisting.
private bool PrimHasNoCuts(PrimitiveBaseShape pbs)
{
return 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;
}
// return 'true' if the prim's shape was changed. // return 'true' if the prim's shape was changed.
public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{ {
@ -518,7 +523,7 @@ public sealed class BSShapeCollection : IDisposable
if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
{ {
// Update prim.BSShape to reference a hull of this shape. // Update prim.BSShape to reference a hull of this shape.
ret = GetReferenceToHull(prim,shapeCallback); ret = GetReferenceToHull(prim, shapeCallback);
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
} }
@ -699,6 +704,7 @@ public sealed class BSShapeCollection : IDisposable
// See that hull shape exists in the physical world and update prim.BSShape. // See that hull shape exists in the physical world and update prim.BSShape.
// We could be creating the hull because scale changed or whatever. // We could be creating the hull because scale changed or whatever.
// Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
{ {
BulletShape newShape; BulletShape newShape;
@ -717,6 +723,7 @@ public sealed class BSShapeCollection : IDisposable
DereferenceShape(prim.PhysShape, shapeCallback); DereferenceShape(prim.PhysShape, shapeCallback);
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
// It might not have been created if we're waiting for an asset.
newShape = VerifyMeshCreated(newShape, prim); newShape = VerifyMeshCreated(newShape, prim);
ReferenceShape(newShape); ReferenceShape(newShape);
@ -735,13 +742,13 @@ public sealed class BSShapeCollection : IDisposable
HullDesc hullDesc; HullDesc hullDesc;
if (Hulls.TryGetValue(newHullKey, out hullDesc)) if (Hulls.TryGetValue(newHullKey, out hullDesc))
{ {
// If the hull shape already is created, just use it. // If the hull shape already has been created, just use the one shared instance.
newShape = hullDesc.shape.Clone(); newShape = hullDesc.shape.Clone();
} }
else else
{ {
// Build a new hull in the physical world // Build a new hull in the physical world.
// Pass true for physicalness as this creates some sort of bounding box which we don't need // Pass true for physicalness as this prevents the creation of bounding box which is not needed
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
if (meshData != null) if (meshData != null)
{ {
@ -761,15 +768,35 @@ public sealed class BSShapeCollection : IDisposable
convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
} }
uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
{
// Simple primitive shapes we know are convex so they are better implemented with
// fewer hulls.
// Check for simple shape (prim without cuts) and reduce split parameter if so.
if (PrimHasNoCuts(pbs))
{
maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
}
}
// setup and do convex hull conversion // setup and do convex hull conversion
m_hulls = new List<ConvexResult>(); m_hulls = new List<ConvexResult>();
DecompDesc dcomp = new DecompDesc(); DecompDesc dcomp = new DecompDesc();
dcomp.mIndices = convIndices; dcomp.mIndices = convIndices;
dcomp.mVertices = convVertices; dcomp.mVertices = convVertices;
dcomp.mDepth = maxDepthSplit;
dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
// create the hull into the _hulls variable // create the hull into the _hulls variable
convexBuilder.process(dcomp); convexBuilder.process(dcomp);
DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
// Convert the vertices and indices for passing to unmanaged. // Convert the vertices and indices for passing to unmanaged.
// The hull information is passed as a large floating point array. // The hull information is passed as a large floating point array.
// The format is: // The format is:
@ -904,58 +931,79 @@ public sealed class BSShapeCollection : IDisposable
if (newShape.HasPhysicalShape) if (newShape.HasPhysicalShape)
return newShape; return newShape;
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) // fetched but we end up here again, the meshing of the asset must have failed.
// Prevent trying to keep fetching the mesh by declaring failure.
if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
{ {
DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lastFailed={1}", prim.LocalID, prim.LastAssetBuildFailed); prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
// This will prevent looping through this code as we keep trying to get the failed shape PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
prim.LastAssetBuildFailed = true; LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
BSPhysObject xprim = prim;
Util.FireAndForget(delegate
{
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
if (assetProvider != null)
{
BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
{
bool assetFound = false; // DEBUG DEBUG
string mismatchIDs = String.Empty; // DEBUG DEBUG
if (asset != null && yprim.BaseShape.SculptEntry)
{
if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
{
yprim.BaseShape.SculptData = asset.Data;
// This will cause the prim to see that the filler shape is not the right
// one and try again to build the object.
// No race condition with the normal shape setting since the rebuild is at taint time.
yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
assetFound = true;
}
else
{
mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
}
}
DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
});
}
else
{
PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
LogHeader, PhysicsScene.Name);
}
});
} }
else else
{ {
if (prim.LastAssetBuildFailed) // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
if (prim.BaseShape.SculptEntry
&& prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed
&& prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
&& prim.BaseShape.SculptTexture != OMV.UUID.Zero
)
{ {
PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); // Multiple requestors will know we're waiting for this asset
prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
BSPhysObject xprim = prim;
Util.FireAndForget(delegate
{
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
if (assetProvider != null)
{
BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
{
bool assetFound = false;
string mismatchIDs = String.Empty; // DEBUG DEBUG
if (asset != null && yprim.BaseShape.SculptEntry)
{
if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
{
yprim.BaseShape.SculptData = asset.Data;
// This will cause the prim to see that the filler shape is not the right
// one and try again to build the object.
// No race condition with the normal shape setting since the rebuild is at taint time.
yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
assetFound = true;
}
else
{
mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
}
}
if (assetFound)
yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
else
yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
});
}
else
{
xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
LogHeader, PhysicsScene.Name);
}
});
}
else
{
if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
{
PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
}
} }
} }

View File

@ -132,6 +132,7 @@ public sealed class BSTerrainManager : IDisposable
// safe to call Bullet in real time. We hope no one is moving prims around yet. // safe to call Bullet in real time. We hope no one is moving prims around yet.
public void CreateInitialGroundPlaneAndTerrain() public void CreateInitialGroundPlaneAndTerrain()
{ {
DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
// 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 = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
@ -145,14 +146,18 @@ public sealed class BSTerrainManager : IDisposable
m_groundPlane.collisionType = CollisionType.Groundplane; m_groundPlane.collisionType = CollisionType.Groundplane;
m_groundPlane.ApplyCollisionMask(PhysicsScene); m_groundPlane.ApplyCollisionMask(PhysicsScene);
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
m_terrains.Add(Vector3.Zero, initialTerrain); lock (m_terrains)
{
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
m_terrains.Add(Vector3.Zero, initialTerrain);
}
} }
// Release all the terrain structures we might have allocated // Release all the terrain structures we might have allocated
public void ReleaseGroundPlaneAndTerrain() public void ReleaseGroundPlaneAndTerrain()
{ {
DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName);
if (m_groundPlane.HasPhysicalBody) if (m_groundPlane.HasPhysicalBody)
{ {
if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
@ -193,11 +198,16 @@ public sealed class BSTerrainManager : IDisposable
// the terrain is added to our parent // the terrain is added to our parent
if (MegaRegionParentPhysicsScene 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); // This looks really odd but this region is passing its terrain to its mega-region root region
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( // and the creation of the terrain must happen on the root region's taint thread and not
BSScene.CHILDTERRAIN_ID, localHeightMap, // my taint thread.
m_worldOffset, m_worldOffset + DefaultRegionSize, true); ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate()
{
((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
BSScene.CHILDTERRAIN_ID, localHeightMap,
m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
});
} }
} }
else else
@ -206,16 +216,16 @@ public sealed class BSTerrainManager : IDisposable
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
m_worldOffset, m_worldOffset + DefaultRegionSize, true); m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */);
} }
}); });
} }
// If called with no mapInfo for the terrain, this will create a new mapInfo and terrain // If called for terrain has has not been previously allocated, a new terrain will be built
// based on the passed information. The 'id' should be either the terrain id or // based on the passed information. The 'id' should be either the terrain id or
// BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
// The latter feature is for creating child terrains for mega-regions. // The latter feature is for creating child terrains for mega-regions.
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new // If there is an existing terrain body, a new
// terrain shape is created and added to the body. // terrain shape is created and added to the body.
// This call is most often used to update the heightMap and parameters of the terrain. // This call is most often used to update the heightMap and parameters of the terrain.
// (The above does suggest that some simplification/refactoring is in order.) // (The above does suggest that some simplification/refactoring is in order.)
@ -223,8 +233,8 @@ public sealed class BSTerrainManager : IDisposable
private void UpdateTerrain(uint id, float[] heightMap, private void UpdateTerrain(uint id, float[] heightMap,
Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{ {
DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}",
BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime);
// Find high and low points of passed heightmap. // Find high and low points of passed heightmap.
// The min and max passed in is usually the area objects can be in (maximum // The min and max passed in is usually the area objects can be in (maximum
@ -253,7 +263,7 @@ public sealed class BSTerrainManager : IDisposable
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
{ {
// There is already a terrain in this spot. Free the old and build the new. // There is already a terrain in this spot. Free the old and build the new.
DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
// Remove old terrain from the collection // Remove old terrain from the collection
@ -292,7 +302,7 @@ public sealed class BSTerrainManager : IDisposable
if (newTerrainID >= BSScene.CHILDTERRAIN_ID) if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
newTerrainID = ++m_terrainCount; newTerrainID = ++m_terrainCount;
DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
m_terrains.Add(terrainRegionBase, newTerrainPhys); m_terrains.Add(terrainRegionBase, newTerrainPhys);
@ -343,37 +353,35 @@ public sealed class BSTerrainManager : IDisposable
{ {
Vector3 ret = pPos; Vector3 ret = pPos;
// First, base addresses are never negative so correct for that possible problem.
if (ret.X < 0f || ret.Y < 0f)
{
ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
BSScene.DetailLogZero, pPos, ret);
}
// Can't do this function if we don't know about any terrain. // Can't do this function if we don't know about any terrain.
if (m_terrains.Count == 0) if (m_terrains.Count == 0)
return ret; return ret;
int loopPrevention = 5; int loopPrevention = 10;
Vector3 terrainBaseXYZ; Vector3 terrainBaseXYZ;
BSTerrainPhys physTerrain; BSTerrainPhys physTerrain;
while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
{ {
// The passed position is not within a known terrain area. // The passed position is not within a known terrain area.
// NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
// First, base addresses are never negative so correct for that possible problem. // Must be off the top of a region. Find an adjacent region to move into.
if (ret.X < 0f || ret.Y < 0f) Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
{
if (ret.X < 0f) ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X));
ret.X = 0f; ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y));
if (ret.Y < 0f) DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
ret.Y = 0f; BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
BSScene.DetailLogZero, pPos, ret);
}
else
{
// Must be off the top of a region. Find an adjacent region to move into.
Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
ret.X = Math.Min(ret.X, adjacentTerrainBase.X + DefaultRegionSize.X);
ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + DefaultRegionSize.Y);
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
}
if (loopPrevention-- < 0f) if (loopPrevention-- < 0f)
{ {
// The 'while' is a little dangerous so this prevents looping forever if the // The 'while' is a little dangerous so this prevents looping forever if the
@ -383,6 +391,7 @@ public sealed class BSTerrainManager : IDisposable
break; break;
} }
} }
return ret; return ret;
} }
@ -479,11 +488,20 @@ public sealed class BSTerrainManager : IDisposable
private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
{ {
Vector3 ret = pTerrainBase; Vector3 ret = pTerrainBase;
// Can't do this function if we don't know about any terrain.
if (m_terrains.Count == 0)
return ret;
// Just some sanity
ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
ret.Z = 0f; ret.Z = 0f;
lock (m_terrains) lock (m_terrains)
{ {
// Once down to the <0,0> region, we have to be done. // Once down to the <0,0> region, we have to be done.
while (ret.X > 0f && ret.Y > 0f) while (ret.X > 0f || ret.Y > 0f)
{ {
if (ret.X > 0f) if (ret.X > 0f)
{ {

View File

@ -98,20 +98,20 @@ public sealed class BSTerrainMesh : BSTerrainPhys
if (!meshCreationSuccess) if (!meshCreationSuccess)
{ {
// DISASTER!! // DISASTER!!
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
// Something is very messed up and a crash is in our future. // Something is very messed up and a crash is in our future.
return; return;
} }
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
ID, indicesCount, indices.Length, verticesCount, vertices.Length); BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
if (!m_terrainShape.HasPhysicalShape) if (!m_terrainShape.HasPhysicalShape)
{ {
// DISASTER!! // DISASTER!!
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
// Something is very messed up and a crash is in our future. // Something is very messed up and a crash is in our future.
return; return;
@ -151,7 +151,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
if (BSParam.UseSingleSidedMeshes) if (BSParam.UseSingleSidedMeshes)
{ {
PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial", id); PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
} }

View File

@ -415,18 +415,17 @@ namespace OpenSim.Region.RegionCombinerModule
*/ */
#endregion #endregion
// If we're one region over +x y // If we're one region over +x y (i.e. root region is to the west)
//xxx //xxx
//xxy //xxy
//xxx //xxx
if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY) if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY)
{ {
connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
break; break;
} }
// If we're one region over x +y // If we're one region over x +y (i.e. root region is to the south)
//xyx //xyx
//xxx //xxx
//xxx //xxx
@ -436,7 +435,7 @@ namespace OpenSim.Region.RegionCombinerModule
break; break;
} }
// If we're one region over +x +y // If we're one region over +x +y (i.e. root region is to the south-west)
//xxy //xxy
//xxx //xxx
//xxx //xxx
@ -646,7 +645,6 @@ namespace OpenSim.Region.RegionCombinerModule
{ {
if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2) if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2)
{ {
rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;
lock (rootConn.RegionScene.NorthBorders) lock (rootConn.RegionScene.NorthBorders)

View File

@ -71,6 +71,7 @@ using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
using System.Reflection; using System.Reflection;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
using System.Linq;
using PermissionMask = OpenSim.Framework.PermissionMask; using PermissionMask = OpenSim.Framework.PermissionMask;
namespace OpenSim.Region.ScriptEngine.Shared.Api namespace OpenSim.Region.ScriptEngine.Shared.Api
@ -150,6 +151,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{"TURNLEFT", "Turning Left"}, {"TURNLEFT", "Turning Left"},
{"TURNRIGHT", "Turning Right"} {"TURNRIGHT", "Turning Right"}
}; };
//An array of HTTP/1.1 headers that are not allowed to be used
//as custom headers by llHTTPRequest.
private string[] HttpStandardHeaders =
{
"Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language",
"Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control",
"Connection", "Content-Encoding", "Content-Language",
"Content-Length", "Content-Location", "Content-MD5",
"Content-Range", "Content-Type", "Date", "ETag", "Expect",
"Expires", "From", "Host", "If-Match", "If-Modified-Since",
"If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified",
"Location", "Max-Forwards", "Pragma", "Proxy-Authenticate",
"Proxy-Authorization", "Range", "Referer", "Retry-After", "Server",
"TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent",
"Vary", "Via", "Warning", "WWW-Authenticate"
};
public void Initialize( public void Initialize(
IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle) IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle)
@ -1750,7 +1767,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if (tex.FaceTextures[i] != null) if (tex.FaceTextures[i] != null)
{ {
tex.FaceTextures[i].Shiny = sval; tex.FaceTextures[i].Shiny = sval;
tex.FaceTextures[i].Bump = bump;; tex.FaceTextures[i].Bump = bump;
} }
tex.DefaultTexture.Shiny = sval; tex.DefaultTexture.Shiny = sval;
tex.DefaultTexture.Bump = bump; tex.DefaultTexture.Bump = bump;
@ -2038,12 +2055,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
UUID textureID = new UUID(); UUID textureID = new UUID();
textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture); textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture);
if (textureID == UUID.Zero) if (textureID == UUID.Zero)
{ {
if (!UUID.TryParse(texture, out textureID)) if (!UUID.TryParse(texture, out textureID))
return; return;
} }
Primitive.TextureEntry tex = part.Shape.Textures; Primitive.TextureEntry tex = part.Shape.Textures;
@ -11127,9 +11144,60 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
IHttpRequestModule httpScriptMod = IHttpRequestModule httpScriptMod =
m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>(); m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
List<string> param = new List<string>(); List<string> param = new List<string>();
foreach (object o in parameters.Data) bool ok;
Int32 flag;
for (int i = 0; i < parameters.Data.Length; i += 2)
{ {
param.Add(o.ToString()); ok = Int32.TryParse(parameters.Data[i].ToString(), out flag);
if (!ok || flag < 0 ||
flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE)
{
throw new ScriptException("Parameter " + i.ToString() + " is an invalid flag");
}
param.Add(parameters.Data[i].ToString()); //Add parameter flag
if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER)
{
param.Add(parameters.Data[i+1].ToString()); //Add parameter value
}
else
{
//Parameters are in pairs and custom header takes
//arguments in pairs so adjust for header marker.
++i;
//Maximum of 8 headers are allowed based on the
//Second Life documentation for llHTTPRequest.
for (int count = 1; count <= 8; ++count)
{
//Enough parameters remaining for (another) header?
if (parameters.Data.Length - i < 2)
{
//There must be at least one name/value pair for custom header
if (count == 1)
throw new ScriptException("Missing name/value for custom header at parameter " + i.ToString());
break;
}
if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase))
throw new ScriptException("Name is invalid as a custom header at parameter " + i.ToString());
param.Add(parameters.Data[i].ToString());
param.Add(parameters.Data[i+1].ToString());
//Have we reached the end of the list of headers?
//End is marked by a string with a single digit.
if (i+2 >= parameters.Data.Length ||
Char.IsDigit(parameters.Data[i].ToString()[0]))
{
break;
}
i += 2;
}
}
} }
Vector3 position = m_host.AbsolutePosition; Vector3 position = m_host.AbsolutePosition;

View File

@ -356,6 +356,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
public const int HTTP_MIMETYPE = 1; public const int HTTP_MIMETYPE = 1;
public const int HTTP_BODY_MAXLENGTH = 2; public const int HTTP_BODY_MAXLENGTH = 2;
public const int HTTP_VERIFY_CERT = 3; public const int HTTP_VERIFY_CERT = 3;
public const int HTTP_VERBOSE_THROTTLE = 4;
public const int HTTP_CUSTOM_HEADER = 5;
public const int HTTP_PRAGMA_NO_CACHE = 6;
public const int PRIM_MATERIAL = 2; public const int PRIM_MATERIAL = 2;
public const int PRIM_PHYSICS = 3; public const int PRIM_PHYSICS = 3;