Merge branch 'master' into careminster

Conflicts:
	OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
	OpenSim/Region/Framework/Scenes/Scene.cs
avinationmerge
Melanie 2013-09-07 13:54:19 +01:00
commit 2f365ea80b
37 changed files with 732 additions and 119 deletions

View File

@ -623,10 +623,13 @@ namespace OpenSim.Groups
if (agent != null) if (agent != null)
break; break;
} }
if (agent == null) // oops if (agent != null)
return AgentID.ToString();
return Util.ProduceUserUniversalIdentifier(agent); return Util.ProduceUserUniversalIdentifier(agent);
// we don't know anything about this foreign user
// try asking the user management module, which may know more
return m_UserManagement.GetUserUUI(AgentID);
} }
private string AgentUUIForOutside(string AgentIDStr) private string AgentUUIForOutside(string AgentIDStr)

View File

@ -81,6 +81,7 @@ namespace OpenSim.Data
bool Delete(UUID regionID); bool Delete(UUID regionID);
List<RegionData> GetDefaultRegions(UUID scopeID); List<RegionData> GetDefaultRegions(UUID scopeID);
List<RegionData> GetDefaultHypergridRegions(UUID scopeID);
List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y); List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y);
List<RegionData> GetHyperlinks(UUID scopeID); List<RegionData> GetHyperlinks(UUID scopeID);
} }

View File

@ -315,6 +315,11 @@ namespace OpenSim.Data.MSSQL
return Get((int)RegionFlags.DefaultRegion, scopeID); return Get((int)RegionFlags.DefaultRegion, scopeID);
} }
public List<RegionData> GetDefaultHypergridRegions(UUID scopeID)
{
return Get((int)RegionFlags.DefaultHGRegion, scopeID);
}
public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y) public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID); List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@ -310,6 +310,11 @@ namespace OpenSim.Data.MySQL
return Get((int)RegionFlags.DefaultRegion, scopeID); return Get((int)RegionFlags.DefaultRegion, scopeID);
} }
public List<RegionData> GetDefaultHypergridRegions(UUID scopeID)
{
return Get((int)RegionFlags.DefaultHGRegion, scopeID);
}
public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y) public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID); List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@ -239,6 +239,11 @@ namespace OpenSim.Data.Null
return Get((int)RegionFlags.DefaultRegion, scopeID); return Get((int)RegionFlags.DefaultRegion, scopeID);
} }
public List<RegionData> GetDefaultHypergridRegions(UUID scopeID)
{
return Get((int)RegionFlags.DefaultHGRegion, scopeID);
}
public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y) public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID); List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@ -48,6 +48,7 @@ namespace OpenSim.Framework
NoMove = 64, // Don't allow moving this region NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation Reservation = 128, // This is an inactive reservation
Authenticate = 256, // Require authentication Authenticate = 256, // Require authentication
Hyperlink = 512 // Record represents a HG link Hyperlink = 512, // Record represents a HG link
DefaultHGRegion = 1024 // Record represents a default region for hypergrid teleports only.
} }
} }

View File

@ -130,7 +130,7 @@ namespace OpenSim.Framework
private static SmartThreadPool m_ThreadPool; private static SmartThreadPool m_ThreadPool;
// Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC.
private static readonly DateTime unixEpoch = public static readonly DateTime UnixEpoch =
DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime();
private static readonly string rawUUIDPattern private static readonly string rawUUIDPattern
@ -521,20 +521,18 @@ namespace OpenSim.Framework
public static int ToUnixTime(DateTime stamp) public static int ToUnixTime(DateTime stamp)
{ {
TimeSpan t = stamp.ToUniversalTime() - unixEpoch; TimeSpan t = stamp.ToUniversalTime() - UnixEpoch;
return (int) t.TotalSeconds; return (int)t.TotalSeconds;
} }
public static DateTime ToDateTime(ulong seconds) public static DateTime ToDateTime(ulong seconds)
{ {
DateTime epoch = unixEpoch; return UnixEpoch.AddSeconds(seconds);
return epoch.AddSeconds(seconds);
} }
public static DateTime ToDateTime(int seconds) public static DateTime ToDateTime(int seconds)
{ {
DateTime epoch = unixEpoch; return UnixEpoch.AddSeconds(seconds);
return epoch.AddSeconds(seconds);
} }
/// <summary> /// <summary>

View File

@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
} }
[Test] [Test]
public void AddForClient() public void TestAddForClient()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();
@ -88,7 +88,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
} }
[Test] [Test]
public void RemoveForClient() public void TestRemoveForClient()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();

View File

@ -372,9 +372,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type, UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type,
string message, ChatSourceType src, bool ignoreDistance) string message, ChatSourceType src, bool ignoreDistance)
{ {
// don't send chat to child agents if (presence.LifecycleState != ScenePresenceState.Running)
if (presence.IsChildAgent) return false; return false;
if (!ignoreDistance)
{
Vector3 fromRegionPos = fromPos + regionPos; Vector3 fromRegionPos = fromPos + regionPos;
Vector3 toRegionPos = presence.AbsolutePosition + Vector3 toRegionPos = presence.AbsolutePosition +
new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize, new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize,
@ -388,6 +390,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
{ {
return false; return false;
} }
}
// TODO: should change so the message is sent through the avatar rather than direct to the ClientView // TODO: should change so the message is sent through the avatar rather than direct to the ClientView
presence.ControllingClient.SendChatMessage( presence.ControllingClient.SendChatMessage(

View File

@ -1212,7 +1212,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
json.Add("jsonrpc", OSD.FromString("2.0")); json.Add("jsonrpc", OSD.FromString("2.0"));
json.Add("id", OSD.FromString(jsonId)); json.Add("id", OSD.FromString(jsonId));
json.Add("method", OSD.FromString(method)); json.Add("method", OSD.FromString(method));
// Experiment
json.Add("params", OSD.SerializeMembers(parameters)); json.Add("params", OSD.SerializeMembers(parameters));
string jsonRequestData = OSDParser.SerializeJsonString(json); string jsonRequestData = OSDParser.SerializeJsonString(json);
@ -1240,8 +1240,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
} }
Stream rstream = webResponse.GetResponseStream(); Stream rstream = webResponse.GetResponseStream();
if (rstream.Length < 1)
return false;
OSDMap mret = new OSDMap(); OSDMap mret = new OSDMap();
try try
@ -1318,8 +1316,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
} }
Stream rstream = webResponse.GetResponseStream(); Stream rstream = webResponse.GetResponseStream();
if (rstream.Length < 1)
return false;
OSDMap response = new OSDMap(); OSDMap response = new OSDMap();
try try

View File

@ -925,6 +925,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
{ {
if (!sp.Scene.IncomingPreCloseAgent(sp))
return;
// We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
// they regard the new region as the current region after receiving the AgentMovementComplete // they regard the new region as the current region after receiving the AgentMovementComplete
// response. If close is sent before then, it will cause the viewer to quit instead. // response. If close is sent before then, it will cause the viewer to quit instead.
@ -1087,6 +1090,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
{ {
if (!sp.Scene.IncomingPreCloseAgent(sp))
return;
// RED ALERT!!!! // RED ALERT!!!!
// PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
// THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
@ -1100,6 +1106,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// then this will be handled in IncomingCloseAgent under lock conditions // then this will be handled in IncomingCloseAgent under lock conditions
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name);
sp.Scene.IncomingCloseAgent(sp.UUID, false); sp.Scene.IncomingCloseAgent(sp.UUID, false);
} }
else else

View File

@ -481,14 +481,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
public string GetUserUUI(UUID userID) public string GetUserUUI(UUID userID)
{ {
UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, userID);
if (account != null)
return userID.ToString();
UserData ud; UserData ud;
lock (m_UserCache) lock (m_UserCache)
m_UserCache.TryGetValue(userID, out ud); m_UserCache.TryGetValue(userID, out ud);
if (ud == null) // It's not in the cache
{
string[] names = new string[2];
// This will pull the data from either UserAccounts or GridUser
// and stick it into the cache
TryGetUserNamesFromServices(userID, names);
lock (m_UserCache)
m_UserCache.TryGetValue(userID, out ud);
}
if (ud != null) if (ud != null)
{ {
string homeURL = ud.HomeURL; string homeURL = ud.HomeURL;

View File

@ -235,6 +235,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
return m_GridService.GetDefaultRegions(scopeID); return m_GridService.GetDefaultRegions(scopeID);
} }
public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
{
return m_GridService.GetDefaultHypergridRegions(scopeID);
}
public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
return m_GridService.GetFallbackRegions(scopeID, x, y); return m_GridService.GetFallbackRegions(scopeID, x, y);

View File

@ -277,6 +277,26 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
return rinfo; return rinfo;
} }
public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
{
List<GridRegion> rinfo = m_LocalGridService.GetDefaultHypergridRegions(scopeID);
//m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Local GetDefaultHypergridRegions {0} found {1} regions", name, rinfo.Count);
List<GridRegion> grinfo = m_RemoteGridService.GetDefaultHypergridRegions(scopeID);
if (grinfo != null)
{
//m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Remote GetDefaultHypergridRegions {0} found {1} regions", name, grinfo.Count);
foreach (GridRegion r in grinfo)
{
m_RegionInfoCache.Cache(r);
if (rinfo.Find(delegate(GridRegion gr) { return gr.RegionID == r.RegionID; }) == null)
rinfo.Add(r);
}
}
return rinfo;
}
public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
List<GridRegion> rinfo = m_LocalGridService.GetFallbackRegions(scopeID, x, y); List<GridRegion> rinfo = m_LocalGridService.GetFallbackRegions(scopeID, x, y);

View File

@ -3854,10 +3854,13 @@ namespace OpenSim.Region.Framework.Scenes
// We need to ensure that we are not already removing the scene presence before we ask it not to be // We need to ensure that we are not already removing the scene presence before we ask it not to be
// closed. // closed.
if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running) if (sp != null && sp.IsChildAgent
&& (sp.LifecycleState == ScenePresenceState.Running
|| sp.LifecycleState == ScenePresenceState.PreRemove))
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name); "[SCENE]: Reusing existing child scene presence for {0}, state {1} in {2}",
sp.Name, sp.LifecycleState, Name);
// In the case where, for example, an A B C D region layout, an avatar may // In the case where, for example, an A B C D region layout, an avatar may
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
@ -3879,6 +3882,8 @@ namespace OpenSim.Region.Framework.Scenes
// } // }
// else if (EntityTransferModule.IsInTransit(sp.UUID)) // else if (EntityTransferModule.IsInTransit(sp.UUID))
sp.LifecycleState = ScenePresenceState.Running;
if (EntityTransferModule.IsInTransit(sp.UUID)) if (EntityTransferModule.IsInTransit(sp.UUID))
{ {
sp.DoNotCloseAfterTeleport = true; sp.DoNotCloseAfterTeleport = true;
@ -4018,6 +4023,19 @@ namespace OpenSim.Region.Framework.Scenes
// uses down the line. // uses down the line.
sp.TeleportFlags = (TPFlags)teleportFlags; sp.TeleportFlags = (TPFlags)teleportFlags;
// We must carry out a further authorization check if there's an
// attempt to make a child agent into a root agent, since SeeIntoRegion may have allowed a child
// agent to login to a region where a full avatar would not be allowed.
//
// We determine whether this is a CreateAgent for a future non-child agent by inspecting
// TeleportFlags, which will be default for a child connection. This relies on input from the source
// region.
if (sp.TeleportFlags != TPFlags.Default)
{
if (!AuthorizeUser(acd, false, out reason))
return false;
}
if (sp.IsChildAgent) if (sp.IsChildAgent)
{ {
m_log.DebugFormat( m_log.DebugFormat(
@ -4526,10 +4544,10 @@ namespace OpenSim.Region.Framework.Scenes
ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
if (childAgentUpdate != null) if (childAgentUpdate != null)
{ {
if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID) // if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
// Only warn for now // // Only warn for now
m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?", // m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
childAgentUpdate.UUID, cAgentData.SessionID); // childAgentUpdate.UUID, cAgentData.SessionID);
// I can't imagine *yet* why we would get an update if the agent is a root agent.. // I can't imagine *yet* why we would get an update if the agent is a root agent..
// however to avoid a race condition crossing borders.. // however to avoid a race condition crossing borders..
@ -4630,6 +4648,50 @@ namespace OpenSim.Region.Framework.Scenes
return IncomingCloseAgent(agentID, true); return IncomingCloseAgent(agentID, true);
} }
/// <summary>
/// Tell a single agent to prepare to close.
/// </summary>
/// <remarks>
/// This should only be called if we may close the agent but there will be some delay in so doing. Meant for
/// internal use - other callers should almost certainly called IncomingCloseAgent().
/// </remarks>
/// <param name="sp"></param>
/// <returns>true if pre-close state notification was successful. false if the agent
/// was not in a state where it could transition to pre-close.</returns>
public bool IncomingPreCloseAgent(ScenePresence sp)
{
lock (m_removeClientLock)
{
// We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
// want to obey this close since C may have renewed the child agent lease on B.
if (sp.DoNotCloseAfterTeleport)
{
m_log.DebugFormat(
"[SCENE]: Not pre-closing {0} agent {1} in {2} since another simulator has re-established the child connection",
sp.IsChildAgent ? "child" : "root", sp.Name, Name);
// Need to reset the flag so that a subsequent close after another teleport can succeed.
sp.DoNotCloseAfterTeleport = false;
return false;
}
if (sp.LifecycleState != ScenePresenceState.Running)
{
m_log.DebugFormat(
"[SCENE]: Called IncomingPreCloseAgent() for {0} in {1} but presence is already in state {2}",
sp.Name, Name, sp.LifecycleState);
return false;
}
sp.LifecycleState = ScenePresenceState.PreRemove;
return true;
}
}
/// <summary> /// <summary>
/// Tell a single agent to disconnect from the region. /// Tell a single agent to disconnect from the region.
/// </summary> /// </summary>
@ -4649,16 +4711,16 @@ namespace OpenSim.Region.Framework.Scenes
if (sp == null) if (sp == null)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}", "[SCENE]: Called IncomingCloseAgent() with agent ID {0} but no such presence is in {1}",
agentID, Name); agentID, Name);
return false; return false;
} }
if (sp.LifecycleState != ScenePresenceState.Running) if (sp.LifecycleState != ScenePresenceState.Running && sp.LifecycleState != ScenePresenceState.PreRemove)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}", "[SCENE]: Called IncomingCloseAgent() for {0} in {1} but presence is already in state {2}",
sp.Name, Name, sp.LifecycleState); sp.Name, Name, sp.LifecycleState);
return false; return false;
@ -6025,7 +6087,7 @@ Environment.Exit(1);
{ {
if (!AuthorizeUser(aCircuit, false, out reason)) if (!AuthorizeUser(aCircuit, false, out reason))
{ {
// m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
return false; return false;
} }
} }

View File

@ -37,7 +37,8 @@ namespace OpenSim.Region.Framework.Scenes
/// This is a state machine. /// This is a state machine.
/// ///
/// [Entry] => Running /// [Entry] => Running
/// Running => Removing /// Running => PreRemove, Removing
/// PreRemove => Running, Removing
/// Removing => Removed /// Removing => Removed
/// ///
/// All other methods should only see the scene presence in running state - this is the normal operational state /// All other methods should only see the scene presence in running state - this is the normal operational state
@ -46,6 +47,7 @@ namespace OpenSim.Region.Framework.Scenes
public enum ScenePresenceState public enum ScenePresenceState
{ {
Running, // Normal operation state. The scene presence is available. Running, // Normal operation state. The scene presence is available.
PreRemove, // The presence is due to be removed but can still be returning to running.
Removing, // The presence is in the process of being removed from the scene via Scene.RemoveClient. Removing, // The presence is in the process of being removed from the scene via Scene.RemoveClient.
Removed, // The presence has been removed from the scene and is effectively dead. Removed, // The presence has been removed from the scene and is effectively dead.
// There is no exit from this state. // There is no exit from this state.
@ -80,8 +82,17 @@ namespace OpenSim.Region.Framework.Scenes
lock (this) lock (this)
{ {
if (newState == ScenePresenceState.Removing && m_state == ScenePresenceState.Running) if (newState == m_state)
return;
else if (newState == ScenePresenceState.Running && m_state == ScenePresenceState.PreRemove)
transitionOkay = true; transitionOkay = true;
else if (newState == ScenePresenceState.PreRemove && m_state == ScenePresenceState.Running)
transitionOkay = true;
else if (newState == ScenePresenceState.Removing)
{
if (m_state == ScenePresenceState.Running || m_state == ScenePresenceState.PreRemove)
transitionOkay = true;
}
else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing) else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing)
transitionOkay = true; transitionOkay = true;
} }

View File

@ -624,9 +624,16 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum(); int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
string childAgentStatus;
if (llClient.SceneAgent != null)
childAgentStatus = llClient.SceneAgent.IsChildAgent ? "N" : "Y";
else
childAgentStatus = "Off!";
m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
scene.RegionInfo.RegionName, llClient.Name, scene.RegionInfo.RegionName, llClient.Name,
llClient.SceneAgent.IsChildAgent ? "N" : "Y", childAgentStatus,
(DateTime.Now - cinfo.StartedTime).Minutes, (DateTime.Now - cinfo.StartedTime).Minutes,
avg_reqs, avg_reqs,
string.Format( string.Format(

View File

@ -106,6 +106,9 @@ namespace OpenSim.Server.Handlers.Grid
case "get_default_regions": case "get_default_regions":
return GetDefaultRegions(request); return GetDefaultRegions(request);
case "get_default_hypergrid_regions":
return GetDefaultHypergridRegions(request);
case "get_fallback_regions": case "get_fallback_regions":
return GetFallbackRegions(request); return GetFallbackRegions(request);
@ -444,6 +447,36 @@ namespace OpenSim.Server.Handlers.Grid
return Util.UTF8NoBomEncoding.GetBytes(xmlString); return Util.UTF8NoBomEncoding.GetBytes(xmlString);
} }
byte[] GetDefaultHypergridRegions(Dictionary<string, object> request)
{
//m_log.DebugFormat("[GRID HANDLER]: GetDefaultRegions");
UUID scopeID = UUID.Zero;
if (request.ContainsKey("SCOPEID"))
UUID.TryParse(request["SCOPEID"].ToString(), out scopeID);
else
m_log.WarnFormat("[GRID HANDLER]: no scopeID in request to get region range");
List<GridRegion> rinfos = m_GridService.GetDefaultHypergridRegions(scopeID);
Dictionary<string, object> result = new Dictionary<string, object>();
if ((rinfos == null) || ((rinfos != null) && (rinfos.Count == 0)))
result["result"] = "null";
else
{
int i = 0;
foreach (GridRegion rinfo in rinfos)
{
Dictionary<string, object> rinfoDict = rinfo.ToKeyValuePairs();
result["region" + i] = rinfoDict;
i++;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] GetFallbackRegions(Dictionary<string, object> request) byte[] GetFallbackRegions(Dictionary<string, object> request)
{ {
//m_log.DebugFormat("[GRID HANDLER]: GetRegionRange"); //m_log.DebugFormat("[GRID HANDLER]: GetRegionRange");

View File

@ -525,6 +525,57 @@ namespace OpenSim.Services.Connectors
return rinfos; return rinfos;
} }
public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["SCOPEID"] = scopeID.ToString();
sendData["METHOD"] = "get_default_hypergrid_regions";
List<GridRegion> rinfos = new List<GridRegion>();
string reply = string.Empty;
string uri = m_ServerURI + "/grid";
try
{
reply = SynchronousRestFormsRequester.MakeRequest("POST",
uri,
ServerUtils.BuildQueryString(sendData));
//m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply);
}
catch (Exception e)
{
m_log.DebugFormat("[GRID CONNECTOR]: Exception when contacting grid server at {0}: {1}", uri, e.Message);
return rinfos;
}
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
Dictionary<string, object>.ValueCollection rinfosList = replyData.Values;
foreach (object r in rinfosList)
{
if (r is Dictionary<string, object>)
{
GridRegion rinfo = new GridRegion((Dictionary<string, object>)r);
rinfos.Add(rinfo);
}
}
}
else
m_log.DebugFormat("[GRID CONNECTOR]: GetDefaultHypergridRegions {0} received null response",
scopeID);
}
else
m_log.DebugFormat("[GRID CONNECTOR]: GetDefaultHypergridRegions received null reply");
return rinfos;
}
public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
Dictionary<string, object> sendData = new Dictionary<string, object>(); Dictionary<string, object> sendData = new Dictionary<string, object>();

View File

@ -341,6 +341,12 @@ namespace OpenSim.Services.Connectors.SimianGrid
return new List<GridRegion>(0); return new List<GridRegion>(0);
} }
public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
{
// TODO: Allow specifying the default grid location
return GetDefaultRegions(scopeID);
}
public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true); GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true);

View File

@ -265,8 +265,9 @@ namespace OpenSim.Services.GridService
m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e); m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e);
} }
m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3}", m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3} with flags {4}",
regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY); regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY,
(OpenSim.Framework.RegionFlags)flags);
return String.Empty; return String.Empty;
} }
@ -478,6 +479,33 @@ namespace OpenSim.Services.GridService
return ret; return ret;
} }
public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
{
List<GridRegion> ret = new List<GridRegion>();
List<RegionData> regions = m_Database.GetDefaultHypergridRegions(scopeID);
foreach (RegionData r in regions)
{
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
ret.Add(RegionData2RegionInfo(r));
}
int hgDefaultRegionsFoundOnline = regions.Count;
// For now, hypergrid default regions will always be given precedence but we will also return simple default
// regions in case no specific hypergrid regions are specified.
ret.AddRange(GetDefaultRegions(scopeID));
int normalDefaultRegionsFoundOnline = ret.Count - hgDefaultRegionsFoundOnline;
m_log.DebugFormat(
"[GRID SERVICE]: GetDefaultHypergridRegions returning {0} hypergrid default and {1} normal default regions",
hgDefaultRegionsFoundOnline, normalDefaultRegionsFoundOnline);
return ret;
}
public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
List<GridRegion> ret = new List<GridRegion>(); List<GridRegion> ret = new List<GridRegion>();

View File

@ -79,7 +79,7 @@ namespace OpenSim.Services.GridService
{ {
if (m_DefaultRegion == null) if (m_DefaultRegion == null)
{ {
List<GridRegion> defs = m_GridService.GetDefaultRegions(m_ScopeID); List<GridRegion> defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID);
if (defs != null && defs.Count > 0) if (defs != null && defs.Count > 0)
m_DefaultRegion = defs[0]; m_DefaultRegion = defs[0];
else else

View File

@ -171,7 +171,7 @@ namespace OpenSim.Services.HypergridService
m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName); m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName);
if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty) if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty)
{ {
List<GridRegion> defs = m_GridService.GetDefaultRegions(m_ScopeID); List<GridRegion> defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID);
if (defs != null && defs.Count > 0) if (defs != null && defs.Count > 0)
{ {
region = defs[0]; region = defs[0];

View File

@ -97,6 +97,7 @@ namespace OpenSim.Services.Interfaces
List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax); List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax);
List<GridRegion> GetDefaultRegions(UUID scopeID); List<GridRegion> GetDefaultRegions(UUID scopeID);
List<GridRegion> GetDefaultHypergridRegions(UUID scopeID);
List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y); List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y);
List<GridRegion> GetHyperlinks(UUID scopeID); List<GridRegion> GetHyperlinks(UUID scopeID);

View File

@ -47,6 +47,44 @@ namespace OpenSim.Services.UserAccountService
public GridUserService(IConfigSource config) : base(config) public GridUserService(IConfigSource config) : base(config)
{ {
m_log.Debug("[GRID USER SERVICE]: Starting user grid service"); m_log.Debug("[GRID USER SERVICE]: Starting user grid service");
MainConsole.Instance.Commands.AddCommand(
"Users", false,
"show grid users online",
"show grid users online",
"Show number of grid users registered as online.",
"This number may not be accurate as a region may crash or not be cleanly shutdown and leave grid users shown as online\n."
+ "For this reason, users online for more than 5 days are not currently counted",
HandleShowGridUsersOnline);
}
protected void HandleShowGridUsersOnline(string module, string[] cmdparams)
{
// if (cmdparams.Length != 4)
// {
// MainConsole.Instance.Output("Usage: show grid users online");
// return;
// }
// int onlineCount;
int onlineRecentlyCount = 0;
DateTime now = DateTime.UtcNow;
foreach (GridUserData gu in m_Database.GetAll(""))
{
if (bool.Parse(gu.Data["Online"]))
{
// onlineCount++;
int unixLoginTime = int.Parse(gu.Data["Login"]);
if ((now - Util.ToDateTime(unixLoginTime)).Days < 5)
onlineRecentlyCount++;
}
}
MainConsole.Instance.OutputFormat("Users online: {0}", onlineRecentlyCount);
} }
public virtual GridUserInfo GetGridUserInfo(string userID) public virtual GridUserInfo GetGridUserInfo(string userID)

View File

@ -35,6 +35,11 @@ namespace pCampBot
{ {
public class AbstractBehaviour : IBehaviour public class AbstractBehaviour : IBehaviour
{ {
/// <summary>
/// Abbreviated name of this behaviour.
/// </summary>
public string AbbreviatedName { get; protected set; }
public string Name { get; protected set; } public string Name { get; protected set; }
public Bot Bot { get; protected set; } public Bot Bot { get; protected set; }
@ -45,5 +50,7 @@ namespace pCampBot
{ {
Bot = bot; Bot = bot;
} }
public virtual void Close() {}
} }
} }

View File

@ -47,7 +47,11 @@ namespace pCampBot
public const int m_regionCrossingTimeout = 1000 * 60; public const int m_regionCrossingTimeout = 1000 * 60;
public CrossBehaviour() { Name = "Cross"; } public CrossBehaviour()
{
AbbreviatedName = "c";
Name = "Cross";
}
public override void Action() public override void Action()
{ {

View File

@ -29,6 +29,7 @@ using OpenMetaverse;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using pCampBot.Interfaces; using pCampBot.Interfaces;
namespace pCampBot namespace pCampBot
@ -41,7 +42,11 @@ namespace pCampBot
/// </remarks> /// </remarks>
public class GrabbingBehaviour : AbstractBehaviour public class GrabbingBehaviour : AbstractBehaviour
{ {
public GrabbingBehaviour() { Name = "Grabbing"; } public GrabbingBehaviour()
{
AbbreviatedName = "g";
Name = "Grabbing";
}
public override void Action() public override void Action()
{ {
@ -56,6 +61,8 @@ namespace pCampBot
Bot.Client.Self.Grab(prim.LocalID); Bot.Client.Self.Grab(prim.LocalID);
Bot.Client.Self.GrabUpdate(prim.ID, Vector3.Zero); Bot.Client.Self.GrabUpdate(prim.ID, Vector3.Zero);
Bot.Client.Self.DeGrab(prim.LocalID); Bot.Client.Self.DeGrab(prim.LocalID);
Thread.Sleep(1000);
} }
} }
} }

View File

@ -38,6 +38,10 @@ namespace pCampBot
/// </summary> /// </summary>
public class NoneBehaviour : AbstractBehaviour public class NoneBehaviour : AbstractBehaviour
{ {
public NoneBehaviour() { Name = "None"; } public NoneBehaviour()
{
AbbreviatedName = "n";
Name = "None";
}
} }
} }

View File

@ -46,6 +46,7 @@ namespace pCampBot
public PhysicsBehaviour() public PhysicsBehaviour()
{ {
AbbreviatedName = "p";
Name = "Physics"; Name = "Physics";
talkarray = readexcuses(); talkarray = readexcuses();
} }
@ -77,6 +78,12 @@ namespace pCampBot
Bot.Client.Self.Chat(randomf, 0, ChatType.Normal); Bot.Client.Self.Chat(randomf, 0, ChatType.Normal);
} }
public override void Close()
{
if (Bot.ConnectionState == ConnectionState.Connected)
Bot.Client.Self.Jump(false);
}
private string[] readexcuses() private string[] readexcuses()
{ {
string allexcuses = ""; string allexcuses = "";

View File

@ -29,6 +29,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading;
using log4net; using log4net;
using OpenMetaverse; using OpenMetaverse;
using pCampBot.Interfaces; using pCampBot.Interfaces;
@ -42,7 +43,11 @@ namespace pCampBot
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public TeleportBehaviour() { Name = "Teleport"; } public TeleportBehaviour()
{
AbbreviatedName = "t";
Name = "Teleport";
}
public override void Action() public override void Action()
{ {
@ -70,6 +75,8 @@ namespace pCampBot
Bot.Name, sourceRegion.Name, Bot.Client.Self.SimPosition, destRegion.Name, destPosition); Bot.Name, sourceRegion.Name, Bot.Client.Self.SimPosition, destRegion.Name, destPosition);
Bot.Client.Self.Teleport(destRegion.RegionHandle, destPosition); Bot.Client.Self.Teleport(destRegion.RegionHandle, destPosition);
Thread.Sleep(Bot.Random.Next(3000, 10000));
} }
} }
} }

View File

@ -72,9 +72,10 @@ namespace pCampBot
/// Behaviours implemented by this bot. /// Behaviours implemented by this bot.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Lock this list before manipulating it. /// Indexed by abbreviated name. There can only be one instance of a particular behaviour.
/// Lock this structure before manipulating it.
/// </remarks> /// </remarks>
public List<IBehaviour> Behaviours { get; private set; } public Dictionary<string, IBehaviour> Behaviours { get; private set; }
/// <summary> /// <summary>
/// Objects that the bot has discovered. /// Objects that the bot has discovered.
@ -165,8 +166,6 @@ namespace pCampBot
{ {
ConnectionState = ConnectionState.Disconnected; ConnectionState = ConnectionState.Disconnected;
behaviours.ForEach(b => b.Initialize(this));
Random = new Random(Environment.TickCount);// We do stuff randomly here Random = new Random(Environment.TickCount);// We do stuff randomly here
FirstName = firstName; FirstName = firstName;
LastName = lastName; LastName = lastName;
@ -176,12 +175,53 @@ namespace pCampBot
StartLocation = startLocation; StartLocation = startLocation;
Manager = bm; Manager = bm;
Behaviours = behaviours;
Behaviours = new Dictionary<string, IBehaviour>();
foreach (IBehaviour behaviour in behaviours)
AddBehaviour(behaviour);
// Only calling for use as a template. // Only calling for use as a template.
CreateLibOmvClient(); CreateLibOmvClient();
} }
public bool TryGetBehaviour(string abbreviatedName, out IBehaviour behaviour)
{
lock (Behaviours)
return Behaviours.TryGetValue(abbreviatedName, out behaviour);
}
public bool AddBehaviour(IBehaviour behaviour)
{
lock (Behaviours)
{
if (!Behaviours.ContainsKey(behaviour.AbbreviatedName))
{
behaviour.Initialize(this);
Behaviours.Add(behaviour.AbbreviatedName, behaviour);
return true;
}
}
return false;
}
public bool RemoveBehaviour(string abbreviatedName)
{
lock (Behaviours)
{
IBehaviour behaviour;
if (!Behaviours.TryGetValue(abbreviatedName, out behaviour))
return false;
behaviour.Close();
Behaviours.Remove(abbreviatedName);
return true;
}
}
private void CreateLibOmvClient() private void CreateLibOmvClient()
{ {
GridClient newClient = new GridClient(); GridClient newClient = new GridClient();
@ -237,16 +277,25 @@ namespace pCampBot
private void Action() private void Action()
{ {
while (ConnectionState != ConnectionState.Disconnecting) while (ConnectionState != ConnectionState.Disconnecting)
lock (Behaviours)
Behaviours.ForEach(
b =>
{ {
Thread.Sleep(Random.Next(3000, 10000)); lock (Behaviours)
{
foreach (IBehaviour behaviour in Behaviours.Values)
{
// Thread.Sleep(Random.Next(3000, 10000));
// m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType());
b.Action(); behaviour.Action();
} }
); }
// XXX: This is a really shitty way of yielding so that behaviours can be added/removed
Thread.Sleep(100);
}
lock (Behaviours)
foreach (IBehaviour b in Behaviours.Values)
b.Close();
} }
/// <summary> /// <summary>

View File

@ -140,7 +140,7 @@ namespace pCampBot
/// <summary> /// <summary>
/// Behaviour switches for bots. /// Behaviour switches for bots.
/// </summary> /// </summary>
private HashSet<string> m_behaviourSwitches = new HashSet<string>(); private HashSet<string> m_defaultBehaviourSwitches = new HashSet<string>();
/// <summary> /// <summary>
/// Constructor Creates MainConsole.Instance to take commands and provide the place to write data /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data
@ -194,6 +194,20 @@ namespace pCampBot
+ "If no <n> is given, then all currently connected bots are disconnected.", + "If no <n> is given, then all currently connected bots are disconnected.",
HandleDisconnect); HandleDisconnect);
m_console.Commands.AddCommand(
"bot", false, "add behaviour", "add behaviour <abbreviated-name> [<bot-number>]",
"Add a behaviour to a bot",
"If no bot number is specified then behaviour is added to all bots.\n"
+ "Can be performed on connected or disconnected bots.",
HandleAddBehaviour);
m_console.Commands.AddCommand(
"bot", false, "remove behaviour", "remove behaviour <abbreviated-name> [<bot-number>]",
"Remove a behaviour from a bot",
"If no bot number is specified then behaviour is added to all bots.\n"
+ "Can be performed on connected or disconnected bots.",
HandleRemoveBehaviour);
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"bot", false, "sit", "sit", "Sit all bots on the ground.", "bot", false, "sit", "sit", "Sit all bots on the ground.",
HandleSit); HandleSit);
@ -212,7 +226,7 @@ namespace pCampBot
"bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus); "bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus);
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"bot", false, "show bot", "show bot <n>", "bot", false, "show bot", "show bot <bot-number>",
"Shows the detailed status and settings of a particular bot.", HandleShowBotStatus); "Shows the detailed status and settings of a particular bot.", HandleShowBotStatus);
m_bots = new List<Bot>(); m_bots = new List<Bot>();
@ -235,7 +249,7 @@ namespace pCampBot
m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last")); m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last"));
Array.ForEach<string>( Array.ForEach<string>(
startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_behaviourSwitches.Add(b)); startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_defaultBehaviourSwitches.Add(b));
for (int i = 0; i < botcount; i++) for (int i = 0; i < botcount; i++)
{ {
@ -243,28 +257,50 @@ namespace pCampBot
{ {
string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber); string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber);
CreateBot(
this,
CreateBehavioursFromAbbreviatedNames(m_defaultBehaviourSwitches),
m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting);
}
}
}
private List<IBehaviour> CreateBehavioursFromAbbreviatedNames(HashSet<string> abbreviatedNames)
{
// We must give each bot its own list of instantiated behaviours since they store state. // We must give each bot its own list of instantiated behaviours since they store state.
List<IBehaviour> behaviours = new List<IBehaviour>(); List<IBehaviour> behaviours = new List<IBehaviour>();
// Hard-coded for now // Hard-coded for now
if (m_behaviourSwitches.Contains("c")) foreach (string abName in abbreviatedNames)
behaviours.Add(new CrossBehaviour()); {
IBehaviour newBehaviour = null;
if (m_behaviourSwitches.Contains("g")) if (abName == "c")
behaviours.Add(new GrabbingBehaviour()); newBehaviour = new CrossBehaviour();
if (m_behaviourSwitches.Contains("n")) if (abName == "g")
behaviours.Add(new NoneBehaviour()); newBehaviour = new GrabbingBehaviour();
if (m_behaviourSwitches.Contains("p")) if (abName == "n")
behaviours.Add(new PhysicsBehaviour()); newBehaviour = new NoneBehaviour();
if (m_behaviourSwitches.Contains("t")) if (abName == "p")
behaviours.Add(new TeleportBehaviour()); newBehaviour = new PhysicsBehaviour();
CreateBot(this, behaviours, m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting); if (abName == "t")
newBehaviour = new TeleportBehaviour();
if (newBehaviour != null)
{
behaviours.Add(newBehaviour);
}
else
{
MainConsole.Instance.OutputFormat("No behaviour with abbreviated name {0} found", abName);
} }
} }
return behaviours;
} }
public void ConnectBots(int botcount) public void ConnectBots(int botcount)
@ -453,6 +489,118 @@ namespace pCampBot
} }
} }
private void HandleAddBehaviour(string module, string[] cmd)
{
if (cmd.Length < 3 || cmd.Length > 4)
{
MainConsole.Instance.OutputFormat("Usage: add behaviour <abbreviated-behaviour> [<bot-number>]");
return;
}
string rawBehaviours = cmd[2];
List<Bot> botsToEffect = new List<Bot>();
if (cmd.Length == 3)
{
lock (m_bots)
botsToEffect.AddRange(m_bots);
}
else
{
int botNumber;
if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber))
return;
Bot bot = GetBotFromNumber(botNumber);
if (bot == null)
{
MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
return;
}
botsToEffect.Add(bot);
}
HashSet<string> rawAbbreviatedSwitchesToAdd = new HashSet<string>();
Array.ForEach<string>(rawBehaviours.Split(new char[] { ',' }), b => rawAbbreviatedSwitchesToAdd.Add(b));
foreach (Bot bot in botsToEffect)
{
List<IBehaviour> behavioursAdded = new List<IBehaviour>();
foreach (IBehaviour behaviour in CreateBehavioursFromAbbreviatedNames(rawAbbreviatedSwitchesToAdd))
{
if (bot.AddBehaviour(behaviour))
behavioursAdded.Add(behaviour);
}
MainConsole.Instance.OutputFormat(
"Added behaviours {0} to bot {1}",
string.Join(", ", behavioursAdded.ConvertAll<string>(b => b.Name).ToArray()), bot.Name);
}
}
private void HandleRemoveBehaviour(string module, string[] cmd)
{
if (cmd.Length < 3 || cmd.Length > 4)
{
MainConsole.Instance.OutputFormat("Usage: remove behaviour <abbreviated-behaviour> [<bot-number>]");
return;
}
string rawBehaviours = cmd[2];
List<Bot> botsToEffect = new List<Bot>();
if (cmd.Length == 3)
{
lock (m_bots)
botsToEffect.AddRange(m_bots);
}
else
{
int botNumber;
if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber))
return;
Bot bot = GetBotFromNumber(botNumber);
if (bot == null)
{
MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
return;
}
botsToEffect.Add(bot);
}
HashSet<string> abbreviatedBehavioursToRemove = new HashSet<string>();
Array.ForEach<string>(rawBehaviours.Split(new char[] { ',' }), b => abbreviatedBehavioursToRemove.Add(b));
foreach (Bot bot in botsToEffect)
{
List<IBehaviour> behavioursRemoved = new List<IBehaviour>();
foreach (string b in abbreviatedBehavioursToRemove)
{
IBehaviour behaviour;
if (bot.TryGetBehaviour(b, out behaviour))
{
bot.RemoveBehaviour(b);
behavioursRemoved.Add(behaviour);
}
}
MainConsole.Instance.OutputFormat(
"Removed behaviours {0} to bot {1}",
string.Join(", ", behavioursRemoved.ConvertAll<string>(b => b.Name).ToArray()), bot.Name);
}
}
private void HandleDisconnect(string module, string[] cmd) private void HandleDisconnect(string module, string[] cmd)
{ {
lock (m_bots) lock (m_bots)
@ -572,10 +720,11 @@ namespace pCampBot
private void HandleShowBotsStatus(string module, string[] cmd) private void HandleShowBotsStatus(string module, string[] cmd)
{ {
ConsoleDisplayTable cdt = new ConsoleDisplayTable(); ConsoleDisplayTable cdt = new ConsoleDisplayTable();
cdt.AddColumn("Name", 30); cdt.AddColumn("Name", 24);
cdt.AddColumn("Region", 30); cdt.AddColumn("Region", 24);
cdt.AddColumn("Status", 14); cdt.AddColumn("Status", 13);
cdt.AddColumn("Connections", 11); cdt.AddColumn("Conns", 5);
cdt.AddColumn("Behaviours", 20);
Dictionary<ConnectionState, int> totals = new Dictionary<ConnectionState, int>(); Dictionary<ConnectionState, int> totals = new Dictionary<ConnectionState, int>();
foreach (object o in Enum.GetValues(typeof(ConnectionState))) foreach (object o in Enum.GetValues(typeof(ConnectionState)))
@ -583,13 +732,17 @@ namespace pCampBot
lock (m_bots) lock (m_bots)
{ {
foreach (Bot pb in m_bots) foreach (Bot bot in m_bots)
{ {
Simulator currentSim = pb.Client.Network.CurrentSim; Simulator currentSim = bot.Client.Network.CurrentSim;
totals[pb.ConnectionState]++; totals[bot.ConnectionState]++;
cdt.AddRow( cdt.AddRow(
pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState, pb.SimulatorsCount); bot.Name,
currentSim != null ? currentSim.Name : "(none)",
bot.ConnectionState,
bot.SimulatorsCount,
string.Join(",", bot.Behaviours.Keys.ToArray()));
} }
} }
@ -616,16 +769,11 @@ namespace pCampBot
if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber)) if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber))
return; return;
string name = string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber); Bot bot = GetBotFromNumber(botNumber);
Bot bot;
lock (m_bots)
bot = m_bots.Find(b => b.Name == name);
if (bot == null) if (bot == null)
{ {
MainConsole.Instance.Output("No bot found with name {0}", name); MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber);
return; return;
} }
@ -645,12 +793,39 @@ namespace pCampBot
MainConsole.Instance.Output("Settings"); MainConsole.Instance.Output("Settings");
ConsoleDisplayList statusCdl = new ConsoleDisplayList(); ConsoleDisplayList statusCdl = new ConsoleDisplayList();
statusCdl.AddRow(
"Behaviours",
string.Join(", ", bot.Behaviours.Values.ToList().ConvertAll<string>(b => b.Name).ToArray()));
GridClient botClient = bot.Client; GridClient botClient = bot.Client;
statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES); statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES);
MainConsole.Instance.Output(statusCdl.ToString()); MainConsole.Instance.Output(statusCdl.ToString());
} }
/// <summary>
/// Get a specific bot from its number.
/// </summary>
/// <returns>null if no bot was found</returns>
/// <param name='botNumber'></param>
private Bot GetBotFromNumber(int botNumber)
{
string name = GenerateBotNameFromNumber(botNumber);
Bot bot;
lock (m_bots)
bot = m_bots.Find(b => b.Name == name);
return bot;
}
private string GenerateBotNameFromNumber(int botNumber)
{
return string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber);
}
internal void Grid_GridRegion(object o, GridRegionEventArgs args) internal void Grid_GridRegion(object o, GridRegionEventArgs args)
{ {
lock (RegionsKnown) lock (RegionsKnown)

View File

@ -31,6 +31,11 @@ namespace pCampBot.Interfaces
{ {
public interface IBehaviour public interface IBehaviour
{ {
/// <summary>
/// Abbreviated name of this behaviour.
/// </summary>
string AbbreviatedName { get; }
/// <summary> /// <summary>
/// Name of this behaviour. /// Name of this behaviour.
/// </summary> /// </summary>
@ -45,6 +50,14 @@ namespace pCampBot.Interfaces
/// <param name="bot"></param> /// <param name="bot"></param>
void Initialize(Bot bot); void Initialize(Bot bot);
/// <summary>
/// Close down this behaviour.
/// </summary>
/// <remarks>
/// This is triggered if a behaviour is removed via explicit command and when a bot is disconnected
/// </remarks>
void Close();
/// <summary> /// <summary>
/// Action to take when this behaviour is invoked. /// Action to take when this behaviour is invoked.
/// </summary> /// </summary>

View File

@ -151,6 +151,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
; * ; *
[GridService] [GridService]
LocalServiceModule = "OpenSim.Services.GridService.dll:GridService" LocalServiceModule = "OpenSim.Services.GridService.dll:GridService"
HypergridLinker = true HypergridLinker = true
; Realm = "regions" ; Realm = "regions"
@ -168,8 +169,23 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
;; Next, we can specify properties of regions, including default and fallback regions ;; Next, we can specify properties of regions, including default and fallback regions
;; The syntax is: Region_<RegionName> = "<flags>" ;; The syntax is: Region_<RegionName> = "<flags>"
;; or: Region_<RegionID> = "<flags>" ;; or: Region_<RegionID> = "<flags>"
;; where <flags> can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut,Reservation,NoMove,Authenticate ;; where <flags> can be DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate
;; For example: ;;
;; DefaultRegion If a local login cannot be placed in the required region (e.g. home region does not exist, avatar is not allowed entry, etc.)
;; then this region becomes the destination. Only the first online default region will be used. If no DefaultHGRegion
;; is specified then this will also be used as the region for hypergrid connections that require it (commonly because they have not specified
;; an explicit region.
;;
;; DefaultHGRegion If an avatar connecting via the hypergrid does not specify a region, then they are placed here. Only the first online
;; region will be used.
;;
;; FallbackRegion If the DefaultRegion is not available for a local login, then any FallbackRegions are tried instead. These are tried in the
;; order specified. This only applies to local logins at this time, not Hypergrid connections.
;;
;; NoDirectLogin A hypergrid user cannot directly connect to this region. This does not apply to local logins.
;;
;; Persistent When the simulator is shutdown, the region is signalled as offline but left registered on the grid.
;;
; Region_Welcome_Area = "DefaultRegion, FallbackRegion" ; Region_Welcome_Area = "DefaultRegion, FallbackRegion"
; (replace spaces with underscore) ; (replace spaces with underscore)

View File

@ -132,8 +132,24 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto
;; Next, we can specify properties of regions, including default and fallback regions ;; Next, we can specify properties of regions, including default and fallback regions
;; The syntax is: Region_<RegionName> = "<flags>" ;; The syntax is: Region_<RegionName> = "<flags>"
;; or: Region_<RegionID> = "<flags>" ;; or: Region_<RegionID> = "<flags>"
;; where <flags> can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut,Reservation,NoMove,Authenticate ;; where <flags> can be DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate
;; For example: ;;
;; DefaultRegion If a local login cannot be placed in the required region (e.g. home region does not exist, avatar is not allowed entry, etc.)
;; then this region becomes the destination. Only the first online default region will be used. If no DefaultHGRegion
;; is specified then this will also be used as the region for hypergrid connections that require it (commonly because they have not specified
;; an explicit region.
;;
;; DefaultHGRegion If an avatar connecting via the hypergrid does not specify a region, then they are placed here. Only the first online
;; region will be used.
;;
;; FallbackRegion If the DefaultRegion is not available for a local login, then any FallbackRegions are tried instead. These are tried in the
;; order specified. This only applies to local logins at this time, not Hypergrid connections.
;;
;; NoDirectLogin A hypergrid user cannot directly connect to this region. This does not apply to local logins.
;;
;; Persistent When the simulator is shutdown, the region is signalled as offline but left registered on the grid.
;;
;; Example specification:
; Region_Welcome_Area = "DefaultRegion, FallbackRegion" ; Region_Welcome_Area = "DefaultRegion, FallbackRegion"
; (replace spaces with underscore) ; (replace spaces with underscore)

View File

@ -81,6 +81,22 @@
;; Next, we can specify properties of regions, including default and fallback regions ;; Next, we can specify properties of regions, including default and fallback regions
;; The syntax is: Region_<RegioName> = "<flags>" ;; The syntax is: Region_<RegioName> = "<flags>"
;; where <flags> can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut ;; where <flags> can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut
;;
;; DefaultRegion If a local login cannot be placed in the required region (e.g. home region does not exist, avatar is not allowed entry, etc.)
;; then this region becomes the destination. Only the first online default region will be used. If no DefaultHGRegion
;; is specified then this will also be used as the region for hypergrid connections that require it (commonly because they have not specified
;; an explicit region.
;;
;; DefaultHGRegion If an avatar connecting via the hypergrid does not specify a region, then they are placed here. Only the first online
;; region will be used.
;;
;; FallbackRegion If the DefaultRegion is not available for a local login, then any FallbackRegions are tried instead. These are tried in the
;; order specified. This only applies to local logins at this time, not Hypergrid connections.
;;
;; NoDirectLogin A hypergrid user cannot directly connect to this region. This does not apply to local logins.
;;
;; Persistent When the simulator is shutdown, the region is signalled as offline but left registered on the grid.
;;
;; For example: ;; For example:
Region_Welcome_Area = "DefaultRegion, FallbackRegion" Region_Welcome_Area = "DefaultRegion, FallbackRegion"