Merge branch 'master' into varregion

varregion
Robert Adams 2014-01-19 07:38:53 -08:00
commit f127e4b4ee
22 changed files with 320 additions and 356 deletions

View File

@ -1,5 +1,4 @@
<<<>>>>The following people have contributed to OpenSim (Thank you The following people have contributed to OpenSim (Thank you for your effort!)
for your effort!)
= Current OpenSim Developers (in very rough order of appearance) = = Current OpenSim Developers (in very rough order of appearance) =
These folks represent the current core team for OpenSim, and are the These folks represent the current core team for OpenSim, and are the
@ -61,8 +60,9 @@ where we are today.
These folks have contributed code patches or content to OpenSimulator to help make it These folks have contributed code patches or content to OpenSimulator to help make it
what it is today. what it is today.
* aduffy70
* A_Biondi * A_Biondi
* aduffy70
* Ai Austin
* alex_carnell * alex_carnell
* Alan Webb (IBM) * Alan Webb (IBM)
* Aleric * Aleric
@ -75,7 +75,7 @@ what it is today.
* Chris Yeoh (IBM) * Chris Yeoh (IBM)
* controlbreak * controlbreak
* coyled * coyled
* ctrlaltdavid * ctrlaltdavid (David Rowe)
* Daedius * Daedius
* daTwitch * daTwitch
* devalnor-#708 * devalnor-#708
@ -173,23 +173,18 @@ what it is today.
* Zha Ewry * Zha Ewry
* ziah * ziah
= LSL Devs = = LSL Devs =
* Alondria * Alondria
* CharlieO * CharlieO
* Tedd * Tedd
* Melanie Thielker * Melanie Thielker
= Testers = = Testers =
* Ai Austin * Ai Austin
* CharlieO (LSL) * CharlieO (LSL)
* Ckrinke * Ckrinke
* openlifegrid.com * openlifegrid.com
This software uses components from the following developers: This software uses components from the following developers:
* Sleepycat Software (Berkeley DB) * Sleepycat Software (Berkeley DB)
* Aurora-Sim (http://aurora-sim.org) * Aurora-Sim (http://aurora-sim.org)

View File

@ -261,6 +261,11 @@ namespace OpenSim.OfflineIM
return m_OfflineIMService.StoreMessage(im, out reason); return m_OfflineIMService.StoreMessage(im, out reason);
} }
public void DeleteMessages(UUID userID)
{
m_OfflineIMService.DeleteMessages(userID);
}
#endregion #endregion
} }
} }

View File

@ -117,6 +117,14 @@ namespace OpenSim.OfflineIM
return true; return true;
} }
public void DeleteMessages(UUID userID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["UserID"] = userID;
MakeRequest("DELETE", sendData);
}
#endregion #endregion

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
@ -96,13 +96,14 @@ namespace OpenSim.OfflineIM
string method = request["METHOD"].ToString(); string method = request["METHOD"].ToString();
request.Remove("METHOD"); request.Remove("METHOD");
m_log.DebugFormat("[OfflineIM.V2.Handler]: {0}", method);
switch (method) switch (method)
{ {
case "GET": case "GET":
return HandleGet(request); return HandleGet(request);
case "STORE": case "STORE":
return HandleStore(request); return HandleStore(request);
case "DELETE":
return HandleDelete(request);
} }
m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method); m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method);
} }
@ -159,6 +160,21 @@ namespace OpenSim.OfflineIM
return Util.UTF8NoBomEncoding.GetBytes(xmlString); return Util.UTF8NoBomEncoding.GetBytes(xmlString);
} }
byte[] HandleDelete(Dictionary<string, object> request)
{
if (!request.ContainsKey("UserID"))
{
return FailureResult();
}
else
{
UUID userID = new UUID(request["UserID"].ToString());
m_OfflineIMService.DeleteMessages(userID);
return SuccessResult();
}
}
#region Helpers #region Helpers
private void NullResult(Dictionary<string, object> result, string reason) private void NullResult(Dictionary<string, object> result, string reason)

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
@ -91,7 +91,7 @@ namespace OpenSim.OfflineIM
{ {
reason = string.Empty; reason = string.Empty;
// TODO Check limits // Check limits
UUID principalID = new UUID(im.toAgentID); UUID principalID = new UUID(im.toAgentID);
long count = m_Database.GetCount("PrincipalID", principalID.ToString()); long count = m_Database.GetCount("PrincipalID", principalID.ToString());
if (count >= MAX_IM) if (count >= MAX_IM)
@ -100,7 +100,7 @@ namespace OpenSim.OfflineIM
return false; return false;
} }
string imXml = string.Empty; string imXml;
using (MemoryStream mstream = new MemoryStream()) using (MemoryStream mstream = new MemoryStream())
{ {
XmlWriterSettings settings = new XmlWriterSettings(); XmlWriterSettings settings = new XmlWriterSettings();
@ -110,22 +110,26 @@ namespace OpenSim.OfflineIM
{ {
m_serializer.Serialize(writer, im); m_serializer.Serialize(writer, im);
writer.Flush(); writer.Flush();
mstream.Position = 0;
using (StreamReader sreader = new StreamReader(mstream))
{
imXml = sreader.ReadToEnd();
}
} }
imXml = Util.UTF8.GetString(mstream.ToArray());
} }
OfflineIMData data = new OfflineIMData(); OfflineIMData data = new OfflineIMData();
data.PrincipalID = principalID; data.PrincipalID = principalID;
data.FromID = new UUID(im.fromAgentID);
data.Data = new Dictionary<string, string>(); data.Data = new Dictionary<string, string>();
data.Data["Message"] = imXml; data.Data["Message"] = imXml;
return m_Database.Store(data); return m_Database.Store(data);
} }
public void DeleteMessages(UUID userID)
{
m_Database.Delete("PrincipalID", userID.ToString());
m_Database.Delete("FromID", userID.ToString());
}
} }
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
@ -34,6 +34,7 @@ namespace OpenSim.Data
public class OfflineIMData public class OfflineIMData
{ {
public UUID PrincipalID; public UUID PrincipalID;
public UUID FromID;
public Dictionary<string, string> Data; public Dictionary<string, string> Data;
} }

View File

@ -22,3 +22,13 @@ DROP TABLE `diva_im_offline`;
DELETE FROM `migrations` WHERE name='diva_im_Store'; DELETE FROM `migrations` WHERE name='diva_im_Store';
COMMIT; COMMIT;
:VERSION 3 # --------------------------
BEGIN;
ALTER TABLE `im_offline`
ADD `FromID` char(36) NOT NULL default '' AFTER `PrincipalID`,
ADD KEY `FromID` (`FromID`);
COMMIT;

View File

@ -31,10 +31,34 @@ namespace OpenSim.Framework
{ {
public interface IImprovedAssetCache public interface IImprovedAssetCache
{ {
/// <summary>
/// Cache the specified asset.
/// </summary>
/// <param name='asset'></param>
void Cache(AssetBase asset); void Cache(AssetBase asset);
/// <summary>
/// Get an asset by its id.
/// </summary>
/// <param name='id'></param>
/// <returns>null if the asset does not exist.</returns>
AssetBase Get(string id); AssetBase Get(string id);
/// <summary>
/// Check whether an asset with the specified id exists in the cache.
/// </summary>
/// <param name='id'></param>
bool Check(string id); bool Check(string id);
/// <summary>
/// Expire an asset from the cache.
/// </summary>
/// <param name='id'></param>
void Expire(string id); void Expire(string id);
/// <summary>
/// Clear the cache.
/// </summary>
void Clear(); void Clear();
} }
} }

View File

@ -194,10 +194,12 @@ namespace OpenSim.Region.CoreModules.Asset
#region IImprovedAssetCache Members #region IImprovedAssetCache Members
public bool Check(string id) public bool Check(string id)
{ {
return false; AssetBase asset;
// XXX:This is probably not an efficient implementation.
return m_cache.TryGetValue(id, out asset);
} }
/// <summary> /// <summary>

View File

@ -114,7 +114,8 @@ namespace OpenSim.Region.CoreModules.Asset
// //
public bool Check(string id) public bool Check(string id)
{ {
return false; // XXX This is probably not an efficient implementation.
return Get(id) != null;
} }
public void Cache(AssetBase asset) public void Cache(AssetBase asset)

View File

@ -248,71 +248,68 @@ namespace OpenSim.Region.CoreModules.Asset
private void UpdateFileCache(string key, AssetBase asset) private void UpdateFileCache(string key, AssetBase asset)
{ {
// TODO: Spawn this off to some seperate thread to do the actual writing string filename = GetFileName(key);
if (asset != null)
try
{ {
string filename = GetFileName(key); // If the file is already cached, don't cache it, just touch it so access time is updated
if (File.Exists(filename))
try
{ {
// If the file is already cached, don't cache it, just touch it so access time is updated // We don't really want to know about sharing
if (File.Exists(filename)) // violations here. If the file is locked, then
// the other thread has updated the time for us.
try
{ {
// We don't really want to know about sharing
// violations here. If the file is locked, then
// the other thread has updated the time for us.
try
{
lock (m_CurrentlyWriting)
{
if (!m_CurrentlyWriting.Contains(filename))
File.SetLastAccessTime(filename, DateTime.Now);
}
}
catch
{
}
} else {
// Once we start writing, make sure we flag that we're writing
// that object to the cache so that we don't try to write the
// same file multiple times.
lock (m_CurrentlyWriting) lock (m_CurrentlyWriting)
{ {
#if WAIT_ON_INPROGRESS_REQUESTS if (!m_CurrentlyWriting.Contains(filename))
if (m_CurrentlyWriting.ContainsKey(filename)) File.SetLastAccessTime(filename, DateTime.Now);
{
return;
}
else
{
m_CurrentlyWriting.Add(filename, new ManualResetEvent(false));
}
#else
if (m_CurrentlyWriting.Contains(filename))
{
return;
}
else
{
m_CurrentlyWriting.Add(filename);
}
#endif
} }
}
Util.FireAndForget( catch
delegate { WriteFileCache(filename, asset); }); {
} }
} }
catch (Exception e) else
{ {
m_log.ErrorFormat( // Once we start writing, make sure we flag that we're writing
"[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}", // that object to the cache so that we don't try to write the
asset.ID, e.Message, e.StackTrace); // same file multiple times.
lock (m_CurrentlyWriting)
{
#if WAIT_ON_INPROGRESS_REQUESTS
if (m_CurrentlyWriting.ContainsKey(filename))
{
return;
}
else
{
m_CurrentlyWriting.Add(filename, new ManualResetEvent(false));
}
#else
if (m_CurrentlyWriting.Contains(filename))
{
return;
}
else
{
m_CurrentlyWriting.Add(filename);
}
#endif
}
Util.FireAndForget(
delegate { WriteFileCache(filename, asset); });
} }
} }
catch (Exception e)
{
m_log.ErrorFormat(
"[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}",
asset.ID, e.Message, e.StackTrace);
}
} }
public void Cache(AssetBase asset) public void Cache(AssetBase asset)
@ -347,15 +344,9 @@ namespace OpenSim.Region.CoreModules.Asset
private bool CheckFromMemoryCache(string id) private bool CheckFromMemoryCache(string id)
{ {
AssetBase asset = null; return m_MemoryCache.Contains(id);
if (m_MemoryCache.TryGetValue(id, out asset))
return true;
return false;
} }
/// <summary> /// <summary>
/// Try to get an asset from the file cache. /// Try to get an asset from the file cache.
/// </summary> /// </summary>
@ -393,15 +384,16 @@ namespace OpenSim.Region.CoreModules.Asset
if (File.Exists(filename)) if (File.Exists(filename))
{ {
FileStream stream = null;
try try
{ {
stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
BinaryFormatter bformatter = new BinaryFormatter(); {
BinaryFormatter bformatter = new BinaryFormatter();
asset = (AssetBase)bformatter.Deserialize(stream); asset = (AssetBase)bformatter.Deserialize(stream);
m_DiskHits++; m_DiskHits++;
}
} }
catch (System.Runtime.Serialization.SerializationException e) catch (System.Runtime.Serialization.SerializationException e)
{ {
@ -420,12 +412,6 @@ namespace OpenSim.Region.CoreModules.Asset
m_log.WarnFormat( m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
filename, id, e.Message, e.StackTrace); filename, id, e.Message, e.StackTrace);
}
finally
{
if (stream != null)
stream.Close();
} }
} }
@ -437,36 +423,19 @@ namespace OpenSim.Region.CoreModules.Asset
bool found = false; bool found = false;
string filename = GetFileName(id); string filename = GetFileName(id);
if (File.Exists(filename)) if (File.Exists(filename))
{ {
// actually check if we can open it, and so update expire
FileStream stream = null;
try try
{ {
stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
if (stream != null)
{ {
found = true; if (stream != null)
stream.Close(); found = true;
} }
}
catch (System.Runtime.Serialization.SerializationException e)
{
found = false;
m_log.ErrorFormat(
"[FLOTSAM ASSET CACHE]: Failed to check file {0} for asset {1}. Exception {2} {3}",
filename, id, e.Message, e.StackTrace);
// If there was a problem deserializing the asset, the asset may
// either be corrupted OR was serialized under an old format
// {different version of AssetBase} -- we should attempt to
// delete it and re-cache
File.Delete(filename);
} }
catch (Exception e) catch (Exception e)
{ {
found = false;
m_log.ErrorFormat( m_log.ErrorFormat(
"[FLOTSAM ASSET CACHE]: Failed to check file {0} for asset {1}. Exception {2} {3}", "[FLOTSAM ASSET CACHE]: Failed to check file {0} for asset {1}. Exception {2} {3}",
filename, id, e.Message, e.StackTrace); filename, id, e.Message, e.StackTrace);
@ -518,11 +487,6 @@ namespace OpenSim.Region.CoreModules.Asset
return Get(id); return Get(id);
} }
public AssetBase CheckCached(string id)
{
return Get(id);
}
public void Expire(string id) public void Expire(string id)
{ {
if (m_LogLevel >= 2) if (m_LogLevel >= 2)
@ -1067,11 +1031,6 @@ namespace OpenSim.Region.CoreModules.Asset
return asset.Data; return asset.Data;
} }
public bool CheckData(string id)
{
return Check(id); ;
}
public bool Get(string id, object sender, AssetRetrieved handler) public bool Get(string id, object sender, AssetRetrieved handler)
{ {
AssetBase asset = Get(id); AssetBase asset = Get(id);

View File

@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Asset
public bool Check(string id) public bool Check(string id)
{ {
return false; return m_Cache.Contains(id);
} }
public void Cache(AssetBase asset) public void Cache(AssetBase asset)

View File

@ -1433,7 +1433,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos) public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos)
{ {
version = String.Empty; version = String.Empty;
newpos = new Vector3(pos.X, pos.Y, pos.Z); newpos = pos;
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);

View File

@ -174,7 +174,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
#endregion #endregion
#region ISimulation #region ISimulationService
public IScene GetScene(UUID regionId) public IScene GetScene(UUID regionId)
{ {
@ -353,7 +353,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
return false; return false;
} }
#endregion /* IInterregionComms */ #endregion
#region Misc #region Misc

View File

@ -146,7 +146,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
#endregion #endregion
#region IInterregionComms #region ISimulationService
public IScene GetScene(UUID regionId) public IScene GetScene(UUID regionId)
{ {
@ -279,6 +279,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
return false; return false;
} }
#endregion /* IInterregionComms */ #endregion
} }
} }

View File

@ -47,13 +47,33 @@ namespace OpenSim.Region.Framework.Interfaces
/// The handle of the destination region. If it's the same as the region currently /// The handle of the destination region. If it's the same as the region currently
/// occupied by the agent then the teleport will be within that region. /// occupied by the agent then the teleport will be within that region.
/// </param> /// </param>
/// <param name='agent'></param>
/// <param name='regionHandle'></param>
/// <param name='position'></param> /// <param name='position'></param>
/// <param name='lookAt'></param> /// <param name='lookAt'></param>
/// <param name='teleportFlags'></param> /// <param name='teleportFlags'></param>
void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags); void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags);
/// <summary>
/// Teleports the agent for the given client to their home destination.
/// </summary>
/// <param name='id'></param>
/// <param name='client'></param>
bool TeleportHome(UUID id, IClientAPI client); bool TeleportHome(UUID id, IClientAPI client);
/// <summary>
/// Teleport an agent directly to a given region without checking whether the region should be substituted.
/// </summary>
/// <remarks>
/// Please use Teleport() instead unless you know exactly what you're doing.
/// Do not use for same region teleports.
/// </remarks>
/// <param name='sp'></param>
/// <param name='reg'></param>
/// <param name='finalDestination'>/param>
/// <param name='position'></param>
/// <param name='lookAt'></param>
/// <param name='teleportFlags'></param>
void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination,
Vector3 position, Vector3 lookAt, uint teleportFlags); Vector3 position, Vector3 lookAt, uint teleportFlags);

View File

@ -1,111 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.Framework.Interfaces
{
public delegate bool ChildAgentUpdateReceived(AgentData data);
public interface IInterregionCommsOut
{
#region Agents
bool SendCreateChildAgent(ulong regionHandle, AgentCircuitData aCircuit, uint teleportFlags, out string reason);
/// <summary>
/// Full child agent update.
/// </summary>
/// <param name="regionHandle"></param>
/// <param name="data"></param>
/// <returns></returns>
bool SendChildAgentUpdate(ulong regionHandle, AgentData data);
/// <summary>
/// Short child agent update, mostly for position.
/// </summary>
/// <param name="regionHandle"></param>
/// <param name="data"></param>
/// <returns></returns>
bool SendChildAgentUpdate(ulong regionHandle, AgentPosition data);
bool SendRetrieveRootAgent(ulong regionHandle, UUID id, out IAgentData agent);
/// <summary>
/// Message from receiving region to departing region, telling it got contacted by the client.
/// When sent over REST, it invokes the opaque uri.
/// </summary>
/// <param name="regionHandle"></param>
/// <param name="id"></param>
/// <param name="uri"></param>
/// <returns></returns>
bool SendReleaseAgent(ulong regionHandle, UUID id, string uri);
/// <summary>
/// Close agent.
/// </summary>
/// <param name="regionHandle"></param>
/// <param name="id"></param>
/// <returns></returns>
bool SendCloseAgent(ulong regionHandle, UUID id);
#endregion Agents
#region Objects
/// <summary>
/// Create an object in the destination region. This message is used primarily for prim crossing.
/// </summary>
/// <param name="regionHandle"></param>
/// <param name="sog"></param>
/// <param name="isLocalCall"></param>
/// <returns></returns>
bool SendCreateObject(ulong regionHandle, SceneObjectGroup sog, bool isLocalCall);
/// <summary>
/// Create an object from the user's inventory in the destination region.
/// This message is used primarily by clients.
/// </summary>
/// <param name="regionHandle"></param>
/// <param name="userID"></param>
/// <param name="itemID"></param>
/// <returns></returns>
bool SendCreateObject(ulong regionHandle, UUID userID, UUID itemID);
#endregion Objects
}
// This may not be needed, but having it here for now.
public interface IInterregionCommsIn
{
event ChildAgentUpdateReceived OnChildAgentUpdate;
}
}

View File

@ -4389,18 +4389,6 @@ namespace OpenSim.Region.Framework.Scenes
return sp; return sp;
} }
public virtual bool IncomingRetrieveRootAgent(UUID id, out IAgentData agent)
{
agent = null;
ScenePresence sp = GetScenePresence(id);
if ((sp != null) && (!sp.IsChildAgent))
{
sp.IsChildAgent = true;
return sp.CopyAgent(out agent);
}
return false;
}
/// <summary> /// <summary>
/// Authenticated close (via network) /// Authenticated close (via network)
/// </summary> /// </summary>

View File

@ -110,6 +110,16 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
/// <summary>
/// This exists to prevent race conditions between two CompleteMovement threads if the simulator is slow and
/// the viewer fires these in quick succession.
/// </summary>
/// <remarks>
/// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement
/// regulation done there.
/// </remarks>
private object m_completeMovementLock = new object();
// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@ -980,6 +990,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// Turns a child agent into a root agent. /// Turns a child agent into a root agent.
/// </summary> /// </summary>
/// <remarks>
/// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the /// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the
/// avatar is actual in the sim. They can perform all actions. /// avatar is actual in the sim. They can perform all actions.
/// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim, /// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim,
@ -987,48 +998,51 @@ namespace OpenSim.Region.Framework.Scenes
/// ///
/// This method is on the critical path for transferring an avatar from one region to another. Delay here /// This method is on the critical path for transferring an avatar from one region to another. Delay here
/// delays that crossing. /// delays that crossing.
/// </summary> /// </remarks>
private void MakeRootAgent(Vector3 pos, bool isFlying) private bool MakeRootAgent(Vector3 pos, bool isFlying)
{ {
// m_log.InfoFormat( lock (m_completeMovementLock)
// "[SCENE]: Upgrading child to root agent for {0} in {1}",
// Name, m_scene.RegionInfo.RegionName);
if (ParentUUID != UUID.Zero)
{ {
m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID); if (!IsChildAgent)
SceneObjectPart part = m_scene.GetSceneObjectPart(ParentUUID); return false;
if (part == null)
//m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
// m_log.InfoFormat(
// "[SCENE]: Upgrading child to root agent for {0} in {1}",
// Name, m_scene.RegionInfo.RegionName);
if (ParentUUID != UUID.Zero)
{ {
m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID); m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID);
SceneObjectPart part = m_scene.GetSceneObjectPart(ParentUUID);
if (part == null)
{
m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID);
}
else
{
part.ParentGroup.AddAvatar(UUID);
if (part.SitTargetPosition != Vector3.Zero)
part.SitTargetAvatar = UUID;
// ParentPosition = part.GetWorldPosition();
ParentID = part.LocalId;
ParentPart = part;
m_pos = PrevSitOffset;
// pos = ParentPosition;
pos = part.GetWorldPosition();
}
ParentUUID = UUID.Zero;
// Animator.TrySetMovementAnimation("SIT");
} }
else else
{ {
part.ParentGroup.AddAvatar(UUID); IsLoggingIn = false;
if (part.SitTargetPosition != Vector3.Zero)
part.SitTargetAvatar = UUID;
// ParentPosition = part.GetWorldPosition();
ParentID = part.LocalId;
ParentPart = part;
m_pos = PrevSitOffset;
// pos = ParentPosition;
pos = part.GetWorldPosition();
} }
ParentUUID = UUID.Zero;
IsChildAgent = false; IsChildAgent = false;
// Animator.TrySetMovementAnimation("SIT");
} }
else
{
IsChildAgent = false;
IsLoggingIn = false;
}
//m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
IsChildAgent = false;
// Must reset this here so that a teleport to a region next to an existing region does not keep the flag // Must reset this here so that a teleport to a region next to an existing region does not keep the flag
// set and prevent the close of the connection on a subsequent re-teleport. // set and prevent the close of the connection on a subsequent re-teleport.
@ -1216,6 +1230,7 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.EventManager.TriggerOnMakeRootAgent(this); m_scene.EventManager.TriggerOnMakeRootAgent(this);
return true;
} }
public int GetStateSource() public int GetStateSource()
@ -1639,7 +1654,14 @@ namespace OpenSim.Region.Framework.Scenes
} }
bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
MakeRootAgent(AbsolutePosition, flying); if (!MakeRootAgent(AbsolutePosition, flying))
{
m_log.DebugFormat(
"[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root",
Name, Scene.Name);
return;
}
// Tell the client that we're totally ready // Tell the client that we're totally ready
ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);

View File

@ -111,6 +111,45 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1)); Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1));
} }
/// <summary>
/// Test that duplicate complete movement calls are ignored.
/// </summary>
/// <remarks>
/// If duplicate calls are not ignored then there is a risk of race conditions or other unexpected effects.
/// </remarks>
[Test]
public void TestDupeCompleteMovementCalls()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID spUuid = TestHelpers.ParseTail(0x1);
TestScene scene = new SceneHelpers().SetupScene();
int makeRootAgentEvents = 0;
scene.EventManager.OnMakeRootAgent += spi => makeRootAgentEvents++;
ScenePresence sp = SceneHelpers.AddScenePresence(scene, spUuid);
Assert.That(makeRootAgentEvents, Is.EqualTo(1));
// Normally these would be invoked by a CompleteMovement message coming in to the UDP stack. But for
// convenience, here we will invoke it manually.
sp.CompleteMovement(sp.ControllingClient, true);
Assert.That(makeRootAgentEvents, Is.EqualTo(1));
// Check rest of exepcted parameters.
Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null);
Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
Assert.That(sp.IsChildAgent, Is.False);
Assert.That(sp.UUID, Is.EqualTo(spUuid));
Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1));
}
[Test] [Test]
public void TestCreateDuplicateRootScenePresence() public void TestCreateDuplicateRootScenePresence()
{ {
@ -249,58 +288,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// Assert.That(childPresence, Is.Not.Null); // Assert.That(childPresence, Is.Not.Null);
// Assert.That(childPresence.IsChildAgent, Is.True); // Assert.That(childPresence.IsChildAgent, Is.True);
} }
// /// <summary>
// /// Test adding a root agent to a scene. Doesn't yet actually complete crossing the agent into the scene.
// /// </summary>
// [Test]
// public void T010_TestAddRootAgent()
// {
// TestHelpers.InMethod();
//
// string firstName = "testfirstname";
//
// AgentCircuitData agent = new AgentCircuitData();
// agent.AgentID = agent1;
// agent.firstname = firstName;
// agent.lastname = "testlastname";
// agent.SessionID = UUID.Random();
// agent.SecureSessionID = UUID.Random();
// agent.circuitcode = 123;
// agent.BaseFolder = UUID.Zero;
// agent.InventoryFolder = UUID.Zero;
// agent.startpos = Vector3.Zero;
// agent.CapsPath = GetRandomCapsObjectPath();
// agent.ChildrenCapSeeds = new Dictionary<ulong, string>();
// agent.child = true;
//
// scene.PresenceService.LoginAgent(agent.AgentID.ToString(), agent.SessionID, agent.SecureSessionID);
//
// string reason;
// scene.NewUserConnection(agent, (uint)TeleportFlags.ViaLogin, out reason);
// testclient = new TestClient(agent, scene);
// scene.AddNewAgent(testclient);
//
// ScenePresence presence = scene.GetScenePresence(agent1);
//
// Assert.That(presence, Is.Not.Null, "presence is null");
// Assert.That(presence.Firstname, Is.EqualTo(firstName), "First name not same");
// acd1 = agent;
// }
//
// /// <summary>
// /// Test removing an uncrossed root agent from a scene.
// /// </summary>
// [Test]
// public void T011_TestRemoveRootAgent()
// {
// TestHelpers.InMethod();
//
// scene.RemoveClient(agent1);
//
// ScenePresence presence = scene.GetScenePresence(agent1);
//
// Assert.That(presence, Is.Null, "presence is not null");
// }
} }
} }

View File

@ -434,6 +434,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
} }
return wl; return wl;
} }
/// <summary> /// <summary>
/// Set the current Windlight scene /// Set the current Windlight scene
/// </summary> /// </summary>
@ -446,13 +447,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
LSShoutError("LightShare functions are not enabled."); LSShoutError("LightShare functions are not enabled.");
return 0; return 0;
} }
if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200)
if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID))
{ {
LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); ScenePresence sp = World.GetScenePresence(m_host.OwnerID);
return 0;
if (sp == null || sp.GodLevel < 200)
{
LSShoutError("lsSetWindlightScene can only be used by estate managers or owners.");
return 0;
}
} }
int success = 0; int success = 0;
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
if (LightShareModule.EnableWindlight) if (LightShareModule.EnableWindlight)
{ {
RegionLightShareData wl = getWindlightProfileFromRules(rules); RegionLightShareData wl = getWindlightProfileFromRules(rules);
@ -465,8 +474,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
LSShoutError("Windlight module is disabled"); LSShoutError("Windlight module is disabled");
return 0; return 0;
} }
return success; return success;
} }
public void lsClearWindlightScene() public void lsClearWindlightScene()
{ {
if (!m_LSFunctionsEnabled) if (!m_LSFunctionsEnabled)
@ -474,17 +485,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
LSShoutError("LightShare functions are not enabled."); LSShoutError("LightShare functions are not enabled.");
return; return;
} }
if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200)
if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID))
{ {
LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); ScenePresence sp = World.GetScenePresence(m_host.OwnerID);
return;
if (sp == null || sp.GodLevel < 200)
{
LSShoutError("lsSetWindlightScene can only be used by estate managers or owners.");
return;
}
} }
m_host.ParentGroup.Scene.RegionInfo.WindlightSettings.valid = false; m_host.ParentGroup.Scene.RegionInfo.WindlightSettings.valid = false;
if (m_host.ParentGroup.Scene.SimulationDataService != null) if (m_host.ParentGroup.Scene.SimulationDataService != null)
m_host.ParentGroup.Scene.SimulationDataService.RemoveRegionWindlightSettings(m_host.ParentGroup.Scene.RegionInfo.RegionID); m_host.ParentGroup.Scene.SimulationDataService.RemoveRegionWindlightSettings(m_host.ParentGroup.Scene.RegionInfo.RegionID);
m_host.ParentGroup.Scene.EventManager.TriggerOnSaveNewWindlightProfile(); m_host.ParentGroup.Scene.EventManager.TriggerOnSaveNewWindlightProfile();
} }
/// <summary> /// <summary>
/// Set the current Windlight scene to a target avatar /// Set the current Windlight scene to a target avatar
/// </summary> /// </summary>
@ -497,13 +516,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
LSShoutError("LightShare functions are not enabled."); LSShoutError("LightShare functions are not enabled.");
return 0; return 0;
} }
if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200)
if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID))
{ {
LSShoutError("lsSetWindlightSceneTargeted can only be used by estate managers or owners."); ScenePresence sp = World.GetScenePresence(m_host.OwnerID);
return 0;
if (sp == null || sp.GodLevel < 200)
{
LSShoutError("lsSetWindlightSceneTargeted can only be used by estate managers or owners.");
return 0;
}
} }
int success = 0; int success = 0;
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
if (LightShareModule.EnableWindlight) if (LightShareModule.EnableWindlight)
{ {
RegionLightShareData wl = getWindlightProfileFromRules(rules); RegionLightShareData wl = getWindlightProfileFromRules(rules);
@ -515,8 +542,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
LSShoutError("Windlight module is disabled"); LSShoutError("Windlight module is disabled");
return 0; return 0;
} }
return success; return success;
} }
} }
} }

View File

@ -35,7 +35,14 @@ namespace OpenSim.Services.Interfaces
public interface IOfflineIMService public interface IOfflineIMService
{ {
List<GridInstantMessage> GetMessages(UUID principalID); List<GridInstantMessage> GetMessages(UUID principalID);
bool StoreMessage(GridInstantMessage im, out string reason); bool StoreMessage(GridInstantMessage im, out string reason);
/// <summary>
/// Delete messages to or from this user (or group).
/// </summary>
/// <param name="userID">A user or group ID</param>
void DeleteMessages(UUID userID);
} }
public class OfflineIMDataUtils public class OfflineIMDataUtils