Compare commits

...

44 Commits

Author SHA1 Message Date
Robert Adams
0dd47d88de BulletSim: add physChangeLinkParams to set individual parameters on link constraints. Not fully functional. Remove double definition of ExtendedPhysics parameters by having BulletSim reference the optional module (addition to prebuild.xml and usings). 2013-09-20 21:02:34 +01:00
Robert Adams
34ae7afe1a BulletSim: update C++ HACD parameters to values that handle enclosed hollow spaces better. This shouldn't affect many since this HACD routine is off by default. 2013-09-20 21:02:24 +01:00
Robert Adams
826f8ce791 BulletSim: add physChangeLinkSpring to change linkset link to be a spring constraint. Add implementation to create spring constraint. Send up property updates for linkset children at the end of flexible linkset links. The simulator probably doesn't do the right thing yet. 2013-09-20 21:02:20 +01:00
Robert Adams
05ff4379f0 BulletSim: Linkset.Refresh() calls internal ScheduleRebuild() to recreate the linkset physics at next PostTaint time. Replace the existing calls to ScheduleRebuild to be calls to Refresh(). This allows external routines to make changes to parameters and then cause the linkset to rebuild. 2013-09-20 21:02:16 +01:00
Robert Adams
3ffad76b0d BulletSim: initial implementation of physChangeLinkFixed that resets a linkset's link back to a fixed, non-moving connection. 2013-09-20 21:02:12 +01:00
Robert Adams
1a8a6b95e5 BulletSim: move linkset extension operations into BSPrimLinkable where they should be. 2013-09-20 21:02:07 +01:00
Robert Adams
785171109e BulletSim: add unmanaged and XNA functions for hinge, slider and spring constraints. 2013-09-20 21:01:58 +01:00
Robert Adams
87aedc44a0 BulletSim: complete linkage of spring constraint into linkset constraint. 2013-09-20 21:01:53 +01:00
Robert Adams
ee86b460cb BulletSim: add spring constraint to linkset constraint types. 2013-09-20 21:01:49 +01:00
Robert Adams
0acde92af9 BulletSim: add API and calls for spring constraint parameters. 2013-09-20 21:01:44 +01:00
Robert Adams
719380380a BulletSim: fixes for change linkset implementation of physical linksets. 2013-09-20 21:01:24 +01:00
Robert Adams
a9dcdae6a2 Change collision logic in SceneObjectPart so land_collision will happen.
The previous logic would generate land_collision_start and land_collision_end
but would not generate the land_collision itself.
2013-09-20 21:01:11 +01:00
Diva Canto
e2b7d941b6 Restore group membership check for HG users in QueryAccess. 2013-09-05 07:48:10 -07:00
Justin Clark-Casey (justincc)
aa4479c4bc minor: add doc about DefaultHGRegion and some of the other GridService region settings (though not all as of yet) 2013-09-05 00:42:11 +01:00
Justin Clark-Casey (justincc)
8568503921 Stop "show client stats" from throwing an exception if somehow Scene.m_clientManager still retains a reference to a dead client.
Instead, "show client stats" now prints "Off!" so that exception is not thrown and we know which entries in ClientManager are in this state.
There's a race condition which could trigger this, but the window is extremely short and exceptions would not be thrown consistently (which is the behaviour observed).
It should otherwise be impossible for this condition to occur, so there may be a weakness in client manager IClientAPI removal.
2013-09-04 23:55:05 +01:00
Justin Clark-Casey (justincc)
6f1ff47fee In pCampbot PhysicsBehaviour.Close(), only cancel jumping if bot is connected 2013-09-04 00:48:23 +01:00
Justin Clark-Casey (justincc)
514c58bc96 Make pCampbot "add behaviour" and "remove behaviour" console commands work for all bots if no bot number is given 2013-09-04 00:48:19 +01:00
Justin Clark-Casey (justincc)
cfdb2700bc Consistently give responsibility for thread sleeping to behaviours rather than controlling from the main action loop
This is to avoid excessive and inconsistent delays between behaviours that currently need to embed sleeps in other actions (e.g. physics) and other behaviours.
Might need a more sophisticated approach in the long term.
2013-09-04 00:48:16 +01:00
Justin Clark-Casey (justincc)
cfef2b19bb Add Close() method to IBehaviour to allow behaviours to cleanup when removed or bot it disconnected.
In this case, it is used to turn off jump when physics testing behaviour is removed.
2013-09-04 00:48:10 +01:00
Justin Clark-Casey (justincc)
2a7b4c9db9 Add pCampbot "remove behaviour" console command for removing bot behaviours during operation.
Doesn't currently work very well as stopping physics, for instance, can leave bot travelling in old direction
2013-09-04 00:48:06 +01:00
Justin Clark-Casey (justincc)
7284cb76b6 Add ability to adjust pCampbot bot behaviours whilst running with "add behaviour <behaviour-name> <bot-number>" console commad 2013-09-04 00:47:59 +01:00
Justin Clark-Casey (justincc)
a4f7eb5b4d And fix break in "show bot" from commit 9c65207 2013-09-04 00:47:55 +01:00
Justin Clark-Casey (justincc)
1e64549acf Fix build break from last commit 9c65207. Mono 2.4 lacks string.join(string, List<string>), or some auto casting is missing 2013-09-04 00:47:51 +01:00
Justin Clark-Casey (justincc)
6570f5dcfe Show behaviours of pCampbot bots in "show bots" and "show bot" console commands 2013-09-04 00:47:34 +01:00
Justin Clark-Casey (justincc)
90907bf4fd minor simplification of some unix date functions in Util. No functional change. 2013-09-04 00:47:26 +01:00
Justin Clark-Casey (justincc)
dbbc260d1a Fix logic errors in "show grid users online" console command which didn't actually filter out users shown continuously online for more than 5 days
Remove confusion in command output.
2013-09-04 00:47:22 +01:00
Justin Clark-Casey (justincc)
49228f9855 Add experimental "show grid users online" console command to show grid users online from a standalone/robust instance.
This is not guaranteed to be accurate since users may be left "online" in certain situations.
For example, if a simulator crashes and they never login/logout again.
To counter this somewhat, only users continuously online for less than 5 days are shown.
2013-09-04 00:47:13 +01:00
Justin Clark-Casey (justincc)
8b7bcc8346 Allow one to specify a DefaultHGRegion flag in [GridService] in order to allow different default regions for HG and direct grid logins.
This requires a new GridService.GetDefaultHypergridRegions() so ROBUST services require updating but not simulators.
This method still returns regions flagged with just DefaultRegion after any DefaultHGRegions, so if no DefaultHGRegions are specified
then existing configured defaults will still work.
Immediate use is for conference where we need to be able to specify different defaults
However, this is also generally useful to send experienced HG users to one default location and local users whose specified region fails (e.g. no "home" or "last") to another.
2013-09-04 00:46:26 +01:00
Justin Clark-Casey (justincc)
3f8a99937e Fix exception thrown after a region has been restarted through scheduling.
This exception was very likely harmless since it occurred after the restart had taken place, but still misleading.
Thanks to SCGreyWolf for the code change suggestion in http://opensimulator.org/mantis/view.php?id=6747, though I did this in a slightly different way.
2013-09-04 00:45:32 +01:00
Diva Canto
b92128b715 Whitespace fubar. 2013-09-04 00:45:10 +01:00
Robert Adams
6eb1436c55 Fix a printing of exception error in InventoryArchiveModule that only
printed the error message and not the call stack.
2013-09-04 00:45:06 +01:00
Justin Clark-Casey (justincc)
41b33b6f0f Rename pCampbot.ini -> pCampBot.ini (and example file) to be consistent with other capitalizations of pCampBot 2013-09-04 00:45:00 +01:00
Justin Clark-Casey (justincc)
e05d11faa5 minor: shortern warning messages in EntityTransferModule when UpdateAgent() fails 2013-09-04 00:44:52 +01:00
Justin Clark-Casey (justincc)
803fa36b68 Make pCampbot "show bot" command take the bot number instead of the full bot name
Shorter and can do this because bot names are uniform
2013-09-04 00:44:47 +01:00
Justin Clark-Casey (justincc)
902c1f0009 remove redundant return at end of HandleDeregisterRegion() 2013-09-04 00:43:53 +01:00
Justin Clark-Casey (justincc)
b21f261008 Make it possible for the "deregister region id" command to accept more than one id 2013-09-04 00:43:48 +01:00
Justin Clark-Casey (justincc)
ab1c63b20c Remove old and unused ScenePresence.RestoreInCurrentScene() 2013-09-04 00:43:40 +01:00
Justin Clark-Casey (justincc)
5c35aa560e Refactor: merge SceneGraph.AddScenePresence() into CreateAndAddChildScenePresence() since the former was only ever called from the latter
This allows us to remove dead code relating to adding root agents directly to the scenegraph, which never happens.
2013-09-04 00:43:35 +01:00
Justin Clark-Casey (justincc)
63be8e3596 minor: Correct typo on "debug stats record start" message 2013-09-04 00:42:58 +01:00
Justin Clark-Casey (justincc)
62b12783df Fix bug where users teleporting to non-neighbour regions could continue to hear chat from their source region for some time after teleport completion.
This occurs on v2 teleport since the source region now waits 15 secs before closing the old child agent, which could still receive chat.
This commit introduces a ScenePresenceState.PreClose which is set before the wait, so that ChatModule can check for ScenePresenceState.Running.
This was theoretically also an issue on v1 teleport but since the pause before close was only 2 secs there, it was not noticed.
2013-09-02 19:21:53 +01:00
Justin Clark-Casey (justincc)
935888d6da Comment out warning about agent updating without valid session ID for now.
This causes extreme console spam if a simulator running latest master and one running 0.7.5 have adjacent regions occupied by avatars.
2013-09-02 17:47:04 +01:00
Justin Clark-Casey (justincc)
2e7f7c41a7 Also check user authorization if looking to upgrade from a child to a root agent.
Relevant if a child agent has been allowed into the region which should not be upgraded to a root agent.
2013-08-27 00:35:33 +01:00
Diva Canto
ed0ffae151 Potential fix for access control bug on login introduced with SeeIntoRegion commit. 2013-08-26 20:28:52 +01:00
Justin Clark-Casey (justincc)
ea5bab5107 For a Hypergrid user, delay estate access checks until NewUserConnection() so that they work.
This is necessary because the hypergrid groups checks (as referenced by estates) require an agent circuit to be present to construct the hypergrid ID.
However, this is not around until Scene.NewUserConnection(), as called by CreateAgent() in EntityTransferModule.
Therefore, if we're dealing with a hypergrid user, delay the check until NewUserConnection()/CreateAgent()
The entity transfer impact should be minimal since CreateAgent() is the next significant call after NewUserConnection()
However, to preserve the accuracy of query access we will only relax the check for HG users.
2013-08-26 20:04:07 +01:00
61 changed files with 1854 additions and 301 deletions

View File

@@ -623,10 +623,13 @@ namespace OpenSim.Groups
if (agent != null)
break;
}
if (agent == null) // oops
return AgentID.ToString();
if (agent != null)
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);
return Util.ProduceUserUniversalIdentifier(agent);
}
private string AgentUUIForOutside(string AgentIDStr)

View File

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

View File

@@ -315,6 +315,11 @@ namespace OpenSim.Data.MSSQL
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)
{
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@@ -310,6 +310,11 @@ namespace OpenSim.Data.MySQL
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)
{
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@@ -239,6 +239,11 @@ namespace OpenSim.Data.Null
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)
{
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@@ -67,7 +67,7 @@ namespace OpenSim.Framework.Monitoring
if (cmd[3] == "start")
{
Start();
con.OutputFormat("Now recording all stats very {0}ms to file", m_statsLogIntervalMs);
con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs);
}
else if (cmd[3] == "stop")
{

View File

@@ -48,6 +48,7 @@ namespace OpenSim.Framework
NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation
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;
// 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();
private static readonly string rawUUIDPattern
@@ -521,20 +521,18 @@ namespace OpenSim.Framework
public static int ToUnixTime(DateTime stamp)
{
TimeSpan t = stamp.ToUniversalTime() - unixEpoch;
return (int) t.TotalSeconds;
TimeSpan t = stamp.ToUniversalTime() - UnixEpoch;
return (int)t.TotalSeconds;
}
public static DateTime ToDateTime(ulong seconds)
{
DateTime epoch = unixEpoch;
return epoch.AddSeconds(seconds);
return UnixEpoch.AddSeconds(seconds);
}
public static DateTime ToDateTime(int seconds)
{
DateTime epoch = unixEpoch;
return epoch.AddSeconds(seconds);
return UnixEpoch.AddSeconds(seconds);
}
/// <summary>

View File

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

View File

@@ -326,15 +326,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type,
string message, ChatSourceType src, bool ignoreDistance)
{
Vector3 fromRegionPos = fromPos + regionPos;
Vector3 toRegionPos = presence.AbsolutePosition +
new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize,
presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);
if (presence.LifecycleState != ScenePresenceState.Running)
return false;
if (!ignoreDistance)
{
Vector3 fromRegionPos = fromPos + regionPos;
Vector3 toRegionPos = presence.AbsolutePosition +
new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize,
presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);
if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance ||
type == ChatTypeEnum.Say && dis > m_saydistance ||
type == ChatTypeEnum.Shout && dis > m_shoutdistance)

View File

@@ -536,7 +536,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
}
catch (Exception e)
{
m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e.Message);
m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e);
return null;
}
}

View File

@@ -832,8 +832,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
}
m_log.WarnFormat(
"[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.",
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
"[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
sp.Name, finalDestination.RegionName, sp.Scene.Name);
Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
return;
@@ -920,6 +920,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
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
// 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.
@@ -1053,8 +1056,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
}
m_log.WarnFormat(
"[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.",
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
"[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
sp.Name, finalDestination.RegionName, sp.Scene.Name);
Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
return;
@@ -1082,6 +1085,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
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
{
if (!sp.Scene.IncomingPreCloseAgent(sp))
return;
// RED ALERT!!!!
// PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
// THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
@@ -1095,6 +1101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// then this will be handled in IncomingCloseAgent under lock conditions
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name);
sp.Scene.IncomingCloseAgent(sp.UUID, false);
}
else

View File

@@ -481,14 +481,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
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;
lock (m_UserCache)
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)
{
string homeURL = ud.HomeURL;

View File

@@ -235,6 +235,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
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)
{
return m_GridService.GetFallbackRegions(scopeID, x, y);

View File

@@ -277,6 +277,26 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
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)
{
List<GridRegion> rinfo = m_LocalGridService.GetFallbackRegions(scopeID, x, y);

View File

@@ -46,8 +46,8 @@ namespace OpenSim.Region.CoreModules.World.Region
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")]
public class RestartModule : INonSharedRegionModule, IRestartModule
{
// private static readonly ILog m_log =
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected Scene m_Scene;
protected Timer m_CountdownTimer = null;
@@ -203,18 +203,30 @@ namespace OpenSim.Region.CoreModules.World.Region
public void SetTimer(int intervalSeconds)
{
m_CountdownTimer = new Timer();
m_CountdownTimer.AutoReset = false;
m_CountdownTimer.Interval = intervalSeconds * 1000;
m_CountdownTimer.Elapsed += OnTimer;
m_CountdownTimer.Start();
if (intervalSeconds > 0)
{
m_CountdownTimer = new Timer();
m_CountdownTimer.AutoReset = false;
m_CountdownTimer.Interval = intervalSeconds * 1000;
m_CountdownTimer.Elapsed += OnTimer;
m_CountdownTimer.Start();
}
else if (m_CountdownTimer != null)
{
m_CountdownTimer.Stop();
m_CountdownTimer = null;
}
else
{
m_log.WarnFormat(
"[RESTART MODULE]: Tried to set restart timer to {0} in {1}, which is not a valid interval",
intervalSeconds, m_Scene.Name);
}
}
private void OnTimer(object source, ElapsedEventArgs e)
{
int nextInterval = DoOneNotice();
SetTimer(nextInterval);
SetTimer(DoOneNotice());
}
public void AbortRestart(string message)

View File

@@ -3695,10 +3695,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
// 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(
"[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
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
@@ -3720,6 +3723,8 @@ namespace OpenSim.Region.Framework.Scenes
// }
// else if (EntityTransferModule.IsInTransit(sp.UUID))
sp.LifecycleState = ScenePresenceState.Running;
if (EntityTransferModule.IsInTransit(sp.UUID))
{
sp.DoNotCloseAfterTeleport = true;
@@ -3824,7 +3829,7 @@ namespace OpenSim.Region.Framework.Scenes
try
{
if (!AuthorizeUser(acd, SeeIntoRegion, out reason))
if (!AuthorizeUser(acd, (vialogin ? false : SeeIntoRegion), out reason))
{
m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
@@ -3855,6 +3860,19 @@ namespace OpenSim.Region.Framework.Scenes
// Let the SP know how we got here. This has a lot of interesting
// uses down the line.
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)
{
@@ -4346,10 +4364,10 @@ namespace OpenSim.Region.Framework.Scenes
ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
if (childAgentUpdate != null)
{
if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
// Only warn for now
m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
childAgentUpdate.UUID, cAgentData.SessionID);
// if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
// // Only warn for now
// m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
// childAgentUpdate.UUID, cAgentData.SessionID);
// 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..
@@ -4440,6 +4458,50 @@ namespace OpenSim.Region.Framework.Scenes
return false;
}
/// <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>
/// Tell a single agent to disconnect from the region.
/// </summary>
@@ -4459,16 +4521,16 @@ namespace OpenSim.Region.Framework.Scenes
if (sp == null)
{
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);
return false;
}
if (sp.LifecycleState != ScenePresenceState.Running)
if (sp.LifecycleState != ScenePresenceState.Running && sp.LifecycleState != ScenePresenceState.PreRemove)
{
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);
return false;
@@ -5741,7 +5803,7 @@ namespace OpenSim.Region.Framework.Scenes
{
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;
}
}

View File

@@ -561,39 +561,15 @@ namespace OpenSim.Region.Framework.Scenes
protected internal ScenePresence CreateAndAddChildScenePresence(
IClientAPI client, AvatarAppearance appearance, PresenceType type)
{
ScenePresence newAvatar = null;
// ScenePresence always defaults to child agent
newAvatar = new ScenePresence(client, m_parentScene, appearance, type);
AddScenePresence(newAvatar);
return newAvatar;
}
/// <summary>
/// Add a presence to the scene
/// </summary>
/// <param name="presence"></param>
protected internal void AddScenePresence(ScenePresence presence)
{
// Always a child when added to the scene
bool child = presence.IsChildAgent;
if (child)
{
m_numChildAgents++;
}
else
{
m_numRootAgents++;
presence.AddToPhysicalScene(false);
}
ScenePresence presence = new ScenePresence(client, m_parentScene, appearance, type);
Entities[presence.UUID] = presence;
lock (m_presenceLock)
{
m_numChildAgents++;
Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -604,7 +580,7 @@ namespace OpenSim.Region.Framework.Scenes
}
else
{
// Remember the old presene reference from the dictionary
// Remember the old presence reference from the dictionary
ScenePresence oldref = newmap[presence.UUID];
// Replace the presence reference in the dictionary with the new value
newmap[presence.UUID] = presence;
@@ -616,6 +592,8 @@ namespace OpenSim.Region.Framework.Scenes
m_scenePresenceMap = newmap;
m_scenePresenceArray = newlist;
}
return presence;
}
/// <summary>

View File

@@ -2464,12 +2464,9 @@ namespace OpenSim.Region.Framework.Scenes
SendCollisionEvent(scriptEvents.collision_end , endedColliders , ParentGroup.Scene.EventManager.TriggerScriptCollidingEnd);
if (startedColliders.Contains(0))
{
if (m_lastColliders.Contains(0))
SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding);
else
SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart);
}
SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart);
if (m_lastColliders.Contains(0))
SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding);
if (endedColliders.Contains(0))
SendLandCollisionEvent(scriptEvents.land_collision_end, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd);
}

View File

@@ -3243,11 +3243,6 @@ namespace OpenSim.Region.Framework.Scenes
}
}
public void RestoreInCurrentScene()
{
AddToPhysicalScene(false); // not exactly false
}
public void Reset()
{
// m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName);

View File

@@ -37,7 +37,8 @@ namespace OpenSim.Region.Framework.Scenes
/// This is a state machine.
///
/// [Entry] => Running
/// Running => Removing
/// Running => PreRemove, Removing
/// PreRemove => Running, Removing
/// Removing => Removed
///
/// 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
{
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.
Removed, // The presence has been removed from the scene and is effectively dead.
// There is no exit from this state.
@@ -80,8 +82,17 @@ namespace OpenSim.Region.Framework.Scenes
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;
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)
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();
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}",
scene.RegionInfo.RegionName, llClient.Name,
llClient.SceneAgent.IsChildAgent ? "N" : "Y",
childAgentStatus,
(DateTime.Now - cinfo.StartedTime).Minutes,
avg_reqs,
string.Format(

View File

@@ -29,12 +29,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using OpenSim.Framework;
using OpenSim.Region.CoreModules;
using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Physics.Manager;
using Mono.Addins;
using Nini.Config;
@@ -60,6 +62,9 @@ public class ExtendedPhysics : INonSharedRegionModule
// Per prim functions. See BSPrim.
public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed";
public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType";
public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams";
// =============================================================
@@ -195,10 +200,36 @@ public class ExtendedPhysics : INonSharedRegionModule
if (rootPart != null)
{
Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor;
PhysicsActor rootPhysActor = rootPart.PhysActor;
if (rootPhysActor != null)
{
ret = (int)rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType);
if (rootPhysActor.IsPhysical)
{
// Change a physical linkset by making non-physical, waiting for one heartbeat so all
// the prim and linkset state is updated, changing the type and making the
// linkset physical again.
containingGroup.ScriptSetPhysicsStatus(false);
Thread.Sleep(150); // longer than one heartbeat tick
// A kludge for the moment.
// Since compound linksets move the children but don't generate position updates to the
// simulator, it is possible for compound linkset children to have out-of-sync simulator
// and physical positions. The following causes the simulator to push the real child positions
// down into the physics engine to get everything synced.
containingGroup.UpdateGroupPosition(containingGroup.AbsolutePosition);
containingGroup.UpdateGroupRotationR(containingGroup.GroupRotation);
ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType));
Thread.Sleep(150); // longer than one heartbeat tick
containingGroup.ScriptSetPhysicsStatus(true);
}
else
{
// Non-physical linksets don't have a physical instantiation so there is no state to
// worry about being updated.
ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType));
}
}
else
{
@@ -223,7 +254,6 @@ public class ExtendedPhysics : INonSharedRegionModule
public int physGetLinksetType(UUID hostID, UUID scriptID)
{
int ret = -1;
if (!Enabled) return ret;
// The part that is requesting the change.
@@ -237,10 +267,10 @@ public class ExtendedPhysics : INonSharedRegionModule
if (rootPart != null)
{
Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor;
PhysicsActor rootPhysActor = rootPart.PhysActor;
if (rootPhysActor != null)
{
ret = (int)rootPhysActor.Extension(PhysFunctGetLinksetType);
ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType));
}
else
{
@@ -260,5 +290,226 @@ public class ExtendedPhysics : INonSharedRegionModule
}
return ret;
}
[ScriptConstant]
public static int PHYS_LINK_TYPE_FIXED = 1234;
[ScriptConstant]
public static int PHYS_LINK_TYPE_HINGE = 4;
[ScriptConstant]
public static int PHYS_LINK_TYPE_SPRING = 9;
[ScriptConstant]
public static int PHYS_LINK_TYPE_6DOF = 6;
[ScriptConstant]
public static int PHYS_LINK_TYPE_SLIDER = 7;
// physChangeLinkType(integer linkNum, integer typeCode)
[ScriptInvocation]
public int physChangeLinkType(UUID hostID, UUID scriptID, int linkNum, int typeCode)
{
int ret = -1;
if (!Enabled) return ret;
PhysicsActor rootPhysActor;
PhysicsActor childPhysActor;
if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
{
ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, childPhysActor, typeCode));
}
return ret;
}
// physChangeLinkFixed(integer linkNum)
// Change the link between the root and the linkNum into a fixed, static physical connection.
[ScriptInvocation]
public int physChangeLinkFixed(UUID hostID, UUID scriptID, int linkNum)
{
int ret = -1;
if (!Enabled) return ret;
PhysicsActor rootPhysActor;
PhysicsActor childPhysActor;
if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
{
ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, childPhysActor, PHYS_LINK_TYPE_FIXED));
}
return ret;
}
// Code for specifying params.
// The choice if 14400 is arbitrary and only serves to catch parameter code misuse.
public static int PHYS_PARAM_MIN = 14401;
[ScriptConstant]
public static int PHYS_PARAM_FRAMEINA_LOC = 14401;
[ScriptConstant]
public static int PHYS_PARAM_FRAMEINA_ROT = 14402;
[ScriptConstant]
public static int PHYS_PARAM_FRAMEINB_LOC = 14403;
[ScriptConstant]
public static int PHYS_PARAM_FRAMEINB_ROT = 14404;
[ScriptConstant]
public static int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405;
[ScriptConstant]
public static int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406;
[ScriptConstant]
public static int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407;
[ScriptConstant]
public static int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408;
[ScriptConstant]
public static int PHYS_PARAM_USE_FRAME_OFFSET = 14409;
[ScriptConstant]
public static int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410;
[ScriptConstant]
public static int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411;
[ScriptConstant]
public static int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412;
[ScriptConstant]
public static int PHYS_PARAM_CFM = 14413;
[ScriptConstant]
public static int PHYS_PARAM_ERP = 14414;
[ScriptConstant]
public static int PHYS_PARAM_SOLVER_ITERATIONS = 14415;
[ScriptConstant]
public static int PHYS_PARAM_SPRING_DAMPING = 14416;
[ScriptConstant]
public static int PHYS_PARAM_SPRING_STIFFNESS = 14417;
public static int PHYS_PARAM_MAX = 14417;
// physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...])
[ScriptInvocation]
public int physChangeLinkParams(UUID hostID, UUID scriptID, int linkNum, object[] parms)
{
int ret = -1;
if (!Enabled) return ret;
PhysicsActor rootPhysActor;
PhysicsActor childPhysActor;
if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
{
ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, childPhysActor, parms));
}
return ret;
}
private bool GetRootPhysActor(UUID hostID, out PhysicsActor rootPhysActor)
{
SceneObjectGroup containingGroup;
SceneObjectPart rootPart;
return GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor);
}
private bool GetRootPhysActor(UUID hostID, out SceneObjectGroup containingGroup, out SceneObjectPart rootPart, out PhysicsActor rootPhysActor)
{
bool ret = false;
rootPhysActor = null;
containingGroup = null;
rootPart = null;
SceneObjectPart requestingPart;
requestingPart = BaseScene.GetSceneObjectPart(hostID);
if (requestingPart != null)
{
// The type is is always on the root of a linkset.
containingGroup = requestingPart.ParentGroup;
if (containingGroup != null && !containingGroup.IsDeleted)
{
rootPart = containingGroup.RootPart;
if (rootPart != null)
{
rootPhysActor = rootPart.PhysActor;
if (rootPhysActor != null)
{
ret = true;
}
else
{
m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}",
LogHeader, rootPart.Name, hostID);
}
}
else
{
m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not exist. RequestingPartName={1}, hostID={2}",
LogHeader, requestingPart.Name, hostID);
}
}
else
{
m_log.WarnFormat("{0} GetRootAndChildPhysActors: Containing group missing or deleted. hostID={1}", LogHeader, hostID);
}
}
else
{
m_log.WarnFormat("{0} GetRootAndChildPhysActors: cannot find script object in scene. hostID={1}", LogHeader, hostID);
}
return ret;
}
// Find the root and child PhysActors based on the linkNum.
// Return 'true' if both are found and returned.
private bool GetRootAndChildPhysActors(UUID hostID, int linkNum, out PhysicsActor rootPhysActor, out PhysicsActor childPhysActor)
{
bool ret = false;
rootPhysActor = null;
childPhysActor = null;
SceneObjectGroup containingGroup;
SceneObjectPart rootPart;
if (GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor))
{
SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum);
if (linkPart != null)
{
childPhysActor = linkPart.PhysActor;
if (childPhysActor != null)
{
ret = true;
}
else
{
m_log.WarnFormat("{0} GetRootAndChildPhysActors: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}",
LogHeader, rootPart.Name, hostID, linkNum);
}
}
else
{
m_log.WarnFormat("{0} GetRootAndChildPhysActors: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}",
LogHeader, rootPart.Name, hostID, linkNum);
}
}
else
{
m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}",
LogHeader, rootPart.Name, hostID);
}
return ret;
}
// Extension() returns an object. Convert that object into the integer error we expect to return.
private int MakeIntError(object extensionRet)
{
int ret = -1;
if (extensionRet != null)
{
try
{
ret = (int)extensionRet;
}
catch
{
ret = -1;
}
}
return ret;
}
}
}

View File

@@ -596,6 +596,60 @@ public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, flo
return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
}
public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation);
}
public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse);
}
public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint);
}
public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss);
}
public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping);
}
public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val);
}
public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val);
}
public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse);
}
public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val);
}
public override bool CalculateTransforms(BulletConstraint constrain)
{
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
@@ -1600,6 +1654,33 @@ public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enabl
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CalculateTransforms2(IntPtr constrain);

View File

@@ -752,6 +752,214 @@ private sealed class BulletConstraintXNA : BulletConstraint
constraint.SetBreakingImpulseThreshold(threshold);
return true;
}
public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation)
{
HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint;
if (softness == HINGE_NOT_SPECIFIED)
constraint.SetLimit(low, high);
else
constraint.SetLimit(low, high, softness, bias, relaxation);
return true;
}
public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse)
{
Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true));
return true;
}
public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint)
{
Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
if (index == SPRING_NOT_SPECIFIED)
{
constraint.SetEquilibriumPoint();
}
else
{
if (equilibriumPoint == SPRING_NOT_SPECIFIED)
constraint.SetEquilibriumPoint(index);
else
constraint.SetEquilibriumPoint(index, equilibriumPoint);
}
return true;
}
public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness)
{
Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
constraint.SetStiffness(index, stiffness);
return true;
}
public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping)
{
Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
constraint.SetDamping(index, damping);
return true;
}
public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val)
{
SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
switch (lowerUpper)
{
case SLIDER_LOWER_LIMIT:
switch (linAng)
{
case SLIDER_LINEAR:
constraint.SetLowerLinLimit(val);
break;
case SLIDER_ANGULAR:
constraint.SetLowerAngLimit(val);
break;
}
break;
case SLIDER_UPPER_LIMIT:
switch (linAng)
{
case SLIDER_LINEAR:
constraint.SetUpperLinLimit(val);
break;
case SLIDER_ANGULAR:
constraint.SetUpperAngLimit(val);
break;
}
break;
}
return true;
}
public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val)
{
SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
switch (softRestDamp)
{
case SLIDER_SET_SOFTNESS:
switch (dirLimOrtho)
{
case SLIDER_SET_DIRECTION:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break;
case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break;
}
break;
case SLIDER_SET_LIMIT:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break;
case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break;
}
break;
case SLIDER_SET_ORTHO:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break;
case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break;
}
break;
}
break;
case SLIDER_SET_RESTITUTION:
switch (dirLimOrtho)
{
case SLIDER_SET_DIRECTION:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break;
case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break;
}
break;
case SLIDER_SET_LIMIT:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break;
case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break;
}
break;
case SLIDER_SET_ORTHO:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break;
case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break;
}
break;
}
break;
case SLIDER_SET_DAMPING:
switch (dirLimOrtho)
{
case SLIDER_SET_DIRECTION:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break;
case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break;
}
break;
case SLIDER_SET_LIMIT:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break;
case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break;
}
break;
case SLIDER_SET_ORTHO:
switch (linAng)
{
case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break;
case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break;
}
break;
}
break;
}
return true;
}
public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse)
{
SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
switch (linAng)
{
case SLIDER_LINEAR:
constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true);
break;
case SLIDER_ANGULAR:
constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true);
break;
}
return true;
}
public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val)
{
SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
switch (forceVel)
{
case SLIDER_MOTOR_VELOCITY:
switch (linAng)
{
case SLIDER_LINEAR:
constraint.SetTargetLinMotorVelocity(val);
break;
case SLIDER_ANGULAR:
constraint.SetTargetAngMotorVelocity(val);
break;
}
break;
case SLIDER_MAX_MOTOR_FORCE:
switch (linAng)
{
case SLIDER_LINEAR:
constraint.SetMaxLinMotorForce(val);
break;
case SLIDER_ANGULAR:
constraint.SetMaxAngMotorForce(val);
break;
}
break;
}
return true;
}
//BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
public override void SetAngularDamping(BulletBody pBody, float angularDamping)
{

View File

@@ -43,7 +43,9 @@ public enum ConstraintType : int
SLIDER_CONSTRAINT_TYPE,
CONTACT_CONSTRAINT_TYPE,
D6_SPRING_CONSTRAINT_TYPE,
MAX_CONSTRAINT_TYPE
MAX_CONSTRAINT_TYPE, // last type defined by Bullet
//
FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving
}
// ===============================================================================
@@ -441,6 +443,38 @@ public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float e
public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
public const int HINGE_NOT_SPECIFIED = -1;
public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation);
public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse);
public const int SPRING_NOT_SPECIFIED = -1;
public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint);
public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss);
public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping);
public const int SLIDER_LOWER_LIMIT = 0;
public const int SLIDER_UPPER_LIMIT = 1;
public const int SLIDER_LINEAR = 2;
public const int SLIDER_ANGULAR = 3;
public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val);
public const int SLIDER_SET_SOFTNESS = 4;
public const int SLIDER_SET_RESTITUTION = 5;
public const int SLIDER_SET_DAMPING = 6;
public const int SLIDER_SET_DIRECTION = 7;
public const int SLIDER_SET_LIMIT = 8;
public const int SLIDER_SET_ORTHO = 9;
public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse);
public const int SLIDER_MOTOR_VELOCITY = 10;
public const int SLIDER_MAX_MOTOR_FORCE = 11;
public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val);
public abstract bool CalculateTransforms(BulletConstraint constrain);
public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);

View File

@@ -32,12 +32,19 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public sealed class BSConstraint6Dof : BSConstraint
public class BSConstraint6Dof : BSConstraint
{
private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world)
{
m_body1 = obj1;
m_body2 = obj2;
m_enabled = false;
}
// Create a btGeneric6DofConstraint
public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
Vector3 frame1, Quaternion frame1rot,

View File

@@ -0,0 +1,54 @@
/*
* 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 copyrightD
* 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 System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public sealed class BSConstraintConeTwist : BSConstraint
{
public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } }
public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2,
Vector3 frameInAloc, Quaternion frameInArot,
Vector3 frameInBloc, Quaternion frameInBrot,
bool disableCollisionsBetweenLinkedBodies)
: base(world)
{
m_body1 = obj1;
m_body2 = obj2;
m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2,
frameInAloc, frameInArot, frameInBloc, frameInBrot,
disableCollisionsBetweenLinkedBodies);
m_enabled = true;
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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 copyrightD
* 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 System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public sealed class BSConstraintSlider : BSConstraint
{
public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } }
public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2,
Vector3 frameInAloc, Quaternion frameInArot,
Vector3 frameInBloc, Quaternion frameInBrot,
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
: base(world)
{
m_body1 = obj1;
m_body2 = obj2;
m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2,
frameInAloc, frameInArot, frameInBloc, frameInBrot,
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
m_enabled = true;
}
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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 copyrightD
* 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 System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public sealed class BSConstraintSpring : BSConstraint6Dof
{
public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } }
public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2,
Vector3 frame1Loc, Quaternion frame1Rot,
Vector3 frame2Loc, Quaternion frame2Rot,
bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
:base(world, obj1, obj2)
{
m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2,
frame1Loc, frame1Rot, frame2Loc, frame2Rot,
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
m_enabled = true;
world.physicsScene.DetailLog("{0},BSConstraintSpring,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
BSScene.DetailLogZero, world.worldID,
obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
}
public bool SetEnable(int index, bool axisEnable)
{
bool ret = false;
return ret;
}
public bool SetStiffness(int index, float stiffness)
{
bool ret = false;
return ret;
}
public bool SetDamping(int index, float damping)
{
bool ret = false;
return ret;
}
public bool SetEquilibriumPoint(int index, float eqPoint)
{
bool ret = false;
return ret;
}
}
}

View File

@@ -77,6 +77,10 @@ public abstract class BSLinkset
{
member = pMember;
}
public virtual void ResetLink() { }
public virtual void SetLinkParameters(BSConstraint constrain) { }
// Returns 'true' if physical property updates from the child should be reported to the simulator
public virtual bool ShouldUpdateChildProperties() { return false; }
}
public LinksetImplementation LinksetImpl { get; protected set; }
@@ -148,7 +152,7 @@ public abstract class BSLinkset
// Returns a new linkset for the child which is a linkset of one (just the
// orphened child).
// Called at runtime.
public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child)
public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
{
lock (m_linksetActivityLock)
{
@@ -157,7 +161,7 @@ public abstract class BSLinkset
// Cannot remove the root from a linkset.
return this;
}
RemoveChildFromLinkset(child);
RemoveChildFromLinkset(child, inTaintTime);
LinksetMass = ComputeLinksetMass();
}
@@ -222,6 +226,21 @@ public abstract class BSLinkset
return ret;
}
// Check the type of the link and return 'true' if the link is flexible and the
// updates from the child should be sent to the simulator so things change.
public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
{
bool ret = false;
BSLinkInfo linkInfo;
if (m_children.TryGetValue(child, out linkInfo))
{
ret = linkInfo.ShouldUpdateChildProperties();
}
return ret;
}
// Called after a simulation step to post a collision with this object.
// Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
// anything to add for the collision and it should be passed through normal processing.
@@ -255,7 +274,7 @@ public abstract class BSLinkset
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
protected abstract void RemoveChildFromLinkset(BSPrimLinkable child);
protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime);
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
@@ -430,6 +449,13 @@ public abstract class BSLinkset
return com;
}
#region Extension
public virtual object Extension(string pFunct, params object[] pParams)
{
return null;
}
#endregion // Extension
// Invoke the detailed logger and output something if it's enabled.
protected void DetailLog(string msg, params Object[] args)
{

View File

@@ -90,10 +90,9 @@ public sealed class BSLinksetCompound : BSLinkset
// its internal properties.
public override void Refresh(BSPrimLinkable requestor)
{
base.Refresh(requestor);
// Something changed so do the rebuilding thing
// ScheduleRebuild();
ScheduleRebuild(requestor);
base.Refresh(requestor);
}
// Schedule a refresh to happen after all the other taint processing.
@@ -127,7 +126,7 @@ public sealed class BSLinksetCompound : BSLinkset
if (IsRoot(child))
{
// The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
ScheduleRebuild(LinksetRoot);
Refresh(LinksetRoot);
}
return ret;
}
@@ -144,7 +143,7 @@ public sealed class BSLinksetCompound : BSLinkset
if (IsRoot(child))
{
// Schedule a rebuild to verify that the root shape is set to the real shape.
ScheduleRebuild(LinksetRoot);
Refresh(LinksetRoot);
}
return ret;
}
@@ -227,7 +226,7 @@ public sealed class BSLinksetCompound : BSLinkset
// there will already be a rebuild scheduled.
DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
updated.LocalID, whichUpdated);
ScheduleRebuild(updated);
Refresh(updated);
}
}
}
@@ -242,10 +241,10 @@ public sealed class BSLinksetCompound : BSLinkset
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
ScheduleRebuild(child);
Refresh(child);
return ret;
}
@@ -263,14 +262,14 @@ public sealed class BSLinksetCompound : BSLinkset
DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
// Rebuild the compound shape with the new child shape included
ScheduleRebuild(child);
Refresh(child);
}
return;
}
// Remove the specified child from the linkset.
// Safe to call even if the child is not really in the linkset.
protected override void RemoveChildFromLinkset(BSPrimLinkable child)
protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
{
child.ClearDisplacement();
@@ -282,17 +281,17 @@ public sealed class BSLinksetCompound : BSLinkset
child.LocalID, child.PhysBody.AddrString);
// Cause the child's body to be rebuilt and thus restored to normal operation
child.ForceBodyShapeRebuild(false);
child.ForceBodyShapeRebuild(inTaintTime);
if (!HasAnyChildren)
{
// The linkset is now empty. The root needs rebuilding.
LinksetRoot.ForceBodyShapeRebuild(false);
LinksetRoot.ForceBodyShapeRebuild(inTaintTime);
}
else
{
// Rebuild the compound shape with the child removed
ScheduleRebuild(LinksetRoot);
Refresh(LinksetRoot);
}
}
return;
@@ -318,10 +317,10 @@ public sealed class BSLinksetCompound : BSLinkset
// being destructed and going non-physical.
LinksetRoot.ForceBodyShapeRebuild(true);
// There is no reason to build all this physical stuff for a non-physical linkset.
if (!LinksetRoot.IsPhysicallyActive)
// There is no reason to build all this physical stuff for a non-physical or empty linkset.
if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
{
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
return; // Note the 'finally' clause at the botton which will get executed.
}

View File

@@ -28,6 +28,8 @@ using System;
using System.Collections.Generic;
using System.Text;
using OpenSim.Region.OptionalModules.Scripting;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
@@ -51,18 +53,27 @@ public sealed class BSLinksetConstraints : BSLinkset
public float cfm;
public float erp;
public float solverIterations;
//
public OMV.Vector3 frameInAloc;
public OMV.Quaternion frameInArot;
public OMV.Vector3 frameInBloc;
public OMV.Quaternion frameInBrot;
// Spring
public float springDamping;
public float springStiffness;
public BSLinkInfoConstraint(BSPrimLinkable pMember)
: base(pMember)
{
constraint = null;
ResetToFixedConstraint();
ResetLink();
}
// Set all the parameters for this constraint to a fixed, non-movable constraint.
public void ResetToFixedConstraint()
public override void ResetLink()
{
constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
// constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
constraintType = ConstraintType.FIXED_CONSTRAINT_TYPE;
linearLimitLow = OMV.Vector3.Zero;
linearLimitHigh = OMV.Vector3.Zero;
angularLimitLow = OMV.Vector3.Zero;
@@ -74,17 +85,25 @@ public sealed class BSLinksetConstraints : BSLinkset
cfm = BSParam.LinkConstraintCFM;
erp = BSParam.LinkConstraintERP;
solverIterations = BSParam.LinkConstraintSolverIterations;
frameInAloc = OMV.Vector3.Zero;
frameInArot = OMV.Quaternion.Identity;
frameInBloc = OMV.Vector3.Zero;
frameInBrot = OMV.Quaternion.Identity;
springDamping = -1f;
springStiffness = -1f;
}
// Given a constraint, apply the current constraint parameters to same.
public void SetConstraintParameters(BSConstraint constrain)
public override void SetLinkParameters(BSConstraint constrain)
{
switch (constraintType)
{
case ConstraintType.FIXED_CONSTRAINT_TYPE:
case ConstraintType.D6_CONSTRAINT_TYPE:
BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
if (constrain6dof != null)
{
// NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code.
// zero linear and angular limits makes the objects unable to move in relation to each other
constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
@@ -99,10 +118,49 @@ public sealed class BSLinksetConstraints : BSLinkset
}
}
break;
case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
BSConstraintSpring constrainSpring = constrain as BSConstraintSpring;
if (constrainSpring != null)
{
// zero linear and angular limits makes the objects unable to move in relation to each other
constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh);
constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh);
// tweek the constraint to increase stability
constrainSpring.UseFrameOffset(useFrameOffset);
constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
constrainSpring.SetCFMAndERP(cfm, erp);
if (solverIterations != 0f)
{
constrainSpring.SetSolverIterations(solverIterations);
}
for (int ii = 0; ii < 6; ii++)
{
if (springDamping != -1)
constrainSpring.SetDamping(ii, springDamping);
if (springStiffness != -1)
constrainSpring.SetStiffness(ii, springStiffness);
}
}
break;
default:
break;
}
}
// Return 'true' if the property updates from the physics engine should be reported
// to the simulator.
// If the constraint is fixed, we don't need to report as the simulator and viewer will
// report the right things.
public override bool ShouldUpdateChildProperties()
{
bool ret = true;
if (constraintType == ConstraintType.FIXED_CONSTRAINT_TYPE)
ret = false;
return ret;
}
}
public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
@@ -116,6 +174,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// refresh will happen once after all the other taints are applied.
public override void Refresh(BSPrimLinkable requestor)
{
ScheduleRebuild(requestor);
base.Refresh(requestor);
}
@@ -152,7 +211,7 @@ public sealed class BSLinksetConstraints : BSLinkset
if (IsRoot(child))
{
// The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
ScheduleRebuild(LinksetRoot);
Refresh(LinksetRoot);
}
return ret;
}
@@ -171,7 +230,7 @@ public sealed class BSLinksetConstraints : BSLinkset
if (IsRoot(child))
{
// Schedule a rebuild to verify that the root shape is set to the real shape.
ScheduleRebuild(LinksetRoot);
Refresh(LinksetRoot);
}
return ret;
}
@@ -199,7 +258,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// Just undo all the constraints for this linkset. Rebuild at the end of the step.
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
// Cause the constraints, et al to be rebuilt before the next simulation step.
ScheduleRebuild(LinksetRoot);
Refresh(LinksetRoot);
}
return ret;
}
@@ -217,14 +276,14 @@ public sealed class BSLinksetConstraints : BSLinkset
DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
// Cause constraints and assorted properties to be recomputed before the next simulation step.
ScheduleRebuild(LinksetRoot);
Refresh(LinksetRoot);
}
return;
}
// Remove the specified child from the linkset.
// Safe to call even if the child is not really in my linkset.
protected override void RemoveChildFromLinkset(BSPrimLinkable child)
protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
{
if (m_children.Remove(child))
{
@@ -236,12 +295,12 @@ public sealed class BSLinksetConstraints : BSLinkset
rootx.LocalID, rootx.PhysBody.AddrString,
childx.LocalID, childx.PhysBody.AddrString);
m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
m_physicsScene.TaintedObject(inTaintTime, "BSLinksetConstraints.RemoveChildFromLinkset", delegate()
{
PhysicallyUnlinkAChildFromRoot(rootx, childx);
});
// See that the linkset parameters are recomputed at the end of the taint time.
ScheduleRebuild(LinksetRoot);
Refresh(LinksetRoot);
}
else
{
@@ -262,8 +321,8 @@ public sealed class BSLinksetConstraints : BSLinkset
// Create a static constraint between the two passed objects
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
{
BSLinkInfoConstraint liConstraint = li as BSLinkInfoConstraint;
if (liConstraint == null)
BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint;
if (linkInfo == null)
return null;
// Zero motion for children so they don't interpolate
@@ -271,27 +330,26 @@ public sealed class BSLinksetConstraints : BSLinkset
BSConstraint constrain = null;
switch (liConstraint.constraintType)
switch (linkInfo.constraintType)
{
case ConstraintType.FIXED_CONSTRAINT_TYPE:
case ConstraintType.D6_CONSTRAINT_TYPE:
// Relative position normalized to the root prim
// Essentually a vector pointing from center of rootPrim to center of li.member
OMV.Vector3 childRelativePosition = liConstraint.member.Position - rootPrim.Position;
OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position;
// real world coordinate of midpoint between the two objects
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.PhysBody.AddrString,
liConstraint.member.LocalID, liConstraint.member.PhysBody.AddrString,
rootPrim.Position, liConstraint.member.Position, midPoint);
DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={7}",
rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody,
rootPrim.Position, linkInfo.member.Position, midPoint);
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
constrain = new BSConstraint6Dof(
m_physicsScene.World, rootPrim.PhysBody, liConstraint.member.PhysBody, midPoint, true, true );
m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true );
/* NOTE: below is an attempt to build constraint with full frame computation, etc.
* Using the midpoint is easier since it lets the Bullet code manipulate the transforms
@@ -319,12 +377,24 @@ public sealed class BSLinksetConstraints : BSLinkset
// ==================================================================================
*/
break;
case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody,
linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot,
true /*useLinearReferenceFrameA*/,
true /*disableCollisionsBetweenLinkedBodies*/);
DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.PhysBody.AddrString,
linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString,
rootPrim.Position, linkInfo.member.Position);
break;
default:
break;
}
liConstraint.SetConstraintParameters(constrain);
linkInfo.SetLinkParameters(constrain);
m_physicsScene.Constraints.AddConstraint(constrain);
@@ -382,9 +452,9 @@ public sealed class BSLinksetConstraints : BSLinkset
Rebuilding = true;
// There is no reason to build all this physical stuff for a non-physical linkset.
if (!LinksetRoot.IsPhysicallyActive)
if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
{
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
return; // Note the 'finally' clause at the botton which will get executed.
}
@@ -401,6 +471,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// If constraint doesn't exist yet, create it.
constrain = BuildConstraint(LinksetRoot, li);
}
li.SetLinkParameters(constrain);
constrain.RecomputeConstraintVariables(linksetMass);
// PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
@@ -412,5 +483,61 @@ public sealed class BSLinksetConstraints : BSLinkset
Rebuilding = false;
}
}
#region Extension
public override object Extension(string pFunct, params object[] pParams)
{
object ret = null;
switch (pFunct)
{
// pParams = (int linkNUm, PhysActor linkChild)
case ExtendedPhysics.PhysFunctChangeLinkType:
if (pParams.Length > 1)
{
int requestedType = (int)pParams[1];
if (requestedType == (int)ConstraintType.FIXED_CONSTRAINT_TYPE
|| requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE
|| requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE
|| requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE
|| requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE
|| requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE)
{
BSPrimLinkable child = pParams[0] as BSPrimLinkable;
if (child != null)
{
m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkFixed", delegate()
{
// Pick up all the constraints currently created.
RemoveDependencies(child);
BSLinkInfo linkInfo = null;
if (m_children.TryGetValue(child, out linkInfo))
{
BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
if (linkInfoC != null)
{
// Setting to fixed is easy. The reset state is the fixed link configuration.
linkInfoC.ResetLink();
linkInfoC.constraintType = (ConstraintType)requestedType;
ret = (object)true;
}
}
// Cause the whole linkset to be rebuilt in post-taint time.
Refresh(child);
});
}
}
}
break;
case ExtendedPhysics.PhysFunctChangeLinkParams:
break;
default:
ret = base.Extension(pFunct, pParams);
break;
}
return ret;
}
#endregion // Extension
}
}

View File

@@ -683,21 +683,21 @@ public static class BSParam
0f ),
new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull",
100f ),
200f ),
new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh",
2f ),
10f ),
new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls",
0.1f ),
20f ),
new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull",
0f ),
0.1f ),
new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be",
100f ),
10f ),
new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors",
false ),
true ),
new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls",
false ),
true ),
new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces",
false ),
true ),
new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
false ),

View File

@@ -41,7 +41,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
[Serializable]
public class BSPrim : BSPhysObject
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS PRIM]";
// _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
@@ -1555,36 +1555,6 @@ public class BSPrim : BSPhysObject
object ret = null;
switch (pFunct)
{
case BSScene.PhysFunctGetLinksetType:
{
BSPrimLinkable myHandle = this as BSPrimLinkable;
if (myHandle != null)
{
ret = (object)myHandle.LinksetType;
}
m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret);
break;
}
case BSScene.PhysFunctSetLinksetType:
{
if (pParams.Length > 0)
{
BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0];
BSPrimLinkable myHandle = this as BSPrimLinkable;
if (myHandle != null && myHandle.Linkset.IsRoot(myHandle))
{
PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate()
{
// Cause the linkset type to change
m_log.DebugFormat("{0} Extension.physSetLinksetType, oldType={1}, newType={2}",
LogHeader, myHandle.Linkset.LinksetImpl, linksetType);
myHandle.ConvertLinkset(linksetType);
});
}
ret = (object)(int)linksetType;
}
break;
}
default:
ret = base.Extension(pFunct, pParams);
break;

View File

@@ -30,6 +30,7 @@ using System.Linq;
using System.Text;
using OpenSim.Framework;
using OpenSim.Region.OptionalModules.Scripting;
using OMV = OpenMetaverse;
@@ -41,6 +42,8 @@ public class BSPrimLinkable : BSPrimDisplaced
// operations necessary for keeping the linkset created and, additionally, this
// calls the linkset implementation for its creation and management.
private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]";
// This adds the overrides for link() and delink() so the prim is linkable.
public BSLinkset Linkset { get; set; }
@@ -58,15 +61,12 @@ public class BSPrimLinkable : BSPrimDisplaced
Linkset = BSLinkset.Factory(PhysScene, this);
PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate()
{
Linkset.Refresh(this);
});
Linkset.Refresh(this);
}
public override void Destroy()
{
Linkset = Linkset.RemoveMeFromLinkset(this);
Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */);
base.Destroy();
}
@@ -80,7 +80,7 @@ public class BSPrimLinkable : BSPrimDisplaced
Linkset = parent.Linkset.AddMeToLinkset(this);
DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
}
return;
@@ -94,9 +94,9 @@ public class BSPrimLinkable : BSPrimDisplaced
BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
int childrenBefore = Linkset.NumberOfChildren; // DEBUG
Linkset = Linkset.RemoveMeFromLinkset(this);
Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/);
DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
return;
}
@@ -108,7 +108,7 @@ public class BSPrimLinkable : BSPrimDisplaced
set
{
base.Position = value;
PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate()
PhysScene.TaintedObject("BSPrimLinkable.setPosition", delegate()
{
Linkset.UpdateProperties(UpdatedProperties.Position, this);
});
@@ -122,7 +122,7 @@ public class BSPrimLinkable : BSPrimDisplaced
set
{
base.Orientation = value;
PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate()
PhysScene.TaintedObject("BSPrimLinkable.setOrientation", delegate()
{
Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
});
@@ -180,7 +180,7 @@ public class BSPrimLinkable : BSPrimDisplaced
// Do any filtering/modification needed for linksets.
public override void UpdateProperties(EntityProperties entprop)
{
if (Linkset.IsRoot(this))
if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this))
{
// Properties are only updated for the roots of a linkset.
// TODO: this will have to change when linksets are articulated.
@@ -240,6 +240,8 @@ public class BSPrimLinkable : BSPrimDisplaced
bool ret = false;
if (LinksetType != newType)
{
DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType);
// Set the implementation type first so the call to BSLinkset.Factory gets the new type.
this.LinksetType = newType;
@@ -263,7 +265,10 @@ public class BSPrimLinkable : BSPrimDisplaced
// Remove the children from the old linkset and add to the new (will be a new instance from the factory)
foreach (BSPrimLinkable child in children)
{
oldLinkset.RemoveMeFromLinkset(child);
oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/);
}
foreach (BSPrimLinkable child in children)
{
newLinkset.AddMeToLinkset(child);
child.Linkset = newLinkset;
}
@@ -274,5 +279,60 @@ public class BSPrimLinkable : BSPrimDisplaced
}
return ret;
}
#region Extension
public override object Extension(string pFunct, params object[] pParams)
{
object ret = null;
switch (pFunct)
{
// physGetLinksetType();
case ExtendedPhysics.PhysFunctGetLinksetType:
{
ret = (object)LinksetType;
m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret);
break;
}
// physSetLinksetType(type);
case ExtendedPhysics.PhysFunctSetLinksetType:
{
if (pParams.Length > 0)
{
BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0];
if (Linkset.IsRoot(this))
{
PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate()
{
// Cause the linkset type to change
m_log.DebugFormat("{0} Extension.physSetLinksetType, oldType={1}, newType={2}",
LogHeader, Linkset.LinksetImpl, linksetType);
ConvertLinkset(linksetType);
});
}
ret = (object)(int)linksetType;
}
break;
}
// physChangeLinkType(linknum, typeCode);
// Params: PhysActor linkedPrim, int typeCode
case ExtendedPhysics.PhysFunctChangeLinkType:
{
Linkset.Extension(pFunct, pParams);
break;
}
// physChangeLinkParams(linknum, [code, value, code, value, ...]);
// Params: PhysActor linkedPrim, object[] params
case ExtendedPhysics.PhysFunctChangeLinkParams:
{
Linkset.Extension(pFunct, pParams);
break;
}
default:
ret = base.Extension(pFunct, pParams);
break;
}
return ret;
}
#endregion // Extension
}
}

View File

@@ -867,16 +867,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public override bool IsThreaded { get { return false; } }
#region Extensions
// =============================================================
// Per scene functions. See below.
// Per avatar functions. See BSCharacter.
// Per prim functions. See BSPrim.
public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
// =============================================================
public override object Extension(string pFunct, params object[] pParams)
{
return base.Extension(pFunct, pParams);

View File

@@ -106,6 +106,9 @@ namespace OpenSim.Server.Handlers.Grid
case "get_default_regions":
return GetDefaultRegions(request);
case "get_default_hypergrid_regions":
return GetDefaultHypergridRegions(request);
case "get_fallback_regions":
return GetFallbackRegions(request);
@@ -444,6 +447,36 @@ namespace OpenSim.Server.Handlers.Grid
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)
{
//m_log.DebugFormat("[GRID HANDLER]: GetRegionRange");

View File

@@ -515,6 +515,57 @@ namespace OpenSim.Services.Connectors
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)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();

View File

@@ -330,6 +330,12 @@ namespace OpenSim.Services.Connectors.SimianGrid
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)
{
GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true);

View File

@@ -86,7 +86,7 @@ namespace OpenSim.Services.GridService
{
MainConsole.Instance.Commands.AddCommand("Regions", true,
"deregister region id",
"deregister region id <Region UUID>",
"deregister region id <region-id>+",
"Deregister a region manually.",
String.Empty,
HandleDeregisterRegion);
@@ -265,8 +265,9 @@ namespace OpenSim.Services.GridService
m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e);
}
m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3}",
regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY);
m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3} with flags {4}",
regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY,
(OpenSim.Framework.RegionFlags)flags);
return String.Empty;
}
@@ -478,6 +479,33 @@ namespace OpenSim.Services.GridService
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)
{
List<GridRegion> ret = new List<GridRegion>();
@@ -526,40 +554,41 @@ namespace OpenSim.Services.GridService
private void HandleDeregisterRegion(string module, string[] cmd)
{
if (cmd.Length != 4)
if (cmd.Length < 4)
{
MainConsole.Instance.Output("Syntax: degregister region id <Region UUID>");
MainConsole.Instance.Output("Usage: degregister region id <region-id>+");
return;
}
string rawRegionUuid = cmd[3];
UUID regionUuid;
if (!UUID.TryParse(rawRegionUuid, out regionUuid))
for (int i = 3; i < cmd.Length; i++)
{
MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid);
return;
}
string rawRegionUuid = cmd[i];
UUID regionUuid;
GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid);
if (!UUID.TryParse(rawRegionUuid, out regionUuid))
{
MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid);
return;
}
if (region == null)
{
MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid);
return;
}
GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid);
if (DeregisterRegion(regionUuid))
{
MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid);
}
else
{
// I don't think this can ever occur if we know that the region exists.
MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid);
}
if (region == null)
{
MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid);
return;
}
return;
if (DeregisterRegion(regionUuid))
{
MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid);
}
else
{
// I don't think this can ever occur if we know that the region exists.
MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid);
}
}
}
private void HandleShowRegions(string module, string[] cmd)

View File

@@ -79,7 +79,7 @@ namespace OpenSim.Services.GridService
{
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)
m_DefaultRegion = defs[0];
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);
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)
{
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> GetDefaultRegions(UUID scopeID);
List<GridRegion> GetDefaultHypergridRegions(UUID scopeID);
List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y);
List<GridRegion> GetHyperlinks(UUID scopeID);

View File

@@ -47,6 +47,44 @@ namespace OpenSim.Services.UserAccountService
public GridUserService(IConfigSource config) : base(config)
{
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)

View File

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

View File

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

View File

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

View File

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

View File

@@ -46,6 +46,7 @@ namespace pCampBot
public PhysicsBehaviour()
{
AbbreviatedName = "p";
Name = "Physics";
talkarray = readexcuses();
}
@@ -77,6 +78,12 @@ namespace pCampBot
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()
{
string allexcuses = "";

View File

@@ -29,6 +29,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using log4net;
using OpenMetaverse;
using pCampBot.Interfaces;
@@ -42,7 +43,11 @@ namespace pCampBot
{
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()
{
@@ -70,6 +75,8 @@ namespace pCampBot
Bot.Name, sourceRegion.Name, Bot.Client.Self.SimPosition, destRegion.Name, 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.
/// </summary>
/// <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>
public List<IBehaviour> Behaviours { get; private set; }
public Dictionary<string, IBehaviour> Behaviours { get; private set; }
/// <summary>
/// Objects that the bot has discovered.
@@ -165,8 +166,6 @@ namespace pCampBot
{
ConnectionState = ConnectionState.Disconnected;
behaviours.ForEach(b => b.Initialize(this));
Random = new Random(Environment.TickCount);// We do stuff randomly here
FirstName = firstName;
LastName = lastName;
@@ -176,12 +175,53 @@ namespace pCampBot
StartLocation = startLocation;
Manager = bm;
Behaviours = behaviours;
Behaviours = new Dictionary<string, IBehaviour>();
foreach (IBehaviour behaviour in behaviours)
AddBehaviour(behaviour);
// Only calling for use as a template.
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()
{
GridClient newClient = new GridClient();
@@ -237,16 +277,25 @@ namespace pCampBot
private void Action()
{
while (ConnectionState != ConnectionState.Disconnecting)
{
lock (Behaviours)
Behaviours.ForEach(
b =>
{
Thread.Sleep(Random.Next(3000, 10000));
// m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType());
b.Action();
}
);
{
foreach (IBehaviour behaviour in Behaviours.Values)
{
// Thread.Sleep(Random.Next(3000, 10000));
// m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType());
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>

View File

@@ -140,7 +140,7 @@ namespace pCampBot
/// <summary>
/// Behaviour switches for bots.
/// </summary>
private HashSet<string> m_behaviourSwitches = new HashSet<string>();
private HashSet<string> m_defaultBehaviourSwitches = new HashSet<string>();
/// <summary>
/// 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.",
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(
"bot", false, "sit", "sit", "Sit all bots on the ground.",
HandleSit);
@@ -212,7 +226,7 @@ namespace pCampBot
"bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus);
m_console.Commands.AddCommand(
"bot", false, "show bot", "show bot <first-name> <last-name>",
"bot", false, "show bot", "show bot <bot-number>",
"Shows the detailed status and settings of a particular bot.", HandleShowBotStatus);
m_bots = new List<Bot>();
@@ -235,7 +249,7 @@ namespace pCampBot
m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last"));
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++)
{
@@ -243,30 +257,52 @@ namespace pCampBot
{
string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber);
// We must give each bot its own list of instantiated behaviours since they store state.
List<IBehaviour> behaviours = new List<IBehaviour>();
// Hard-coded for now
if (m_behaviourSwitches.Contains("c"))
behaviours.Add(new CrossBehaviour());
if (m_behaviourSwitches.Contains("g"))
behaviours.Add(new GrabbingBehaviour());
if (m_behaviourSwitches.Contains("n"))
behaviours.Add(new NoneBehaviour());
if (m_behaviourSwitches.Contains("p"))
behaviours.Add(new PhysicsBehaviour());
if (m_behaviourSwitches.Contains("t"))
behaviours.Add(new TeleportBehaviour());
CreateBot(this, behaviours, m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting);
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.
List<IBehaviour> behaviours = new List<IBehaviour>();
// Hard-coded for now
foreach (string abName in abbreviatedNames)
{
IBehaviour newBehaviour = null;
if (abName == "c")
newBehaviour = new CrossBehaviour();
if (abName == "g")
newBehaviour = new GrabbingBehaviour();
if (abName == "n")
newBehaviour = new NoneBehaviour();
if (abName == "p")
newBehaviour = new PhysicsBehaviour();
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)
{
ConnectingBots = true;
@@ -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)
{
lock (m_bots)
@@ -572,10 +720,11 @@ namespace pCampBot
private void HandleShowBotsStatus(string module, string[] cmd)
{
ConsoleDisplayTable cdt = new ConsoleDisplayTable();
cdt.AddColumn("Name", 30);
cdt.AddColumn("Region", 30);
cdt.AddColumn("Status", 14);
cdt.AddColumn("Connections", 11);
cdt.AddColumn("Name", 24);
cdt.AddColumn("Region", 24);
cdt.AddColumn("Status", 13);
cdt.AddColumn("Conns", 5);
cdt.AddColumn("Behaviours", 20);
Dictionary<ConnectionState, int> totals = new Dictionary<ConnectionState, int>();
foreach (object o in Enum.GetValues(typeof(ConnectionState)))
@@ -583,13 +732,17 @@ namespace pCampBot
lock (m_bots)
{
foreach (Bot pb in m_bots)
foreach (Bot bot in m_bots)
{
Simulator currentSim = pb.Client.Network.CurrentSim;
totals[pb.ConnectionState]++;
Simulator currentSim = bot.Client.Network.CurrentSim;
totals[bot.ConnectionState]++;
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()));
}
}
@@ -605,22 +758,22 @@ namespace pCampBot
private void HandleShowBotStatus(string module, string[] cmd)
{
if (cmd.Length != 4)
if (cmd.Length != 3)
{
MainConsole.Instance.Output("Usage: show bot <first-name> <last-name>");
MainConsole.Instance.Output("Usage: show bot <n>");
return;
}
string name = string.Format("{0} {1}", cmd[2], cmd[3]);
int botNumber;
Bot bot;
if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber))
return;
lock (m_bots)
bot = m_bots.Find(b => b.Name == name);
Bot bot = GetBotFromNumber(botNumber);
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;
}
@@ -640,12 +793,39 @@ namespace pCampBot
MainConsole.Instance.Output("Settings");
ConsoleDisplayList statusCdl = new ConsoleDisplayList();
statusCdl.AddRow(
"Behaviours",
string.Join(", ", bot.Behaviours.Values.ToList().ConvertAll<string>(b => b.Name).ToArray()));
GridClient botClient = bot.Client;
statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES);
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)
{
lock (RegionsKnown)

View File

@@ -31,6 +31,11 @@ namespace pCampBot.Interfaces
{
public interface IBehaviour
{
/// <summary>
/// Abbreviated name of this behaviour.
/// </summary>
string AbbreviatedName { get; }
/// <summary>
/// Name of this behaviour.
/// </summary>
@@ -45,6 +50,14 @@ namespace pCampBot.Interfaces
/// <param name="bot"></param>
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>
/// Action to take when this behaviour is invoked.
/// </summary>

View File

@@ -51,7 +51,7 @@ namespace pCampBot
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public const string ConfigFileName = "pCampbot.ini";
public const string ConfigFileName = "pCampBot.ini";
[STAThread]
public static void Main(string[] args)

View File

@@ -151,7 +151,8 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
; *
[GridService]
LocalServiceModule = "OpenSim.Services.GridService.dll:GridService"
HypergridLinker = true
HypergridLinker = true
; Realm = "regions"
; AllowDuplicateNames = "True"
@@ -168,16 +169,31 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
;; Next, we can specify properties of regions, including default and fallback regions
;; The syntax is: Region_<RegionName> = "<flags>"
;; or: Region_<RegionID> = "<flags>"
;; where <flags> can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut,Reservation,NoMove,Authenticate
;; For example:
;; where <flags> can be DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate
;;
;; 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"
; (replace spaces with underscore)
;; Allow Hyperlinks to be created at the console
;; Allow Hyperlinks to be created at the console
HypergridLinker = true
;; If you have this set under [Hypergrid], no need to set it here, leave it commented
; GatekeeperURI = "http://127.0.0.1:8002"
;; If you have this set under [Hypergrid], no need to set it here, leave it commented
; GatekeeperURI = "http://127.0.0.1:8002"
; * This is the configuration for the freeswitch server in grid mode

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
;; The syntax is: Region_<RegionName> = "<flags>"
;; or: Region_<RegionID> = "<flags>"
;; where <flags> can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut,Reservation,NoMove,Authenticate
;; For example:
;; where <flags> can be DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate
;;
;; 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"
; (replace spaces with underscore)

View File

@@ -81,11 +81,27 @@
;; Next, we can specify properties of regions, including default and fallback regions
;; The syntax is: Region_<RegioName> = "<flags>"
;; 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:
Region_Welcome_Area = "DefaultRegion, FallbackRegion"
; === HG ONLY ===
;; If you have this set under [Hypergrid], no need to set it here, leave it commented
;; If you have this set under [Hypergrid], no need to set it here, leave it commented
; GatekeeperURI="http://127.0.0.1:9000"
[LibraryModule]
@@ -94,7 +110,7 @@
[LoginService]
WelcomeMessage = "Welcome, Avatar!"
;; If you have Gatekeeper set under [Hypergrid], no need to set it here, leave it commented
;; If you have Gatekeeper set under [Hypergrid], no need to set it here, leave it commented
; GatekeeperURI = "http://127.0.0.1:9000"
SRV_HomeURI = "http://127.0.0.1:9000"

View File

@@ -2,4 +2,4 @@ Not all of the files in this directory are licensed under the BSD license. Some
These files are:
- avataranimations.xml (Derivative work of viewerart.ini, Creative Commons Attribution+Share-Alike v2.5 License)
- avataranimations.xml (Derivative work of viewerart.ini, Creative Commons Attribution+Share-Alike v2.5 License)

View File

@@ -1795,6 +1795,7 @@
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Region.Framework"/>
<Reference name="OpenSim.Region.CoreModules"/>
<Reference name="OpenSim.Region.OptionalModules"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Region.Physics.Manager"/>
<Reference name="OpenSim.Region.Physics.Meshing" path="../../../../bin/Physics/"/>