commit
c38736de82
|
@ -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)
|
||||||
|
|
|
@ -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))
|
||||||
|
{
|
||||||
|
upd = new PresenceInfo();
|
||||||
|
upd.RegionID = m_UserRegionMap[toAgentID];
|
||||||
|
|
||||||
|
// We need to compare the current regionhandle with the previous region handle
|
||||||
|
// or the recursive loop will never end because it will never try to lookup the agent again
|
||||||
|
if (prevRegionID == upd.RegionID)
|
||||||
|
{
|
||||||
|
lookupAgent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lookupAgent = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
// Are we needing to look-up an agent?
|
||||||
* 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)
|
if (lookupAgent)
|
||||||
{
|
{
|
||||||
|
// Non-cached user agent lookup.
|
||||||
PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
|
PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
|
||||||
|
if (presences != null && presences.Length > 0)
|
||||||
regionID = UUID.Zero;
|
|
||||||
if (presences != null)
|
|
||||||
{
|
{
|
||||||
foreach (PresenceInfo p in presences)
|
foreach (PresenceInfo p in presences)
|
||||||
{
|
{
|
||||||
if (p.RegionID != UUID.Zero)
|
if (p.RegionID != UUID.Zero)
|
||||||
{
|
{
|
||||||
regionID = p.RegionID;
|
upd = p;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found, message is undeliverable
|
if (upd != null)
|
||||||
if (regionID == UUID.Zero)
|
|
||||||
{
|
{
|
||||||
break;
|
// check if we've tried this before..
|
||||||
}
|
// This is one way to end the recursive loop
|
||||||
}
|
//
|
||||||
|
if (upd.RegionID == prevRegionID)
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
result(true);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
|
// m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
|
||||||
HandleUndeliveredMessage(im, result);
|
HandleUndeliveredMessage(im, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
|
||||||
|
HandleUndeliveredMessage(im, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upd != null)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|
||||||
|
// This is recursive!!!!!
|
||||||
|
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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.).
|
||||||
|
|
Loading…
Reference in New Issue