Merge branch 'master' into 0.8-post-fixes

0.8.0.3 0.8-rc1
Justin Clark-Casey 2014-05-06 19:57:31 +01:00
commit c38736de82
4 changed files with 285 additions and 86 deletions

View File

@ -402,6 +402,12 @@ namespace OpenSim
"Delete a region from disk", "Delete a region from disk",
RunCommand); RunCommand);
m_console.Commands.AddCommand("Estates", false, "estate create",
"estate create <owner UUID> <estate name>",
"Creates a new estate with the specified name, owned by the specified user."
+ " Estate name must be unique.",
CreateEstateCommand);
m_console.Commands.AddCommand("Estates", false, "estate set owner", m_console.Commands.AddCommand("Estates", false, "estate set owner",
"estate set owner <estate-id>[ <UUID> | <Firstname> <Lastname> ]", "estate set owner <estate-id>[ <UUID> | <Firstname> <Lastname> ]",
"Sets the owner of the specified estate to the specified UUID or user. ", "Sets the owner of the specified estate to the specified UUID or user. ",
@ -411,6 +417,11 @@ namespace OpenSim
"estate set name <estate-id> <new name>", "estate set name <estate-id> <new name>",
"Sets the name of the specified estate to the specified value. New name must be unique.", "Sets the name of the specified estate to the specified value. New name must be unique.",
SetEstateNameCommand); SetEstateNameCommand);
m_console.Commands.AddCommand("Estates", false, "estate link region",
"estate link region <estate ID> <region ID>",
"Attaches the specified region to the specified estate.",
EstateLinkRegionCommand);
} }
protected override void ShutdownSpecific() protected override void ShutdownSpecific()
@ -1177,6 +1188,58 @@ namespace OpenSim
SceneManager.SaveCurrentSceneToArchive(cmdparams); SceneManager.SaveCurrentSceneToArchive(cmdparams);
} }
protected void CreateEstateCommand(string module, string[] args)
{
string response = null;
UUID userID;
if (args.Length == 2)
{
response = "No user specified.";
}
else if (!UUID.TryParse(args[2], out userID))
{
response = String.Format("{0} is not a valid UUID", args[2]);
}
else if (args.Length == 3)
{
response = "No estate name specified.";
}
else
{
Scene scene = SceneManager.CurrentOrFirstScene;
// TODO: Is there a better choice here?
UUID scopeID = UUID.Zero;
UserAccount account = scene.UserAccountService.GetUserAccount(scopeID, userID);
if (account == null)
{
response = String.Format("Could not find user {0}", userID);
}
else
{
// concatenate it all to "name"
StringBuilder sb = new StringBuilder(args[3]);
for (int i = 4; i < args.Length; i++)
sb.Append (" " + args[i]);
string estateName = sb.ToString().Trim();
// send it off for processing.
IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
response = estateModule.CreateEstate(estateName, userID);
if (response == String.Empty)
{
List<int> estates = scene.EstateDataService.GetEstates(estateName);
response = String.Format("Estate {0} created as \"{1}\"", estates.ElementAt(0), estateName);
}
}
}
// give the user some feedback
if (response != null)
MainConsole.Instance.Output(response);
}
protected void SetEstateOwnerCommand(string module, string[] args) protected void SetEstateOwnerCommand(string module, string[] args)
{ {
string response = null; string response = null;
@ -1299,6 +1362,56 @@ namespace OpenSim
MainConsole.Instance.Output(response); MainConsole.Instance.Output(response);
} }
private void EstateLinkRegionCommand(string module, string[] args)
{
int estateId =-1;
UUID regionId = UUID.Zero;
Scene scene = null;
string response = null;
if (args.Length == 3)
{
response = "No estate specified.";
}
else if (!int.TryParse(args [3], out estateId))
{
response = String.Format("\"{0}\" is not a valid ID for an Estate", args [3]);
}
else if (args.Length == 4)
{
response = "No region specified.";
}
else if (!UUID.TryParse(args[4], out regionId))
{
response = String.Format("\"{0}\" is not a valid UUID for a Region", args [4]);
}
else if (!SceneManager.TryGetScene(regionId, out scene))
{
// region may exist, but on a different sim.
response = String.Format("No access to Region \"{0}\"", args [4]);
}
if (response != null)
{
MainConsole.Instance.Output(response);
return;
}
// send it off for processing.
IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
response = estateModule.SetRegionEstate(scene.RegionInfo, estateId);
if (response == String.Empty)
{
estateModule.TriggerRegionInfoChange();
estateModule.sendRegionHandshakeToAll();
response = String.Format ("Region {0} is now attached to estate {1}", regionId, estateId);
}
// give the user some feedback
if (response != null)
MainConsole.Instance.Output (response);
}
#endregion #endregion
private static string CombineParams(string[] commandParams, int pos) private static string CombineParams(string[] commandParams, int pos)

View File

@ -428,7 +428,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
/// <summary> /// <summary>
/// delegate for sending a grid instant message asynchronously /// delegate for sending a grid instant message asynchronously
/// </summary> /// </summary>
public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID);
protected virtual void GridInstantMessageCompleted(IAsyncResult iar) protected virtual void GridInstantMessageCompleted(IAsyncResult iar)
{ {
@ -442,118 +442,138 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
{ {
GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync;
d.BeginInvoke(im, result, GridInstantMessageCompleted, d); d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d);
} }
/// <summary> /// <summary>
/// Internal SendGridInstantMessage over XMLRPC method. /// Recursive SendGridInstantMessage over XMLRPC method.
/// This is called from within a dedicated thread. /// This is called from within a dedicated thread.
/// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from
/// itself, prevRegionHandle will be the last region handle that we tried to send.
/// If the handles are the same, we look up the user's location using the grid.
/// If the handles are still the same, we end. The send failed.
/// </summary> /// </summary>
private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result) /// <param name="prevRegionHandle">
/// Pass in 0 the first time this method is called. It will be called recursively with the last
/// regionhandle tried
/// </param>
protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID)
{ {
UUID toAgentID = new UUID(im.toAgentID); UUID toAgentID = new UUID(im.toAgentID);
UUID regionID;
bool lookupAgent;
/* PresenceInfo upd = null;
* Try to get what region the agent is in from the cache.
*/ bool lookupAgent = false;
lock (m_UserRegionMap) lock (m_UserRegionMap)
{ {
lookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID); if (m_UserRegionMap.ContainsKey(toAgentID))
}
while (true)
{
/*
* If not in cache, try to find out what region the agent is in.
* Also do this if we know the existing cache entry is bad.
*/
if (lookupAgent)
{ {
PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); upd = new PresenceInfo();
upd.RegionID = m_UserRegionMap[toAgentID];
regionID = UUID.Zero; // We need to compare the current regionhandle with the previous region handle
if (presences != null) // or the recursive loop will never end because it will never try to lookup the agent again
if (prevRegionID == upd.RegionID)
{ {
foreach (PresenceInfo p in presences) lookupAgent = true;
}
}
else
{
lookupAgent = true;
}
}
// Are we needing to look-up an agent?
if (lookupAgent)
{
// Non-cached user agent lookup.
PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
if (presences != null && presences.Length > 0)
{
foreach (PresenceInfo p in presences)
{
if (p.RegionID != UUID.Zero)
{ {
if (p.RegionID != UUID.Zero) upd = p;
{ break;
regionID = p.RegionID;
break;
}
} }
} }
// If not found, message is undeliverable
if (regionID == UUID.Zero)
{
break;
}
} }
/* if (upd != null)
* Try to find out about region.
* If unable, message is undeliverable.
*/
GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID);
if (reginfo == null)
{ {
m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID); // check if we've tried this before..
break; // This is one way to end the recursive loop
} //
if (upd.RegionID == prevRegionID)
/*
* Try to send message to agent in the region.
*/
Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
msgdata["region_handle"] = 0;
bool imresult = doIMSending(reginfo, msgdata);
/*
* If message delivery successful, save cache entry because we know it is good.
* Then tell caller message has been delivered and we are done.
*/
if (imresult)
{
lock (m_UserRegionMap)
{ {
m_UserRegionMap[toAgentID] = regionID; // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
HandleUndeliveredMessage(im, result);
return;
} }
result(true); }
else
{
// m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
HandleUndeliveredMessage(im, result);
return; return;
} }
/*
* Message delivery failed.
* If we just looked up what region the agent is in, message is undeliverable.
*/
if (lookupAgent)
{
break;
}
/*
* We used a cached entry that we now know is bad.
* Try again by searching the grid for the user.
*/
lookupAgent = true;
} }
/* if (upd != null)
* Message is undeliverable for one reason or another.
* Remove possible bad entry from cache.
* Then inform caller that the message is undeliverable.
*/
lock (m_UserRegionMap)
{ {
m_UserRegionMap.Remove(toAgentID); GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID,
} upd.RegionID);
if (reginfo != null)
{
Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
// Not actually used anymore, left in for compatibility
// Remove at next interface change
//
msgdata["region_handle"] = 0;
bool imresult = doIMSending(reginfo, msgdata);
if (imresult)
{
// IM delivery successful, so store the Agent's location in our local cache.
lock (m_UserRegionMap)
{
if (m_UserRegionMap.ContainsKey(toAgentID))
{
m_UserRegionMap[toAgentID] = upd.RegionID;
}
else
{
m_UserRegionMap.Add(toAgentID, upd.RegionID);
}
}
result(true);
}
else
{
// try again, but lookup user this time.
// Warning, this must call the Async version
// of this method or we'll be making thousands of threads
// The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
// The version that spawns the thread is SendGridInstantMessageViaXMLRPC
// m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); // This is recursive!!!!!
HandleUndeliveredMessage(im, result); SendGridInstantMessageViaXMLRPCAsync(im, result,
upd.RegionID);
}
}
else
{
m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID);
HandleUndeliveredMessage(im, result);
}
}
else
{
HandleUndeliveredMessage(im, result);
}
} }
/// <summary> /// <summary>

View File

@ -313,6 +313,69 @@ namespace OpenSim.Region.CoreModules.World.Estate
return response; return response;
} }
public string SetRegionEstate(RegionInfo regionInfo, int estateID)
{
string response;
if (regionInfo.EstateSettings.EstateID == estateID)
{
response = String.Format("\"{0}\" is already part of estate {1}", regionInfo.RegionName, estateID);
}
else
{
// get the current settings from DB
EstateSettings dbSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
if (dbSettings.EstateID == 0)
{
response = String.Format("No estate found with ID {0}", estateID);
}
else if (Scene.EstateDataService.LinkRegion(regionInfo.RegionID, estateID))
{
// make sure there's a log entry to document the change
m_log.InfoFormat("[ESTATE]: Region {0} ({1}) moved to Estate {2} ({3}).", regionInfo.RegionID, regionInfo.RegionName, estateID, dbSettings.EstateName);
// propagate the change
ChangeDelegate change = OnEstateInfoChange;
if (change != null)
change(regionInfo.RegionID);
response = String.Empty;
}
else
{
response = String.Format("Could not move \"{0}\" to estate {1}", regionInfo.RegionName, estateID);
}
}
return response;
}
public string CreateEstate(string estateName, UUID ownerID)
{
string response;
if (string.IsNullOrEmpty(estateName))
{
response = "No estate name specified.";
}
else
{
List<int> estates = Scene.EstateDataService.GetEstates(estateName);
if (estates.Count() > 0)
{
response = String.Format("An estate named \"{0}\" already exists.", estateName);
}
else
{
EstateSettings settings = Scene.EstateDataService.CreateNewEstate();
settings.EstateOwner = ownerID;
settings.EstateName = estateName;
settings.Save();
response = String.Empty;
}
}
return response;
}
#endregion #endregion
#region Packet Data Responders #region Packet Data Responders

View File

@ -26,6 +26,7 @@
*/ */
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
namespace OpenSim.Region.Framework.Interfaces namespace OpenSim.Region.Framework.Interfaces
@ -44,6 +45,8 @@ namespace OpenSim.Region.Framework.Interfaces
string SetEstateOwner(int estateID, UserAccount account); string SetEstateOwner(int estateID, UserAccount account);
string SetEstateName(int estateID, string newName); string SetEstateName(int estateID, string newName);
string SetRegionEstate(RegionInfo regionInfo, int estateID);
string CreateEstate(string estateName, UUID ownerID);
/// <summary> /// <summary>
/// Tell all clients about the current state of the region (terrain textures, water height, etc.). /// Tell all clients about the current state of the region (terrain textures, water height, etc.).