Compare commits

...

147 Commits

Author SHA1 Message Date
Justin Clark-Casey (justincc) b7e3e9e2f5 Merge branch '0.7.6-post-fixes' into 0.7.6-extended 2014-02-13 00:30:55 +00:00
Justin Clark-Casey (justincc) d81a1666da Revert "Reassert extended branch version flavour again after merge from 0.7.6-post-fixes"
This reverts commit 2a482c22bc.
2014-02-13 00:23:51 +00:00
Justin Clark-Casey (justincc) 2a482c22bc Reassert extended branch version flavour again after merge from 0.7.6-post-fixes 2014-02-13 00:22:47 +00:00
Justin Clark-Casey (justincc) bb0f2f98e8 If a caller tries to queue a CAPs message to a scene presence that has no event queue (e.g. an NPC), only warn if event queue debugging is greater than zero.
Removes the spurious log warnings if groups are active when NPCs are used.
Adds more regression tests associated with adding messages to the event queue
2014-02-12 23:27:22 +00:00
Justin Clark-Casey (justincc) 8000d0ec32 Change 0.7.6-post-fixes branch back to Post_Fixes flavour 2014-02-01 00:15:47 +00:00
Justin Clark-Casey (justincc) 40144fb0f6 Change 0.7.6.1 flavour to release 2014-01-31 20:28:09 +00:00
Justin Clark-Casey (justincc) 88bd146f04 Change release flavour on 0.7.6-extended branch back to extended again (changed from pf merge) 2014-01-30 01:02:10 +00:00
Justin Clark-Casey (justincc) 75777ddd57 Record whether login to home fails because no home set (UUID.Zero) or region not found. 2014-01-30 00:50:53 +00:00
Justin Clark-Casey (justincc) 6dd99837fd Add "show grid user" robust/standalone console command for debug purposes.
Shows all data on entries which match or start with a given ID.
This would usually be a UUID.
2014-01-30 00:28:49 +00:00
Justin Clark-Casey (justincc) 798c61c112 minor: remove long unused state queue from "show queues" console reports 2014-01-24 19:42:52 +00:00
Justin Clark-Casey (justincc) ed1a10d92f minor: correct the usage statement on the "show image queues" console command - should not have been "image queues show" 2014-01-24 19:42:48 +00:00
Justin Clark-Casey (justincc) d1f1642e1a Skip IClientAPIs that don't implement IStatsCollector (such as NPCAvatar) from the "show queues" console report to stop screwing up formatting.
"show pquques" already did this
2014-01-24 19:42:44 +00:00
Justin Clark-Casey (justincc) 87e725cd24 Merge branch '0.7.6-extended' into 0.7.6-post-fixes 2014-01-24 19:16:59 +00:00
Justin Clark-Casey (justincc) 3ee9a6c2ee Change version to 0.7.6.1-rc1 instead 2014-01-24 19:14:45 +00:00
Justin Clark-Casey (justincc) 972f5175a8 Change version to 0.7.6.1 and type to Release 2014-01-24 18:29:31 +00:00
Justin Clark-Casey (justincc) 04e6c68242 Properly dispose of drawing objects to reduce/stop memory leakage on generating map tiles with the MapImageModule and TexturedMapTileRenderer (the current defaults) 2014-01-24 00:20:41 +00:00
Justin Clark-Casey (justincc) 099975dec2 Add "generate map" console command to allow manual regeneration and storage of maptiles
Primarily for test purposes though could be useful if one prefers to manually update the map tile
2014-01-24 00:20:22 +00:00
Justin Clark-Casey (justincc) 27abe040bd Stop exceptions being generated on agent connection if a telehub object has been deleted or has no spawn points. 2014-01-20 19:37:50 +00:00
Justin Clark-Casey (justincc) d88c9756a7 Actually put IsChildAgent = true inside the lock, otherwise there is still a small window for race conditions on duplicate CompleteMovement calls 2014-01-17 00:11:52 +00:00
Justin Clark-Casey (justincc) bf86addf3d Prevent duplicate invocations or race dontision in SP.CompleteMovement()
This can happen under poor network conditions if a viewer repeats the message send
If this happens, physics actors can get orphaned, which unecessarily raises physics frame times
2014-01-17 00:11:48 +00:00
Justin Clark-Casey (justincc) 91d86301ef Merge branch '0.7.6-post-fixes' of ssh://opensimulator.org/var/git/opensim into 0.7.6-post-fixes 2014-01-15 00:28:58 +00:00
Justin Clark-Casey (justincc) b73b5a24c3 Fix false positive test failure in TestRepeatSameDrawContainingImageReusingTexture() and TestRepeatSameDrawContainingImage() if localhost has a webserver set up.
Use 0.0.0.0 instead of localhost
2014-01-15 00:15:28 +00:00
Melanie 3ab559efa9 Dynamically adjust to the number of visual params sent. 2014-01-05 19:50:51 +00:00
BlueWall bece6fb8a3 Merge branch '0.7.6-post-fixes' of ssh://opensimulator.org/var/git/opensim into 0.7.6-post-fixes 2013-12-16 16:36:05 -05:00
BlueWall 017ae9132e Fix issue with editing notes for other avatars 2013-12-16 16:26:28 -05:00
BlueWall b699af87dc Populate user preferences with UserAccount email if it is present, else return an error indicating no email is on record for the user. 2013-12-16 16:25:14 -05:00
Justin Clark-Casey (justincc) c1ff245bf3 Wrap analysis of the particle system in the UUID Gatherer in a separate try/catch as sometimes it appears that this can be corrupt.
As per Oren's suggestion.
2013-12-14 02:35:07 +00:00
BlueWall 5745aa0f86 Backport profile fixes 2013-12-06 14:30:37 -05:00
Kevin Cozens b8a6fd3e64 Added support for attachments to group notices when using Flotsam groups. 2013-10-15 23:19:37 +01:00
Justin Clark-Casey (justincc) 3bd922f61b Change 0.7.6 release flavour to post fixes 2013-10-04 23:37:48 +01:00
Justin Clark-Casey (justincc) 9dae06b296 Update flavour to release 2013-10-04 20:45:02 +01:00
Justin Clark-Casey (justincc) ef10e10fd7 Add OnChatToNPC and OnInstantMessageToNPC messages to NPCAvatar to allow region modules to directly subscribe to chat and messages received by NPCs
Currently still requires INPC from NPCModule.GetNPC() to be cast to an NPCAvatar.
2013-10-04 20:43:02 +01:00
Justin Clark-Casey (justincc) 329235d3b7 Flip release version to RC1 2013-09-27 22:34:40 +01:00
Justin Clark-Casey (justincc) 1e48bf43a3 minor: Disable logging left active on regression test TestSameSimulatorIsolatedRegionsV2() 2013-09-27 22:34:24 +01:00
Justin Clark-Casey (justincc) 5a6ad028e3 refactor: Rename Scene.AddNewClient() to AddNewAgent() to make it obvious in the code that this is symmetric with CloseAgent() 2013-09-27 22:29:16 +01:00
Justin Clark-Casey (justincc) e6c0267def refactor: rename Scene.IncomingCloseAgent() to CloseAgent() in order to make it clear that all non-clientstack callers should be using this rather than RemoveClient() in order to step through the ScenePresence state machine properly.
Adds IScene.CloseAgent() to replace RemoveClient()
2013-09-27 22:29:10 +01:00
dahlia 753cc93af5 minor code formatting for the sake of consistency and readability 2013-09-27 00:36:13 +01:00
Justin Clark-Casey (justincc) d950cd7670 minor: Make OpenSimDefaults.ini consistent (spacing and tabs to spaces) 2013-09-27 00:18:39 +01:00
Justin Clark-Casey (justincc) ae3407c73e minor: Clean up tabbing and spacing issues in OpenSim.ini.example 2013-09-27 00:18:33 +01:00
Justin Clark-Casey (justincc) 19e2f44c25 minor: correct attachment spelling mistake in log message in HGEntityTransferModule.OnIncomingSceneObject() 2013-09-26 22:38:49 +01:00
Justin Clark-Casey (justincc) f0845c18d4 minor: Comment out windlight log message about sending scene data for now. 2013-09-26 20:11:27 +01:00
Justin Clark-Casey (justincc) b21c06de23 minor: Add scene name to baked textures in cache log message 2013-09-26 20:11:22 +01:00
Justin Clark-Casey (justincc) 643bc47451 minor: log MaxOutgoingTransferVersion at EntityTransferModule startup 2013-09-26 20:11:17 +01:00
Justin Clark-Casey (justincc) 7d6072b825 minor: correct spelling of Initialized in LSC connector version message 2013-09-26 20:11:12 +01:00
Justin Clark-Casey (justincc) 6013c15b6e Move adding UUID.Zero -> Unknown User binding to UMM.Init() so that it's also called by HGUserManagementModule 2013-09-26 20:11:09 +01:00
Justin Clark-Casey (justincc) 0114c8bd15 Reinsert client.SceneAgent checks into LLUDPServer.HandleCompleteMovementIntoRegion() to fix race condition regression in commit 7dbc93c (Wed Sep 18 21:41:51 2013 +0100)
This check is necessary to close a race condition where the CompleteAgentMovement processing could proceed when the UseCircuitCode thread had added the client to the client manager but before the ScenePresence had registered to process the CompleteAgentMovement message.
This is most probably why the message appeared to get lost on a proportion of entity transfers.
A better long term solution may be to set the IClientAPI.SceneAgent property before the client is added to the manager.
2013-09-26 20:11:05 +01:00
Justin Clark-Casey (justincc) 7eb5680c38 Reinsert 200ms sleep accidentally removed in commit 7dbc93c (Wed Sep 18 21:41:51 2013 +0100) 2013-09-26 20:11:00 +01:00
Justin Clark-Casey (justincc) 516ab5d8c6 Instead of swallowing any socket begin/end receive exceptions, log them for debugging purposes.
This may reveal why on some teleports with current code, the UseCircuitCode message gets through but CompleteMovement disappears into the ether.
2013-09-26 20:10:56 +01:00
Justin Clark-Casey (justincc) 2b392a09b1 minor: Recomment out log message uncommented in previous cbdfe969 2013-09-26 20:09:48 +01:00
Oren Hurvitz 5be6954e5d When giving items between avatars in different simulators, only add the item to the receiving avatar's inventory once.
When a user gives an item, the user's client sends an InventoryOffered IM message to its simulator. This adds the item to the receiver's inventory. If the receiver isn't in the same simulator then XMLRPC is used to forward the IM to the correct simulator. The bug was that the receiving simulator handled the message by calling OnInstantMessage() again, which added a second copy of the item to the inventory. Instead, the receiving simulator should only notify the avatar that the item was offered.
2013-09-26 20:09:43 +01:00
Justin Clark-Casey (justincc) 7cb673e5dc minor: Add prefix to log message in LureModule 2013-09-26 20:09:38 +01:00
Justin Clark-Casey (justincc) e4dd069a95 minor: Correct minor spelling mistake Reseting -> Resetting in HG Map module log message 2013-09-26 20:09:34 +01:00
Justin Clark-Casey (justincc) afa9847288 Make UUID.Zero resolve to "Unknown User" in user cache.
This is to avoid massive numbers of 'no user found' logs when user IDs are missing for some reason.
UUID.Zero should not be used for any user ID.
2013-09-26 20:09:30 +01:00
Justin Clark-Casey (justincc) 111d1ba826 Lock around read/write of ScenePresence.m_originRegionID to make sure that all threads are seeing the latest value and not a cached one.
There is a possibilty that some V2 teleport failures are due to the viewer triggered CompleteMovement thread not seeing the change of m_originRegionID by the UpdateAgent thread.
2013-09-26 20:09:25 +01:00
Justin Clark-Casey (justincc) 914a92335a Change some message log levels in Scene.IncomingUpdateChildAgent() for debugging purposes 2013-09-26 20:09:21 +01:00
Robert Adams 2c856f2a60 BulletSim: reduce avatar walking stopped threshold.
Add parameter for setting the walking stopped threshold.

This fixes the slight jump when an avatar stops walking.
2013-09-26 20:09:16 +01:00
Robert Adams 3ba1d5259a BulletSim: zero velocity when avatar not moving.
This fixes a movement jitter that happens when an avatar is standing on a
tilted surface.
2013-09-26 20:09:12 +01:00
Justin Clark-Casey (justincc) 0bb8415a69 Make new regions PG by default instead of Mature.
This makes scripted object sounds and a few other things play by default instead of having to switch the viewer to adult
This reduces the support burden
2013-09-26 20:09:07 +01:00
Oren Hurvitz 24ab021ea1 UUID Gatherer: find assets used in Light Projection, Particle Systems, and Collision Sounds. 2013-09-26 20:09:03 +01:00
Justin Clark-Casey (justincc) 882ba74140 For debug purposes, allow simulators to force use of earlier SIMULATION/0.1 teleport protocol even if SIMULATION/0.2 is available.
This is specified in the MaxOutgoingTransferVersion attribute of [EntityTransfer] in OpenSim.ini, see OpenSimDefaults.ini for more details.
Default remains "SIMULATION/0.2"
Primarily for http://opensimulator.org/mantis/view.php?id=6755
2013-09-26 20:08:49 +01:00
Justin Clark-Casey (justincc) b675e41d01 minor: Make log message at top of ScenePresence.CompleteMovement info level and comment out later log message in ScenePresence.MakeRootAgent()
Need an info message since this is currently important in detecting teleport issue when not at debug log level.
CompleteMovement message occurs before MakeRootAgent() one did
2013-09-26 20:07:30 +01:00
Justin Clark-Casey (justincc) c01dea0f6a minor: Make SP.MakeRootAgent() private - no external code has any business calling this method 2013-09-26 20:07:15 +01:00
Justin Clark-Casey (justincc) ff08f56937 minor: Stop debug logging whenever an npc is moved, other npc log related formatting cleanups 2013-09-26 20:07:07 +01:00
Justin Clark-Casey (justincc) 5dabecf95d Revert "Also check user authorization if looking to upgrade from a child to a root agent."
This reverts commit c7ded0618c.
This proves not to be necessary - the necessary checks are already being done via QueryAccess() before cross or teleport
2013-09-26 20:07:02 +01:00
Justin Clark-Casey (justincc) 689f79fead Create regression TestCrossOnSameSimulatorNoRootDestPerm() to check that avatars are not allowed to cross into a neighbour where they are not authorized, even if a child agent was allowed. 2013-09-26 20:06:57 +01:00
Justin Clark-Casey (justincc) ac2b1497c0 minor: Make config-include .ini files more consistent
Chiefly tabs to spaces.
No actual setting changes
2013-09-26 20:06:51 +01:00
Justin Clark-Casey (justincc) de4d568923 Add [SimulationService] section to GridHypergrid.ini and StandaloneHypergrid.ini
This was already in Grid.ini and Standalone.ini
Default settings are same as previously, just introduce a debug ConnectorProtocolVersion parameter
2013-09-26 20:06:47 +01:00
Justin Clark-Casey (justincc) 12a191409e minor: correct method name in comment 2013-09-26 20:06:42 +01:00
Justin Clark-Casey (justincc) d1d4dd547a refactor: rename *ChildAgentDataUpdate() methods to *UpdateChildAgent()
verb-noun is consistent with other similar methods
2013-09-26 20:06:38 +01:00
Justin Clark-Casey (justincc) 1a55309ea7 minor: Make log message when Scene.IncomingChildAgentDateUpdate() more explicit that there is a problem if it still finds the agent to be a child if the sender wanted to wait till it became root
Add some comments about the mssage sequence, though much more data is at
http://opensimulator.org/wiki/Teleports
2013-09-26 20:06:32 +01:00
Justin Clark-Casey (justincc) ee58e3a5a1 Double the time spent waiting for a UseCircuitCode packet in LLUDPServer.HandleCompleteMovementIntoRegion()
This is to deal with one aspect of http://opensimulator.org/mantis/view.php?id=6755
With the V2 teleport arrangements, viewers appear to send the single UseCircuitCode and CompleteAgentMovement packets immediately after each other
Possibly, on occasion a poor network might drop the initial UseCircuitCode packet and by the time it retries, the CompleteAgementMovement has timed out and the teleport fails.
There's no apparant harm in doubling the wait time (most times only one wait will be performed) so trying this.
2013-09-26 20:06:28 +01:00
Justin Clark-Casey (justincc) 6c2462e410 Change logging to provide more information on LLUDPServer.HandleCompleteMovementIntoRegion()
Add more information on which endpoint sent the packet when we have to wait and if we end up dropping the packet
Only check if the client is active - other checks are redundant since they can only failed if IsActve = false
2013-09-26 20:06:22 +01:00
Justin Clark-Casey (justincc) b1d43d46bf Reinstate insertion of "Unknown UserUMMAU4" now, as naive removing may be generating too many repeating user requests from other sources.
Leaves in the dropping of the client GUN8 (now 9) uuid binding message, since this was the much more common case from the viewer-side and this can only affect viewers.
2013-09-20 21:39:30 +01:00
Justin Clark-Casey (justincc) ccf52d3d9d Comment out warning about no grid user found in UMM.TryGetUserNamesFromServices() for now 2013-09-20 21:39:26 +01:00
Justin Clark-Casey (justincc) 7a14221754 Fix issue in recent 3f0fa9f7 where the code start adding unknown user cache entries with no name 2013-09-20 21:39:20 +01:00
Justin Clark-Casey (justincc) d5a3139b05 Reinsert comments about possible race conditions when sending bulk inventory updates on non-flag clothing editing 2013-09-20 21:39:17 +01:00
Justin Clark-Casey (justincc) 6f5fd067a5 Fix bug where using PRIM_LINK_TARGET with only two remaining list items (e.g. link number then PRIM_ROTATION) would not return the parameter
Extended regression test for this case
2013-09-20 21:39:10 +01:00
Justin Clark-Casey (justincc) 9fcf1de0fa Make llGetLinkPrimitiveParams() abort and return existing list of params when it encounters an invalid link number, rather than throwing an exception
Addresses http://opensimulator.org/mantis/view.php?id=6768
Thanks to talun for the patch on that commit - in the end I took a different approach that also deals with invalid PRIM_LINK_TARGET
However, not yet generating the same warning on invalid PRIM_LINK_TARGET as seen on LL grid
This commit also adds regression tests for some cases of llGetLinkPrimitiveParams()
2013-09-20 21:39:07 +01:00
Justin Clark-Casey (justincc) 86c39d618e To avoid viewers (particularly on the Hypergrid) from permanently caching a UUID -> "Unknown User" binding, drop the binding request rather than replying with "Unknown User"
By not binding UUID -> "Unknown User", we leave open the possibility that the binding may be correctly resolved at a later time, which can still happen in some Hypergrid situations.
Observed behaviour of LL viewer 3.3.4 is that a dropped bind request is not retried until the next session.
2013-09-20 21:39:01 +01:00
Justin Clark-Casey (justincc) 068f22a52c minor: replace spaces with tabs for see_into_region setting 2013-09-20 21:38:55 +01:00
Talun 726b7dce61 6762: llList2Key fails to convert a string in a list to a key
llGetPrimitiveParams changed to return the sculpty key as an LSL_String so
that type checking in llList2Key will work
2013-09-20 21:38:49 +01:00
Robert Adams d260e398f5 BulletSim: update DLLs and SOs to disable Bullet's internal profiling.
This was accidentily left on. This version should make performance better
and fix the memory leak.
2013-09-20 21:38:45 +01:00
BlueWall 560ea54c98 Allow setting the EntityTransfer-max_distance to 0 to override distance checks. This is to facilitate current viewer work fixing the distance limitations for teleporting. 2013-09-20 21:37:56 +01:00
Robert Adams 10152815ac BulletSim: remove collision cache clearing logic for physical objects.
This fixes constraints from getting messed up when properties change.
2013-09-20 21:04:18 +01:00
Mic Bowman 1217785155 Change handling of the FetchInventoryDescendents2 capability configuration to allow
for external handlers.
2013-09-20 21:04:10 +01:00
Robert Adams 712bee7206 BulletSim: update DLLs and SOs with ClearCollisionCache inteface calls
and constraint debugging messages.
2013-09-20 21:04:07 +01:00
Robert Adams 568ff6fddc BulletSim: add ClearCollisionProxyCache function to API.
Add proxy cache clearing when some properties are changed. This fixes
a problem where objects would stop colliding of they were moved
with setPosition mulitple times.
2013-09-20 21:04:03 +01:00
Robert Adams b6568c7e22 BulletSim: update DLLs and SOs for spring parameters and constraint
debugging dump code.
2013-09-20 21:03:54 +01:00
Robert Adams 4179d8f651 BulletSim: add LSL function and plumbing for setting a spring
equilibrium point in the physics engine constraint.
2013-09-20 21:03:50 +01:00
Robert Adams bde8ac6a5c BulletSim: add extended physics LSL constants for axis specification.
Add specific error warnings for mis-matched parameter types in extended
   physics functions.
2013-09-20 21:03:47 +01:00
Robert Adams 9d04c6a828 BulletSim: ability to specify groups of axis to modify in constraint parameters that control multiple axis. Add useLinearReferenceFrameA constraint parameter. 2013-09-20 21:03:42 +01:00
Robert Adams 7a9eb26b00 BulletSim: add axis parameter for specifying enable, damping, and stiffness for spring constraints. Renumber parameter ops since I can as no one is using them yet. 2013-09-20 21:03:34 +01:00
Robert Adams 2e32b2aacb BulletSim: implementation of setting spring specific physical parameters. Add setting of linkset type to physChangeLinkParams. Lots of detail logging for setting of linkset constraint parameters. 2013-09-20 21:03:31 +01:00
Robert Adams 6ade1c6c76 BulletSim: add requestor's ID to post taint detail log message. 2013-09-20 21:03:28 +01:00
Robert Adams 0e4a06edf9 BulletSim: remove chatty debug message from previous commit. 2013-09-20 21:03:25 +01:00
Robert Adams d3efb6a7f7 BulletSim: add position and rotation update for child prim physics update events. Normally, physics engines do not return updates for child prims so, under normal operation, this code should never execute. Will only be used when using flexible linkset linkages. 2013-09-20 21:03:21 +01:00
Robert Adams 70438ff6ab BulletSim: pass both root and child BSPhysObjects to Extension function. Update routines to use the new parameters list from above change. 2013-09-20 21:03:18 +01:00
Robert Adams 1b021e0eaa BulletSim: add ID parameter to TaintedObject calls so logging will include LocalID of object which created the taint. 2013-09-20 21:03:14 +01:00
Robert Adams 21a046e622 BulletSim: Extension parameters passed through the classes made to pass just and array of objects rather than a mixture of parameters and array. Makes understanding and parsing what is being passed much easier. 2013-09-20 21:03:10 +01:00
Robert Adams 1f740926a2 BulletSim: adjust avatar capsule height calculation to be closer to defined SL heights. Correct BSParam avatar height defaults to be what's in OpenSimDefaults.ini. 2013-09-20 21:03:06 +01:00
Robert Adams fd3e267ec6 BulletSim: add extended physics function physGetLinkType(linkNum). Add implementation of physChangeLinkParams() in BSLinksetConstraint. 2013-09-20 21:02:50 +01:00
Robert Adams 73a62788a5 BulletSim: update DLLs and SOs with Bullet svn version 2644 (no major fixes) and with BulletSim implementing more of the constraint types and parameter settings. 2013-09-20 21:02:43 +01:00
Robert Adams 1076f56373 BulletSim: change ExtendedPhysics constants to 'const' so they can be used as case variables in switch statements. 2013-09-20 21:02:39 +01:00
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
135 changed files with 4954 additions and 1606 deletions

View File

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

View File

@ -48,6 +48,8 @@ namespace OpenSim.Data
bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result); bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result);
bool UpdateAvatarInterests(UserProfileProperties up, ref string result); bool UpdateAvatarInterests(UserProfileProperties up, ref string result);
bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result); bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result);
bool UpdateUserPreferences(ref UserPreferences pref, ref string result);
bool GetUserPreferences(ref UserPreferences pref, ref string result);
bool GetUserAppData(ref UserAppData props, ref string result); bool GetUserAppData(ref UserAppData props, ref string result);
bool SetUserAppData(UserAppData props, ref string result); bool SetUserAppData(UserAppData props, ref string result);
OSDArray GetUserImageAssets(UUID avatarId); OSDArray GetUserImageAssets(UUID avatarId);

View File

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

View File

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

View File

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

View File

@ -546,6 +546,10 @@ namespace OpenSim.Data.MySQL
reader.Read(); reader.Read();
notes.Notes = OSD.FromString((string)reader["notes"]); notes.Notes = OSD.FromString((string)reader["notes"]);
} }
else
{
notes.Notes = OSD.FromString("");
}
} }
} }
} }
@ -897,7 +901,7 @@ namespace OpenSim.Data.MySQL
} }
#region User Preferences #region User Preferences
public OSDArray GetUserPreferences(UUID avatarId) public bool GetUserPreferences(ref UserPreferences pref, ref string result)
{ {
string query = string.Empty; string query = string.Empty;
@ -914,31 +918,32 @@ namespace OpenSim.Data.MySQL
dbcon.Open(); dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
{ {
cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); cmd.Parameters.AddWithValue("?Id", pref.UserId.ToString());
using (MySqlDataReader reader = cmd.ExecuteReader()) using (MySqlDataReader reader = cmd.ExecuteReader())
{ {
if(reader.HasRows) if(reader.HasRows)
{ {
reader.Read(); reader.Read();
OSDMap record = new OSDMap(); bool.TryParse((string)reader["imviaemail"], out pref.IMViaEmail);
bool.TryParse((string)reader["visible"], out pref.Visible);
record.Add("imviaemail",OSD.FromString((string)reader["imviaemail"])); pref.EMail = (string)reader["email"];
record.Add("visible",OSD.FromString((string)reader["visible"]));
record.Add("email",OSD.FromString((string)reader["email"]));
data.Add(record);
} }
else else
{ {
dbcon.Close();
dbcon.Open();
query = "INSERT INTO usersettings VALUES ";
query += "(?uuid,'false','false', ?Email)";
using (MySqlCommand put = new MySqlCommand(query, dbcon)) using (MySqlCommand put = new MySqlCommand(query, dbcon))
{ {
query = "INSERT INTO usersettings VALUES ";
query += "(?Id,'false','false', '')";
lock(Lock) put.Parameters.AddWithValue("?Email", pref.EMail);
{ put.Parameters.AddWithValue("?uuid", pref.UserId.ToString());
put.ExecuteNonQuery();
} put.ExecuteNonQuery();
} }
} }
} }
@ -949,17 +954,19 @@ namespace OpenSim.Data.MySQL
{ {
m_log.DebugFormat("[PROFILES_DATA]" + m_log.DebugFormat("[PROFILES_DATA]" +
": Get preferences exception {0}", e.Message); ": Get preferences exception {0}", e.Message);
result = e.Message;
return false;
} }
return data; return true;
} }
public bool UpdateUserPreferences(bool emailIm, bool visible, UUID avatarId ) public bool UpdateUserPreferences(ref UserPreferences pref, ref string result)
{ {
string query = string.Empty; string query = string.Empty;
query += "UPDATE userpsettings SET "; query += "UPDATE usersettings SET ";
query += "imviaemail=?ImViaEmail, "; query += "imviaemail=?ImViaEmail, ";
query += "visible=?Visible,"; query += "visible=?Visible ";
query += "WHERE useruuid=?uuid"; query += "WHERE useruuid=?uuid";
try try
@ -969,14 +976,11 @@ namespace OpenSim.Data.MySQL
dbcon.Open(); dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) using (MySqlCommand cmd = new MySqlCommand(query, dbcon))
{ {
cmd.Parameters.AddWithValue("?ImViaEmail", emailIm.ToString().ToLower ()); cmd.Parameters.AddWithValue("?ImViaEmail", pref.IMViaEmail);
cmd.Parameters.AddWithValue("?WantText", visible.ToString().ToLower ()); cmd.Parameters.AddWithValue("?Visible", pref.Visible);
cmd.Parameters.AddWithValue("?uuid", avatarId.ToString()); cmd.Parameters.AddWithValue("?uuid", pref.UserId.ToString());
lock(Lock) cmd.ExecuteNonQuery();
{
cmd.ExecuteNonQuery();
}
} }
} }
} }
@ -984,6 +988,7 @@ namespace OpenSim.Data.MySQL
{ {
m_log.DebugFormat("[PROFILES_DATA]" + m_log.DebugFormat("[PROFILES_DATA]" +
": AgentInterestsUpdate exception {0}", e.Message); ": AgentInterestsUpdate exception {0}", e.Message);
result = e.Message;
return false; return false;
} }
return true; return true;

View File

@ -81,3 +81,13 @@ CREATE TABLE IF NOT EXISTS `userdata` (
commit; commit;
:VERSION 3 # -------------------------------
begin;
CREATE TABLE IF NOT EXISTS `usersettings` (
`useruuid` varchar(36) NOT NULL,
`imviaemail` enum('true','false') NOT NULL,
`visible` enum('true','false') NOT NULL,
`email` varchar(254) NOT NULL,
PRIMARY KEY (`useruuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
commit;

View File

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

View File

@ -88,3 +88,15 @@ CREATE TABLE IF NOT EXISTS userdata (
commit; commit;
:VERSION 3 # -------------------------------
begin;
CREATE TABLE IF NOT EXISTS usersettings (
useruuid char(36) NOT NULL,
imviaemail binary(1) NOT NULL,
visible binary(1) NOT NULL,
email varchar(254) NOT NULL,
PRIMARY KEY (useruuid)
)
commit;

View File

@ -749,6 +749,90 @@ namespace OpenSim.Data.SQLite
} }
return true; return true;
} }
public bool UpdateUserPreferences(ref UserPreferences pref, ref string result)
{
string query = string.Empty;
query += "UPDATE usersettings SET ";
query += "imviaemail=:ImViaEmail, ";
query += "visible=:Visible ";
query += "WHERE useruuid=:uuid";
try
{
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = query;
cmd.Parameters.AddWithValue(":ImViaEmail", pref.IMViaEmail);
cmd.Parameters.AddWithValue(":Visible", pref.Visible);
cmd.Parameters.AddWithValue(":uuid", pref.UserId.ToString());
cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
m_log.DebugFormat("[PROFILES_DATA]" +
": AgentInterestsUpdate exception {0}", e.Message);
result = e.Message;
return false;
}
return true;
}
public bool GetUserPreferences(ref UserPreferences pref, ref string result)
{
IDataReader reader = null;
string query = string.Empty;
query += "SELECT imviaemail,visible,email FROM ";
query += "usersettings WHERE ";
query += "useruuid = :Id";
OSDArray data = new OSDArray();
try
{
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
{
cmd.CommandText = query;
cmd.Parameters.AddWithValue("?Id", pref.UserId.ToString());
using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
if(reader.Read())
{
bool.TryParse((string)reader["imviaemail"], out pref.IMViaEmail);
bool.TryParse((string)reader["visible"], out pref.Visible);
pref.EMail = (string)reader["email"];
}
else
{
query = "INSERT INTO usersettings VALUES ";
query += "(:Id,'false','false', :Email)";
using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand())
{
put.Parameters.AddWithValue(":Id", pref.UserId.ToString());
put.Parameters.AddWithValue(":Email", pref.EMail);
put.ExecuteNonQuery();
}
}
}
}
}
catch (Exception e)
{
m_log.DebugFormat("[PROFILES_DATA]" +
": Get preferences exception {0}", e.Message);
result = e.Message;
return false;
}
return true;
}
public bool GetUserAppData(ref UserAppData props, ref string result) public bool GetUserAppData(ref UserAppData props, ref string result)
{ {
IDataReader reader = null; IDataReader reader = null;

View File

@ -86,24 +86,26 @@ namespace OpenSim.Framework
event restart OnRestart; event restart OnRestart;
/// <summary> /// <summary>
/// Add a new client and create a presence for it. All clients except initial login clients will starts off as a child agent /// Add a new agent with an attached client. All agents except initial login clients will starts off as a child agent
/// - the later agent crossing will promote it to a root agent. /// - the later agent crossing will promote it to a root agent.
/// </summary> /// </summary>
/// <param name="client"></param> /// <param name="client"></param>
/// <param name="type">The type of agent to add.</param> /// <param name="type">The type of agent to add.</param>
/// <returns> /// <returns>
/// The scene agent if the new client was added or if an agent that already existed.</returns> /// The scene agent if the new client was added or if an agent that already existed.</returns>
ISceneAgent AddNewClient(IClientAPI client, PresenceType type); ISceneAgent AddNewAgent(IClientAPI client, PresenceType type);
/// <summary> /// <summary>
/// Remove the given client from the scene. /// Tell a single agent to disconnect from the region.
/// </summary> /// </summary>
/// <param name="agentID"></param> /// <param name="agentID"></param>
/// <param name="closeChildAgents">Close the neighbour child agents associated with this client.</param> /// <param name="force">
void RemoveClient(UUID agentID, bool closeChildAgents); /// Force the agent to close even if it might be in the middle of some other operation. You do not want to
/// force unless you are absolutely sure that the agent is dead and a normal close is not working.
/// </param>
bool CloseAgent(UUID agentID, bool force);
void Restart(); void Restart();
//RegionInfo OtherRegionUp(RegionInfo thisRegion);
string GetSimulatorVersion(); string GetSimulatorVersion();

View File

@ -67,7 +67,7 @@ namespace OpenSim.Framework.Monitoring
if (cmd[3] == "start") if (cmd[3] == "start")
{ {
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") else if (cmd[3] == "stop")
{ {

View File

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

View File

@ -200,7 +200,7 @@ namespace OpenSim.Framework
set { m_ObjectBonus = value; } set { m_ObjectBonus = value; }
} }
private int m_Maturity = 1; private int m_Maturity = 0;
public int Maturity public int Maturity
{ {
@ -482,21 +482,14 @@ namespace OpenSim.Framework
set { m_LoadedCreationID = value; } set { m_LoadedCreationID = value; }
} }
// Connected Telehub object /// <summary>
private UUID m_TelehubObject = UUID.Zero; /// Connected Telehub object
public UUID TelehubObject /// </summary>
{ public UUID TelehubObject { get; set; }
get
{
return m_TelehubObject;
}
set
{
m_TelehubObject = value;
}
}
// Our Connected Telehub's SpawnPoints /// <summary>
/// Our connected Telehub's SpawnPoints
/// </summary>
public List<SpawnPoint> l_SpawnPoints = new List<SpawnPoint>(); public List<SpawnPoint> l_SpawnPoints = new List<SpawnPoint>();
// Add a SpawnPoint // Add a SpawnPoint

View File

@ -29,8 +29,8 @@ namespace OpenSim
{ {
public class VersionInfo public class VersionInfo
{ {
private const string VERSION_NUMBER = "0.7.6"; private const string VERSION_NUMBER = "0.7.6.1";
private const Flavour VERSION_FLAVOUR = Flavour.Dev; private const Flavour VERSION_FLAVOUR = Flavour.Extended;
public enum Flavour public enum Flavour
{ {

View File

@ -90,6 +90,14 @@ namespace OpenSim.Framework
public UUID TargetId; public UUID TargetId;
public string Notes; public string Notes;
} }
public class UserPreferences
{
public UUID UserId;
public bool IMViaEmail = false;
public bool Visible = false;
public string EMail = string.Empty;
}
public class UserAccountProperties public class UserAccountProperties
{ {

View File

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

View File

@ -237,27 +237,33 @@ namespace OpenSim
m_console.Commands.AddCommand("General", false, "change region", m_console.Commands.AddCommand("General", false, "change region",
"change region <region name>", "change region <region name>",
"Change current console region", ChangeSelectedRegion); "Change current console region",
ChangeSelectedRegion);
m_console.Commands.AddCommand("Archiving", false, "save xml", m_console.Commands.AddCommand("Archiving", false, "save xml",
"save xml", "save xml",
"Save a region's data in XML format", SaveXml); "Save a region's data in XML format",
SaveXml);
m_console.Commands.AddCommand("Archiving", false, "save xml2", m_console.Commands.AddCommand("Archiving", false, "save xml2",
"save xml2", "save xml2",
"Save a region's data in XML2 format", SaveXml2); "Save a region's data in XML2 format",
SaveXml2);
m_console.Commands.AddCommand("Archiving", false, "load xml", m_console.Commands.AddCommand("Archiving", false, "load xml",
"load xml [-newIDs [<x> <y> <z>]]", "load xml [-newIDs [<x> <y> <z>]]",
"Load a region's data from XML format", LoadXml); "Load a region's data from XML format",
LoadXml);
m_console.Commands.AddCommand("Archiving", false, "load xml2", m_console.Commands.AddCommand("Archiving", false, "load xml2",
"load xml2", "load xml2",
"Load a region's data from XML2 format", LoadXml2); "Load a region's data from XML2 format",
LoadXml2);
m_console.Commands.AddCommand("Archiving", false, "save prims xml2", m_console.Commands.AddCommand("Archiving", false, "save prims xml2",
"save prims xml2 [<prim name> <file name>]", "save prims xml2 [<prim name> <file name>]",
"Save named prim to XML2", SavePrimsXml2); "Save named prim to XML2",
SavePrimsXml2);
m_console.Commands.AddCommand("Archiving", false, "load oar", m_console.Commands.AddCommand("Archiving", false, "load oar",
"load oar [--merge] [--skip-assets] [<OAR path>]", "load oar [--merge] [--skip-assets] [<OAR path>]",
@ -287,7 +293,8 @@ namespace OpenSim
m_console.Commands.AddCommand("Objects", false, "edit scale", m_console.Commands.AddCommand("Objects", false, "edit scale",
"edit scale <name> <x> <y> <z>", "edit scale <name> <x> <y> <z>",
"Change the scale of a named prim", HandleEditScale); "Change the scale of a named prim",
HandleEditScale);
m_console.Commands.AddCommand("Users", false, "kick user", m_console.Commands.AddCommand("Users", false, "kick user",
"kick user <first> <last> [--force] [message]", "kick user <first> <last> [--force] [message]",
@ -305,31 +312,38 @@ namespace OpenSim
m_console.Commands.AddCommand("Comms", false, "show connections", m_console.Commands.AddCommand("Comms", false, "show connections",
"show connections", "show connections",
"Show connection data", HandleShow); "Show connection data",
HandleShow);
m_console.Commands.AddCommand("Comms", false, "show circuits", m_console.Commands.AddCommand("Comms", false, "show circuits",
"show circuits", "show circuits",
"Show agent circuit data", HandleShow); "Show agent circuit data",
HandleShow);
m_console.Commands.AddCommand("Comms", false, "show pending-objects", m_console.Commands.AddCommand("Comms", false, "show pending-objects",
"show pending-objects", "show pending-objects",
"Show # of objects on the pending queues of all scene viewers", HandleShow); "Show # of objects on the pending queues of all scene viewers",
HandleShow);
m_console.Commands.AddCommand("General", false, "show modules", m_console.Commands.AddCommand("General", false, "show modules",
"show modules", "show modules",
"Show module data", HandleShow); "Show module data",
HandleShow);
m_console.Commands.AddCommand("Regions", false, "show regions", m_console.Commands.AddCommand("Regions", false, "show regions",
"show regions", "show regions",
"Show region data", HandleShow); "Show region data",
HandleShow);
m_console.Commands.AddCommand("Regions", false, "show ratings", m_console.Commands.AddCommand("Regions", false, "show ratings",
"show ratings", "show ratings",
"Show rating data", HandleShow); "Show rating data",
HandleShow);
m_console.Commands.AddCommand("Objects", false, "backup", m_console.Commands.AddCommand("Objects", false, "backup",
"backup", "backup",
"Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", RunCommand); "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.",
RunCommand);
m_console.Commands.AddCommand("Regions", false, "create region", m_console.Commands.AddCommand("Regions", false, "create region",
"create region [\"region name\"] <region_file.ini>", "create region [\"region name\"] <region_file.ini>",
@ -342,19 +356,23 @@ namespace OpenSim
m_console.Commands.AddCommand("Regions", false, "restart", m_console.Commands.AddCommand("Regions", false, "restart",
"restart", "restart",
"Restart all sims in this instance", RunCommand); "Restart all sims in this instance",
RunCommand);
m_console.Commands.AddCommand("General", false, "command-script", m_console.Commands.AddCommand("General", false, "command-script",
"command-script <script>", "command-script <script>",
"Run a command script from file", RunCommand); "Run a command script from file",
RunCommand);
m_console.Commands.AddCommand("Regions", false, "remove-region", m_console.Commands.AddCommand("Regions", false, "remove-region",
"remove-region <name>", "remove-region <name>",
"Remove a region from this simulator", RunCommand); "Remove a region from this simulator",
RunCommand);
m_console.Commands.AddCommand("Regions", false, "delete-region", m_console.Commands.AddCommand("Regions", false, "delete-region",
"delete-region <name>", "delete-region <name>",
"Delete a region from disk", RunCommand); "Delete a region from disk",
RunCommand);
} }
protected override void ShutdownSpecific() protected override void ShutdownSpecific()
@ -434,7 +452,7 @@ namespace OpenSim
else else
presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n");
presence.Scene.IncomingCloseAgent(presence.UUID, force); presence.Scene.CloseAgent(presence.UUID, force);
break; break;
} }
} }

View File

@ -228,12 +228,18 @@ namespace OpenSim.Region.ClientStack.Linden
lock (queue) lock (queue)
queue.Enqueue(ev); queue.Enqueue(ev);
} }
else else if (DebugLevel > 0)
{ {
OSDMap evMap = (OSDMap)ev; ScenePresence sp = m_scene.GetScenePresence(avatarID);
m_log.WarnFormat(
"[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}", // This assumes that an NPC should never have a queue.
avatarID, evMap["message"], m_scene.Name); if (sp != null && sp.PresenceType != PresenceType.Npc)
{
OSDMap evMap = (OSDMap)ev;
m_log.WarnFormat(
"[EVENTQUEUE]: (Enqueue) No queue found for agent {0} {1} when placing message {2} in region {3}",
sp.Name, sp.UUID, evMap["message"], m_scene.Name);
}
} }
} }
catch (NullReferenceException e) catch (NullReferenceException e)

View File

@ -26,6 +26,7 @@
*/ */
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using log4net.Config; using log4net.Config;
@ -33,11 +34,14 @@ using Nini.Config;
using NUnit.Framework; using NUnit.Framework;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.Packets; using OpenMetaverse.Packets;
using OpenMetaverse.StructuredData;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Servers; using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer; using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.ClientStack.Linden; using OpenSim.Region.ClientStack.Linden;
using OpenSim.Region.CoreModules.Framework; using OpenSim.Region.CoreModules.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.OptionalModules.World.NPC;
using OpenSim.Tests.Common; using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock; using OpenSim.Tests.Common.Mock;
@ -47,6 +51,8 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
public class EventQueueTests : OpenSimTestCase public class EventQueueTests : OpenSimTestCase
{ {
private TestScene m_scene; private TestScene m_scene;
private EventQueueGetModule m_eqgMod;
private NPCModule m_npcMod;
[SetUp] [SetUp]
public override void SetUp() public override void SetUp()
@ -69,14 +75,19 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
config.Configs["Startup"].Set("EventQueue", "true"); config.Configs["Startup"].Set("EventQueue", "true");
CapabilitiesModule capsModule = new CapabilitiesModule(); CapabilitiesModule capsModule = new CapabilitiesModule();
EventQueueGetModule eqgModule = new EventQueueGetModule(); m_eqgMod = new EventQueueGetModule();
// For NPC test support
config.AddConfig("NPC");
config.Configs["NPC"].Set("Enabled", "true");
m_npcMod = new NPCModule();
m_scene = new SceneHelpers().SetupScene(); m_scene = new SceneHelpers().SetupScene();
SceneHelpers.SetupSceneModules(m_scene, config, capsModule, eqgModule); SceneHelpers.SetupSceneModules(m_scene, config, capsModule, m_eqgMod, m_npcMod);
} }
[Test] [Test]
public void AddForClient() public void TestAddForClient()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();
@ -88,7 +99,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
} }
[Test] [Test]
public void RemoveForClient() public void TestRemoveForClient()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
@ -96,10 +107,85 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
UUID spId = TestHelpers.ParseTail(0x1); UUID spId = TestHelpers.ParseTail(0x1);
SceneHelpers.AddScenePresence(m_scene, spId); SceneHelpers.AddScenePresence(m_scene, spId);
m_scene.IncomingCloseAgent(spId, false); m_scene.CloseAgent(spId, false);
// TODO: Add more assertions for the other aspects of event queues // TODO: Add more assertions for the other aspects of event queues
Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
} }
[Test]
public void TestEnqueueMessage()
{
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
string messageName = "TestMessage";
m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), sp.UUID);
Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK));
// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]);
OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]);
OSDArray eventsOsd = (OSDArray)rawOsd["events"];
bool foundUpdate = false;
foreach (OSD osd in eventsOsd)
{
OSDMap eventOsd = (OSDMap)osd;
if (eventOsd["message"] == messageName)
foundUpdate = true;
}
Assert.That(foundUpdate, Is.True, string.Format("Did not find {0} in response", messageName));
}
/// <summary>
/// Test an attempt to put a message on the queue of a user that is not in the region.
/// </summary>
[Test]
public void TestEnqueueMessageNoUser()
{
TestHelpers.InMethod();
TestHelpers.EnableLogging();
string messageName = "TestMessage";
m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), TestHelpers.ParseTail(0x1));
Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, TestHelpers.ParseTail(0x1));
Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
}
/// <summary>
/// NPCs do not currently have an event queue but a caller may try to send a message anyway, so check behaviour.
/// </summary>
[Test]
public void TestEnqueueMessageToNpc()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID npcId
= m_npcMod.CreateNPC(
"John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance());
ScenePresence npc = m_scene.GetScenePresence(npcId);
string messageName = "TestMessage";
m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), npc.UUID);
Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, npc.UUID);
Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
}
} }
} }

View File

@ -63,7 +63,7 @@ namespace OpenSim.Region.ClientStack.Linden
public List<UUID> folders; public List<UUID> folders;
} }
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene; private Scene m_scene;
@ -115,7 +115,7 @@ namespace OpenSim.Region.ClientStack.Linden
m_scene.EventManager.OnRegisterCaps -= RegisterCaps; m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
foreach (Thread t in m_workerThreads) foreach (Thread t in m_workerThreads)
Watchdog.AbortThread(t.ManagedThreadId); Watchdog.AbortThread(t.ManagedThreadId);
m_scene = null; m_scene = null;
} }
@ -296,36 +296,49 @@ namespace OpenSim.Region.ClientStack.Linden
requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
lock (responses) lock (responses)
responses[requestID] = response; responses[requestID] = response;
} }
} }
private void RegisterCaps(UUID agentID, Caps caps) private void RegisterCaps(UUID agentID, Caps caps)
{ {
if (m_fetchInventoryDescendents2Url == "") RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
}
private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url)
{
string capUrl;
// disable the cap clause
if (url == "")
{
return; return;
}
// handled by the simulator
else if (url == "localhost")
{
capUrl = "/CAPS/" + UUID.Random() + "/";
// Register this as a poll service // Register this as a poll service
PollServiceInventoryEventArgs args PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, capUrl, agentID);
= new PollServiceInventoryEventArgs(m_scene, "/CAPS/" + UUID.Random() + "/", agentID); args.Type = PollServiceEventArgs.EventType.Inventory;
args.Type = PollServiceEventArgs.EventType.Inventory;
caps.RegisterPollHandler("FetchInventoryDescendents2", args); caps.RegisterPollHandler(capName, args);
}
// external handler
else
{
capUrl = url;
IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
if (handler != null)
handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl);
else
caps.RegisterHandler(capName, capUrl);
}
// MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); // m_log.DebugFormat(
// // "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}",
// string hostName = m_scene.RegionInfo.ExternalHostName; // capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
// string protocol = "http";
//
// if (MainServer.Instance.UseSSL)
// {
// hostName = MainServer.Instance.SSLCommonName;
// port = MainServer.Instance.SSLPort;
// protocol = "https";
// }
//
// caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
} }
// private void DeregisterCaps(UUID agentID, Caps caps) // private void DeregisterCaps(UUID agentID, Caps caps)

View File

@ -750,7 +750,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public virtual void Start() public virtual void Start()
{ {
m_scene.AddNewClient(this, PresenceType.User); m_scene.AddNewAgent(this, PresenceType.User);
RefreshGroupMembership(); RefreshGroupMembership();
} }
@ -3631,7 +3631,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
// TODO: don't create new blocks if recycling an old packet // TODO: don't create new blocks if recycling an old packet
avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
avp.ObjectData.TextureEntry = textureEntry; avp.ObjectData.TextureEntry = textureEntry;
AvatarAppearancePacket.VisualParamBlock avblock = null; AvatarAppearancePacket.VisualParamBlock avblock = null;

View File

@ -1692,32 +1692,76 @@ namespace OpenSim.Region.ClientStack.LindenUDP
endPoint = (IPEndPoint)array[0]; endPoint = (IPEndPoint)array[0];
CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
m_log.DebugFormat(
"[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name);
// Determine which agent this packet came from // Determine which agent this packet came from
int count = 20; // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
bool ready = false; // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
while (!ready && count-- > 0) // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
// packets asynchronously, we need to account for this thread proceeding more quickly than the
// UseCircuitCode thread.
int count = 40;
while (count-- > 0)
{ {
if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null) if (m_scene.TryGetClient(endPoint, out client))
{ {
LLClientView llClientView = (LLClientView)client; if (!client.IsActive)
LLUDPClient udpClient = llClientView.UDPClient; {
if (udpClient != null && udpClient.IsConnected) // This check exists to catch a condition where the client has been closed by another thread
ready = true; // but has not yet been removed from the client manager (and possibly a new connection has
// not yet been established).
m_log.DebugFormat(
"[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
endPoint, client.Name, m_scene.Name);
}
else if (client.SceneAgent == null)
{
// This check exists to catch a condition where the new client has been added to the client
// manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
// eager, then the new ScenePresence may not have registered a listener for this messsage
// before we try to process it.
// XXX: A better long term fix may be to add the SceneAgent before the client is added to
// the client manager
m_log.DebugFormat(
"[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
endPoint, client.Name, m_scene.Name);
}
else else
{ {
m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); break;
Thread.Sleep(200);
} }
} }
else else
{ {
m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); m_log.DebugFormat(
Thread.Sleep(200); "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
endPoint, m_scene.Name);
} }
Thread.Sleep(200);
} }
if (client == null) if (client == null)
{
m_log.DebugFormat(
"[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
endPoint, m_scene.Name);
return; return;
}
else if (!client.IsActive || client.SceneAgent == null)
{
// This check exists to catch a condition where the client has been closed by another thread
// but has not yet been removed from the client manager.
// The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
// purposes.
m_log.DebugFormat(
"[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
endPoint, client.Name, m_scene.Name);
return;
}
IncomingPacket incomingPacket1; IncomingPacket incomingPacket1;
@ -1738,7 +1782,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
catch (Exception e) catch (Exception e)
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
endPoint != null ? endPoint.ToString() : "n/a", endPoint != null ? endPoint.ToString() : "n/a",
client != null ? client.Name : "unknown", client != null ? client.Name : "unknown",
client != null ? client.AgentId.ToString() : "unknown", client != null ? client.AgentId.ToString() : "unknown",
@ -1849,7 +1893,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
client.Kick("Simulator logged you out due to connection timeout."); client.Kick("Simulator logged you out due to connection timeout.");
} }
m_scene.IncomingCloseAgent(client.AgentId, true); m_scene.CloseAgent(client.AgentId, true);
} }
private void IncomingPacketHandler() private void IncomingPacketHandler()
@ -2190,7 +2234,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!client.IsLoggingOut) if (!client.IsLoggingOut)
{ {
client.IsLoggingOut = true; client.IsLoggingOut = true;
m_scene.IncomingCloseAgent(client.AgentId, false); m_scene.CloseAgent(client.AgentId, false);
} }
} }
} }

View File

@ -295,7 +295,16 @@ namespace OpenMetaverse
m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
} }
} }
catch (ObjectDisposedException) { } catch (ObjectDisposedException e)
{
m_log.Error(
string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
}
catch (Exception e)
{
m_log.Error(
string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
}
} }
} }
@ -312,12 +321,12 @@ namespace OpenMetaverse
if (m_asyncPacketHandling) if (m_asyncPacketHandling)
AsyncBeginReceive(); AsyncBeginReceive();
// get the buffer that was created in AsyncBeginReceive
// this is the received data
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
try try
{ {
// get the buffer that was created in AsyncBeginReceive
// this is the received data
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
int startTick = Util.EnvironmentTickCount(); int startTick = Util.EnvironmentTickCount();
// get the length of data actually read from the socket, store it with the // get the length of data actually read from the socket, store it with the
@ -345,8 +354,24 @@ namespace OpenMetaverse
m_currentReceiveTimeSamples++; m_currentReceiveTimeSamples++;
} }
} }
catch (SocketException) { } catch (SocketException se)
catch (ObjectDisposedException) { } {
m_log.Error(
string.Format(
"[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
UdpReceives, se.ErrorCode),
se);
}
catch (ObjectDisposedException e)
{
m_log.Error(
string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
}
catch (Exception e)
{
m_log.Error(
string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
}
finally finally
{ {
// if (UsePools) // if (UsePools)

View File

@ -52,17 +52,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
public override void Update(int frames) {} public override void Update(int frames) {}
public override void LoadWorldMap() {} public override void LoadWorldMap() {}
public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
{ {
client.OnObjectName += RecordObjectNameCall; client.OnObjectName += RecordObjectNameCall;
// FIXME // FIXME
return null; return null;
} }
public override void RemoveClient(UUID agentID, bool someReason) {} public override bool CloseAgent(UUID agentID, bool force) { return true; }
// public override void CloseAllAgents(uint circuitcode) {}
public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; } public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
public override void OtherRegionUp(GridRegion otherRegion) { } public override void OtherRegionUp(GridRegion otherRegion) { }
public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; } public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }

View File

@ -719,7 +719,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
m_numberOfAttachEventsFired = 0; m_numberOfAttachEventsFired = 0;
scene.IncomingCloseAgent(presence.UUID, false); scene.CloseAgent(presence.UUID, false);
// Check that we can't retrieve this attachment from the scene. // Check that we can't retrieve this attachment from the scene.
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);

View File

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

View File

@ -272,7 +272,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
if (sp.IsChildAgent) if (sp.IsChildAgent)
return; return;
sp.ControllingClient.Kick(reason); sp.ControllingClient.Kick(reason);
sp.Scene.IncomingCloseAgent(sp.UUID, true); sp.Scene.CloseAgent(sp.UUID, true);
} }
private void OnIncomingInstantMessage(GridInstantMessage msg) private void OnIncomingInstantMessage(GridInstantMessage msg)

View File

@ -536,7 +536,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
} }
catch (Exception e) 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; return null;
} }
} }

View File

@ -149,8 +149,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
private void OnInstantMessage(IClientAPI client, GridInstantMessage im) private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[INVENTORY TRANSFER]: {0} IM type received from {1}", // "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}",
// (InstantMessageDialog)im.dialog, client.Name); // (InstantMessageDialog)im.dialog, client.Name,
// im.fromAgentID, im.fromAgentName, im.toAgentID);
Scene scene = FindClientScene(client.AgentId); Scene scene = FindClientScene(client.AgentId);
@ -450,23 +451,57 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="msg"></param> /// <param name="im"></param>
private void OnGridInstantMessage(GridInstantMessage msg) private void OnGridInstantMessage(GridInstantMessage im)
{ {
// Check if it's a type of message that we should handle
if (!((im.dialog == (byte) InstantMessageDialog.InventoryOffered)
|| (im.dialog == (byte) InstantMessageDialog.InventoryAccepted)
|| (im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
|| (im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined)))
return;
m_log.DebugFormat(
"[INVENTORY TRANSFER]: {0} IM type received from grid. From={1} ({2}), To={3}",
(InstantMessageDialog)im.dialog, im.fromAgentID, im.fromAgentName, im.toAgentID);
// Check if this is ours to handle // Check if this is ours to handle
// //
Scene scene = FindClientScene(new UUID(msg.toAgentID)); Scene scene = FindClientScene(new UUID(im.toAgentID));
if (scene == null) if (scene == null)
return; return;
// Find agent to deliver to // Find agent to deliver to
// //
ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID)); ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
// Just forward to local handling if (user != null)
OnInstantMessage(user.ControllingClient, msg); {
user.ControllingClient.SendInstantMessage(im);
if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
{
AssetType assetType = (AssetType)im.binaryBucket[0];
UUID inventoryID = new UUID(im.binaryBucket, 1);
IInventoryService invService = scene.InventoryService;
InventoryNodeBase node = null;
if (AssetType.Folder == assetType)
{
InventoryFolderBase folder = new InventoryFolderBase(inventoryID, new UUID(im.toAgentID));
node = invService.GetFolder(folder);
}
else
{
InventoryItemBase item = new InventoryItemBase(inventoryID, new UUID(im.toAgentID));
node = invService.GetItem(item);
}
if (node != null)
user.ControllingClient.SendBulkUpdateInventory(node);
}
}
} }
} }
} }

View File

@ -165,7 +165,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
(uint)presence.AbsolutePosition.Y, (uint)presence.AbsolutePosition.Y,
(uint)Math.Ceiling(presence.AbsolutePosition.Z)); (uint)Math.Ceiling(presence.AbsolutePosition.Z));
m_log.DebugFormat("TP invite with message {0}, type {1}", message, lureType); m_log.DebugFormat("[LURE MODULE]: TP invite with message {0}, type {1}", message, lureType);
GridInstantMessage m = new GridInstantMessage(scene, client.AgentId, GridInstantMessage m = new GridInstantMessage(scene, client.AgentId,
client.FirstName+" "+client.LastName, targetid, client.FirstName+" "+client.LastName, targetid,

View File

@ -270,6 +270,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
// Notes // Notes
client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest); client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest);
client.OnAvatarNotesUpdate += NotesUpdate; client.OnAvatarNotesUpdate += NotesUpdate;
// Preferences
client.OnUserInfoRequest += UserPreferencesRequest;
client.OnUpdateUserInfo += UpdateUserPreferences;
} }
#endregion Region Event Handlers #endregion Region Event Handlers
@ -756,8 +760,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
IClientAPI remoteClient = (IClientAPI)sender; IClientAPI remoteClient = (IClientAPI)sender;
string serverURI = string.Empty; string serverURI = string.Empty;
GetUserProfileServerURI(remoteClient.AgentId, out serverURI); GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
note.TargetId = remoteClient.AgentId; note.UserId = remoteClient.AgentId;
UUID.TryParse(args[0], out note.UserId); UUID.TryParse(args[0], out note.TargetId);
object Note = (object)note; object Note = (object)note;
if(!JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString())) if(!JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString()))
@ -802,6 +806,69 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
} }
#endregion Notes #endregion Notes
#region User Preferences
/// <summary>
/// Updates the user preferences.
/// </summary>
/// <param name='imViaEmail'>
/// Im via email.
/// </param>
/// <param name='visible'>
/// Visible.
/// </param>
/// <param name='remoteClient'>
/// Remote client.
/// </param>
public void UpdateUserPreferences(bool imViaEmail, bool visible, IClientAPI remoteClient)
{
UserPreferences pref = new UserPreferences();
pref.UserId = remoteClient.AgentId;
pref.IMViaEmail = imViaEmail;
pref.Visible = visible;
string serverURI = string.Empty;
bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
object Pref = pref;
if(!JsonRpcRequest(ref Pref, "user_preferences_update", serverURI, UUID.Random().ToString()))
{
m_log.InfoFormat("[PROFILES]: UserPreferences update error");
remoteClient.SendAgentAlertMessage("Error updating preferences", false);
return;
}
}
/// <summary>
/// Users the preferences request.
/// </summary>
/// <param name='remoteClient'>
/// Remote client.
/// </param>
public void UserPreferencesRequest(IClientAPI remoteClient)
{
UserPreferences pref = new UserPreferences();
pref.UserId = remoteClient.AgentId;
string serverURI = string.Empty;
bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI);
object Pref = (object)pref;
if(!JsonRpcRequest(ref Pref, "user_preferences_request", serverURI, UUID.Random().ToString()))
{
m_log.InfoFormat("[PROFILES]: UserPreferences request error");
remoteClient.SendAgentAlertMessage("Error requesting preferences", false);
return;
}
pref = (UserPreferences) Pref;
remoteClient.SendUserInfoReply(pref.IMViaEmail, pref.Visible, pref.EMail);
}
#endregion User Preferences
#region Avatar Properties #region Avatar Properties
/// <summary> /// <summary>
/// Update the avatars interests . /// Update the avatars interests .

View File

@ -56,6 +56,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
public const int DefaultMaxTransferDistance = 4095; public const int DefaultMaxTransferDistance = 4095;
public const bool WaitForAgentArrivedAtDestinationDefault = true; public const bool WaitForAgentArrivedAtDestinationDefault = true;
public string OutgoingTransferVersionName { get; set; }
/// <summary>
/// Determine the maximum entity transfer version we will use for teleports.
/// </summary>
public float MaxOutgoingTransferVersion { get; set; }
/// <summary> /// <summary>
/// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer.
/// </summary> /// </summary>
@ -151,9 +158,39 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// <param name="source"></param> /// <param name="source"></param>
protected virtual void InitialiseCommon(IConfigSource source) protected virtual void InitialiseCommon(IConfigSource source)
{ {
string transferVersionName = "SIMULATION";
float maxTransferVersion = 0.2f;
IConfig transferConfig = source.Configs["EntityTransfer"]; IConfig transferConfig = source.Configs["EntityTransfer"];
if (transferConfig != null) if (transferConfig != null)
{ {
string rawVersion
= transferConfig.GetString(
"MaxOutgoingTransferVersion",
string.Format("{0}/{1}", transferVersionName, maxTransferVersion));
string[] rawVersionComponents = rawVersion.Split(new char[] { '/' });
bool versionValid = false;
if (rawVersionComponents.Length >= 2)
versionValid = float.TryParse(rawVersionComponents[1], out maxTransferVersion);
if (!versionValid)
{
m_log.ErrorFormat(
"[ENTITY TRANSFER MODULE]: MaxOutgoingTransferVersion {0} is invalid, using {1}",
rawVersion, string.Format("{0}/{1}", transferVersionName, maxTransferVersion));
}
else
{
transferVersionName = rawVersionComponents[0];
m_log.InfoFormat(
"[ENTITY TRANSFER MODULE]: MaxOutgoingTransferVersion set to {0}",
string.Format("{0}/{1}", transferVersionName, maxTransferVersion));
}
DisableInterRegionTeleportCancellation DisableInterRegionTeleportCancellation
= transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
@ -167,6 +204,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
MaxTransferDistance = DefaultMaxTransferDistance; MaxTransferDistance = DefaultMaxTransferDistance;
} }
OutgoingTransferVersionName = transferVersionName;
MaxOutgoingTransferVersion = maxTransferVersion;
m_entityTransferStateMachine = new EntityTransferStateMachine(this); m_entityTransferStateMachine = new EntityTransferStateMachine(this);
m_Enabled = true; m_Enabled = true;
@ -518,6 +558,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// </returns> /// </returns>
private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion)
{ {
if(MaxTransferDistance == 0)
return true;
// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY);
// //
// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}",
@ -620,7 +663,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (!sp.ValidateAttachments()) if (!sp.ValidateAttachments())
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); sp.Name, sp.Scene.Name, finalDestination.RegionName);
string reason; string reason;
string version; string version;
@ -631,7 +674,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}",
sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); sp.Name, sp.Scene.Name, finalDestination.RegionName, reason);
return; return;
} }
@ -641,7 +684,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// as server attempts. // as server attempts.
m_interRegionTeleportAttempts.Value++; m_interRegionTeleportAttempts.Value++;
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: {0} max transfer version is {1}/{2}, {3} max version is {4}",
sp.Scene.Name, OutgoingTransferVersionName, MaxOutgoingTransferVersion, finalDestination.RegionName, version);
// Fixing a bug where teleporting while sitting results in the avatar ending up removed from // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
// both regions // both regions
@ -686,7 +731,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
} }
if (version.Equals("SIMULATION/0.2")) // We're going to fallback to V1 if the destination gives us anything smaller than 0.2 or we're forcing
// use of the earlier protocol
float versionNumber = 0.1f;
string[] versionComponents = version.Split(new char[] { '/' });
if (versionComponents.Length >= 2)
float.TryParse(versionComponents[1], out versionNumber);
if (versionNumber == 0.2f && MaxOutgoingTransferVersion >= versionNumber)
TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason);
else else
TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason);
@ -832,8 +884,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
} }
m_log.WarnFormat( m_log.WarnFormat(
"[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); sp.Name, finalDestination.RegionName, sp.Scene.Name);
Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
return; return;
@ -920,6 +972,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
{ {
if (!sp.Scene.IncomingPreCloseClient(sp))
return;
// We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before
// they regard the new region as the current region after receiving the AgentMovementComplete // they regard the new region as the current region after receiving the AgentMovementComplete
// response. If close is sent before then, it will cause the viewer to quit instead. // response. If close is sent before then, it will cause the viewer to quit instead.
@ -928,7 +983,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// an agent cannot teleport back to this region if it has teleported away. // an agent cannot teleport back to this region if it has teleported away.
Thread.Sleep(2000); Thread.Sleep(2000);
sp.Scene.IncomingCloseAgent(sp.UUID, false); sp.Scene.CloseAgent(sp.UUID, false);
} }
else else
{ {
@ -1053,8 +1108,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
} }
m_log.WarnFormat( m_log.WarnFormat(
"[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}",
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); sp.Name, finalDestination.RegionName, sp.Scene.Name);
Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established.");
return; return;
@ -1082,6 +1137,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
{ {
if (!sp.Scene.IncomingPreCloseClient(sp))
return;
// RED ALERT!!!! // RED ALERT!!!!
// PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES.
// THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion
@ -1095,7 +1153,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// then this will be handled in IncomingCloseAgent under lock conditions // then this will be handled in IncomingCloseAgent under lock conditions
m_log.DebugFormat( m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name);
sp.Scene.IncomingCloseAgent(sp.UUID, false);
sp.Scene.CloseAgent(sp.UUID, false);
} }
else else
{ {

View File

@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
{ {
string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); string url = aCircuit.ServiceURLs["AssetServerURI"].ToString();
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url);
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>(); Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
HGUuidGatherer uuidGatherer = new HGUuidGatherer(Scene.AssetService, url); HGUuidGatherer uuidGatherer = new HGUuidGatherer(Scene.AssetService, url);
uuidGatherer.GatherAssetUuids(so, ids); uuidGatherer.GatherAssetUuids(so, ids);

View File

@ -178,17 +178,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate
{ {
//m_log.DebugFormat("[YYY]: Name request {0}", uuid); //m_log.DebugFormat("[YYY]: Name request {0}", uuid);
bool foundRealName = TryGetUserNames(uuid, names);
if (names.Length == 2)
{
if (!foundRealName)
m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, client.Name);
// As least upto September 2013, clients permanently cache UUID -> Name bindings. Some clients
// appear to clear this when the user asks it to clear the cache, but others may not.
//
// So to avoid clients
// (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will
// instead drop the request entirely.
if (TryGetUserNames(uuid, names))
client.SendNameReply(uuid, names[0], names[1]); client.SendNameReply(uuid, names[0], names[1]);
} // else
// m_log.DebugFormat(
// "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}",
// uuid, client.Name);
}); });
} }
} }
@ -391,7 +394,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
} }
names[0] = "Unknown"; names[0] = "Unknown";
names[1] = "UserUMMTGUN8"; names[1] = "UserUMMTGUN9";
return false; return false;
} }
@ -481,14 +484,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
public string GetUserUUI(UUID userID) public string GetUserUUI(UUID userID)
{ {
UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, userID);
if (account != null)
return userID.ToString();
UserData ud; UserData ud;
lock (m_UserCache) lock (m_UserCache)
m_UserCache.TryGetValue(userID, out ud); m_UserCache.TryGetValue(userID, out ud);
if (ud == null) // It's not in the cache
{
string[] names = new string[2];
// This will pull the data from either UserAccounts or GridUser
// and stick it into the cache
TryGetUserNamesFromServices(userID, names);
lock (m_UserCache)
m_UserCache.TryGetValue(userID, out ud);
}
if (ud != null) if (ud != null)
{ {
string homeURL = ud.HomeURL; string homeURL = ud.HomeURL;
@ -533,7 +542,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
AddUser(uuid, homeURL + ";" + first + " " + last); AddUser(uuid, homeURL + ";" + first + " " + last);
} }
public void AddUser (UUID id, string creatorData) public void AddUser(UUID id, string creatorData)
{ {
//m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData);
@ -593,6 +602,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
user.LastName = "@unknown"; user.LastName = "@unknown";
} }
} }
if (parts.Length >= 2) if (parts.Length >= 2)
user.FirstName = parts[1].Replace(' ', '.'); user.FirstName = parts[1].Replace(' ', '.');
} }
@ -605,7 +615,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
user.FirstName = "Unknown"; user.FirstName = "Unknown";
user.LastName = "UserUMMAU4"; user.LastName = "UserUMMAU4";
} }
AddUserInternal(user); AddUserInternal(user);
} }
} }
@ -633,6 +643,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
protected void Init() protected void Init()
{ {
AddUser(UUID.Zero, "Unknown", "User");
RegisterConsoleCmds(); RegisterConsoleCmds();
} }

View File

@ -129,7 +129,7 @@ namespace OpenSim.Region.CoreModules.Hypergrid
b.Access = 254; // means 'simulator is offline'. We need this because the viewer ignores 255's b.Access = 254; // means 'simulator is offline'. We need this because the viewer ignores 255's
} }
m_log.DebugFormat("[HG MAP]: Reseting {0} blocks", mapBlocks.Count); m_log.DebugFormat("[HG MAP]: Resetting {0} blocks", mapBlocks.Count);
sp.ControllingClient.SendMapBlock(mapBlocks, 0); sp.ControllingClient.SendMapBlock(mapBlocks, 0);
m_SeenMapBlocks.Remove(clientID); m_SeenMapBlocks.Remove(clientID);
} }

View File

@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
string dtText string dtText
= "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://0.0.0.0/shouldnotexist.png";
SetupScene(false); SetupScene(false);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
@ -307,7 +307,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
TestHelpers.InMethod(); TestHelpers.InMethod();
string dtText string dtText
= "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://localhost/shouldnotexist.png"; = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World; Image http://0.0.0.0/shouldnotexist.png";
SetupScene(true); SetupScene(true);
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene); SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);

View File

@ -153,6 +153,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile
Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest); Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest);
Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate); Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate);
Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate); Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate);
Server.AddJsonRPCHandler("user_preferences_update", handler.UserPreferenecesUpdate);
Server.AddJsonRPCHandler("user_preferences_request", handler.UserPreferencesRequest);
Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest); Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest);
Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData); Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData);
Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData);

View File

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

View File

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

View File

@ -94,7 +94,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
throw new Exception(string.Format("Invalid ConnectorProtocolVersion {0}", ServiceVersion)); throw new Exception(string.Format("Invalid ConnectorProtocolVersion {0}", ServiceVersion));
m_log.InfoFormat( m_log.InfoFormat(
"[LOCAL SIMULATION CONNECTOR]: Initialzied with connector protocol version {0}", ServiceVersion); "[LOCAL SIMULATION CONNECTOR]: Initialized with connector protocol version {0}", ServiceVersion);
} }
} }
@ -235,7 +235,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
// destination.RegionName, destination.RegionID); // destination.RegionName, destination.RegionID);
return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData); return m_scenes[destination.RegionID].IncomingUpdateChildAgent(cAgentData);
} }
// m_log.DebugFormat( // m_log.DebugFormat(
@ -245,7 +245,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
return false; return false;
} }
public bool UpdateAgent(GridRegion destination, AgentPosition cAgentData) public bool UpdateAgent(GridRegion destination, AgentPosition agentPosition)
{ {
if (destination == null) if (destination == null)
return false; return false;
@ -257,7 +257,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
foreach (Scene s in m_scenes.Values) foreach (Scene s in m_scenes.Values)
{ {
// m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); // m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
s.IncomingChildAgentDataUpdate(cAgentData); s.IncomingUpdateChildAgent(agentPosition);
} }
//m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate"); //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate");
@ -311,7 +311,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
// s.RegionInfo.RegionName, destination.RegionHandle); // s.RegionInfo.RegionName, destination.RegionHandle);
m_scenes[destination.RegionID].IncomingCloseAgent(id, false, auth_token); m_scenes[destination.RegionID].CloseAgent(id, false, auth_token);
return true; return true;
} }

View File

@ -60,7 +60,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
public void Initialise() public void Initialise()
{ {
m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName); // m_log.DebugFormat("[ESTATE MODULE]: Setting up estate commands for region {0}", m_module.Scene.RegionInfo.RegionName);
m_module.Scene.AddCommand("Regions", m_module, "set terrain texture", m_module.Scene.AddCommand("Regions", m_module, "set terrain texture",
"set terrain texture <number> <uuid> [<x>] [<y>]", "set terrain texture <number> <uuid> [<x>] [<y>]",

View File

@ -562,7 +562,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
if (!Scene.TeleportClientHome(user, s.ControllingClient)) if (!Scene.TeleportClientHome(user, s.ControllingClient))
{ {
s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
Scene.IncomingCloseAgent(s.UUID, false); Scene.CloseAgent(s.UUID, false);
} }
} }
} }
@ -702,7 +702,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
} }
} }
public void handleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1) public void HandleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
{ {
SceneObjectPart part; SceneObjectPart part;
@ -742,7 +742,9 @@ namespace OpenSim.Region.CoreModules.World.Estate
default: default:
break; break;
} }
SendTelehubInfo(client);
if (client != null)
SendTelehubInfo(client);
} }
private void SendSimulatorBlueBoxMessage( private void SendSimulatorBlueBoxMessage(
@ -797,7 +799,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
if (!Scene.TeleportClientHome(prey, s.ControllingClient)) if (!Scene.TeleportClientHome(prey, s.ControllingClient))
{ {
s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
Scene.IncomingCloseAgent(s.UUID, false); Scene.CloseAgent(s.UUID, false);
} }
} }
} }
@ -820,7 +822,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient)) if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient))
{ {
p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
Scene.IncomingCloseAgent(p.UUID, false); Scene.CloseAgent(p.UUID, false);
} }
} }
} }
@ -1207,7 +1209,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
client.OnEstateRestartSimRequest += handleEstateRestartSimRequest; client.OnEstateRestartSimRequest += handleEstateRestartSimRequest;
client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest; client.OnEstateChangeCovenantRequest += handleChangeEstateCovenantRequest;
client.OnEstateChangeInfo += handleEstateChangeInfo; client.OnEstateChangeInfo += handleEstateChangeInfo;
client.OnEstateManageTelehub += handleOnEstateManageTelehub; client.OnEstateManageTelehub += HandleOnEstateManageTelehub;
client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest; client.OnUpdateEstateAccessDeltaRequest += handleEstateAccessDeltaRequest;
client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage; client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage;
client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage; client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage;

View File

@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
public struct DrawStruct public struct DrawStruct
{ {
public DrawRoutine dr; public DrawRoutine dr;
public Rectangle rect; // public Rectangle rect;
public SolidBrush brush; public SolidBrush brush;
public face[] trns; public face[] trns;
} }
@ -119,6 +119,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
{ {
mapbmp = FetchTexture(m_scene.RegionInfo.RegionSettings.TerrainImageID); mapbmp = FetchTexture(m_scene.RegionInfo.RegionSettings.TerrainImageID);
} }
return mapbmp; return mapbmp;
} }
@ -127,7 +128,10 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
try try
{ {
using (Bitmap mapbmp = CreateMapTile()) using (Bitmap mapbmp = CreateMapTile())
return OpenJPEG.EncodeFromImage(mapbmp, true); {
if (mapbmp != null)
return OpenJPEG.EncodeFromImage(mapbmp, true);
}
} }
catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke catch (Exception e) // LEGIT: Catching problems caused by OpenJPEG p/invoke
{ {
@ -277,321 +281,331 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
tc = Environment.TickCount; tc = Environment.TickCount;
m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
EntityBase[] objs = whichScene.GetEntities(); EntityBase[] objs = whichScene.GetEntities();
Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>();
//SortedList<float, RectangleDrawStruct> z_sort = new SortedList<float, RectangleDrawStruct>();
List<float> z_sortheights = new List<float>(); List<float> z_sortheights = new List<float>();
List<uint> z_localIDs = new List<uint>(); List<uint> z_localIDs = new List<uint>();
Dictionary<uint, DrawStruct> z_sort = new Dictionary<uint, DrawStruct>();
lock (objs) try
{ {
foreach (EntityBase obj in objs) //SortedList<float, RectangleDrawStruct> z_sort = new SortedList<float, RectangleDrawStruct>();
lock (objs)
{ {
// Only draw the contents of SceneObjectGroup foreach (EntityBase obj in objs)
if (obj is SceneObjectGroup)
{ {
SceneObjectGroup mapdot = (SceneObjectGroup)obj; // Only draw the contents of SceneObjectGroup
Color mapdotspot = Color.Gray; // Default color when prim color is white if (obj is SceneObjectGroup)
// Loop over prim in group
foreach (SceneObjectPart part in mapdot.Parts)
{ {
if (part == null) SceneObjectGroup mapdot = (SceneObjectGroup)obj;
continue; Color mapdotspot = Color.Gray; // Default color when prim color is white
// Draw if the object is at least 1 meter wide in any direction // Loop over prim in group
if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f) foreach (SceneObjectPart part in mapdot.Parts)
{ {
// Try to get the RGBA of the default texture entry.. if (part == null)
//
try
{
// get the null checks out of the way
// skip the ones that break
if (part == null)
continue;
if (part.Shape == null)
continue;
if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass)
continue; // eliminates trees from this since we don't really have a good tree representation
// if you want tree blocks on the map comment the above line and uncomment the below line
//mapdotspot = Color.PaleGreen;
Primitive.TextureEntry textureEntry = part.Shape.Textures;
if (textureEntry == null || textureEntry.DefaultTexture == null)
continue;
Color4 texcolor = textureEntry.DefaultTexture.RGBA;
// Not sure why some of these are null, oh well.
int colorr = 255 - (int)(texcolor.R * 255f);
int colorg = 255 - (int)(texcolor.G * 255f);
int colorb = 255 - (int)(texcolor.B * 255f);
if (!(colorr == 255 && colorg == 255 && colorb == 255))
{
//Try to set the map spot color
try
{
// If the color gets goofy somehow, skip it *shakes fist at Color4
mapdotspot = Color.FromArgb(colorr, colorg, colorb);
}
catch (ArgumentException)
{
}
}
}
catch (IndexOutOfRangeException)
{
// Windows Array
}
catch (ArgumentOutOfRangeException)
{
// Mono Array
}
Vector3 pos = part.GetWorldPosition();
// skip prim outside of retion
if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
continue; continue;
// skip prim in non-finite position // Draw if the object is at least 1 meter wide in any direction
if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) || if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
continue;
// Figure out if object is under 256m above the height of the terrain
bool isBelow256AboveTerrain = false;
try
{ {
isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f)); // Try to get the RGBA of the default texture entry..
} //
catch (Exception) try
{
}
if (isBelow256AboveTerrain)
{
// Translate scale by rotation so scale is represented properly when object is rotated
Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
Vector3 scale = new Vector3();
Vector3 tScale = new Vector3();
Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z);
Quaternion llrot = part.GetWorldRotation();
Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
scale = lscale * rot;
// negative scales don't work in this situation
scale.X = Math.Abs(scale.X);
scale.Y = Math.Abs(scale.Y);
scale.Z = Math.Abs(scale.Z);
// This scaling isn't very accurate and doesn't take into account the face rotation :P
int mapdrawstartX = (int)(pos.X - scale.X);
int mapdrawstartY = (int)(pos.Y - scale.Y);
int mapdrawendX = (int)(pos.X + scale.X);
int mapdrawendY = (int)(pos.Y + scale.Y);
// If object is beyond the edge of the map, don't draw it to avoid errors
if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1)
|| mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0
|| mapdrawendY > ((int)Constants.RegionSize - 1))
continue;
#region obb face reconstruction part duex
Vector3[] vertexes = new Vector3[8];
// float[] distance = new float[6];
Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
scale = ((tScale * rot));
vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[0].x = pos.X + vertexes[0].x;
//vertexes[0].y = pos.Y + vertexes[0].y;
//vertexes[0].z = pos.Z + vertexes[0].z;
FaceA[0] = vertexes[0];
FaceB[3] = vertexes[0];
FaceA[4] = vertexes[0];
tScale = lscale;
scale = ((tScale * rot));
vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[1].x = pos.X + vertexes[1].x;
// vertexes[1].y = pos.Y + vertexes[1].y;
//vertexes[1].z = pos.Z + vertexes[1].z;
FaceB[0] = vertexes[1];
FaceA[1] = vertexes[1];
FaceC[4] = vertexes[1];
tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
scale = ((tScale * rot));
vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
//vertexes[2].x = pos.X + vertexes[2].x;
//vertexes[2].y = pos.Y + vertexes[2].y;
//vertexes[2].z = pos.Z + vertexes[2].z;
FaceC[0] = vertexes[2];
FaceD[3] = vertexes[2];
FaceC[5] = vertexes[2];
tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
scale = ((tScale * rot));
vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
//vertexes[3].x = pos.X + vertexes[3].x;
// vertexes[3].y = pos.Y + vertexes[3].y;
// vertexes[3].z = pos.Z + vertexes[3].z;
FaceD[0] = vertexes[3];
FaceC[1] = vertexes[3];
FaceA[5] = vertexes[3];
tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
scale = ((tScale * rot));
vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[4].x = pos.X + vertexes[4].x;
// vertexes[4].y = pos.Y + vertexes[4].y;
// vertexes[4].z = pos.Z + vertexes[4].z;
FaceB[1] = vertexes[4];
FaceA[2] = vertexes[4];
FaceD[4] = vertexes[4];
tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
scale = ((tScale * rot));
vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[5].x = pos.X + vertexes[5].x;
// vertexes[5].y = pos.Y + vertexes[5].y;
// vertexes[5].z = pos.Z + vertexes[5].z;
FaceD[1] = vertexes[5];
FaceC[2] = vertexes[5];
FaceB[5] = vertexes[5];
tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
scale = ((tScale * rot));
vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[6].x = pos.X + vertexes[6].x;
// vertexes[6].y = pos.Y + vertexes[6].y;
// vertexes[6].z = pos.Z + vertexes[6].z;
FaceB[2] = vertexes[6];
FaceA[3] = vertexes[6];
FaceB[4] = vertexes[6];
tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z);
scale = ((tScale * rot));
vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[7].x = pos.X + vertexes[7].x;
// vertexes[7].y = pos.Y + vertexes[7].y;
// vertexes[7].z = pos.Z + vertexes[7].z;
FaceD[2] = vertexes[7];
FaceC[3] = vertexes[7];
FaceD[5] = vertexes[7];
#endregion
//int wy = 0;
//bool breakYN = false; // If we run into an error drawing, break out of the
// loop so we don't lag to death on error handling
DrawStruct ds = new DrawStruct();
ds.brush = new SolidBrush(mapdotspot);
//ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY);
ds.trns = new face[FaceA.Length];
for (int i = 0; i < FaceA.Length; i++)
{ {
Point[] working = new Point[5]; // get the null checks out of the way
working[0] = project(FaceA[i], axPos); // skip the ones that break
working[1] = project(FaceB[i], axPos); if (part == null)
working[2] = project(FaceD[i], axPos); continue;
working[3] = project(FaceC[i], axPos);
working[4] = project(FaceA[i], axPos);
face workingface = new face(); if (part.Shape == null)
workingface.pts = working; continue;
ds.trns[i] = workingface; if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Grass)
continue; // eliminates trees from this since we don't really have a good tree representation
// if you want tree blocks on the map comment the above line and uncomment the below line
//mapdotspot = Color.PaleGreen;
Primitive.TextureEntry textureEntry = part.Shape.Textures;
if (textureEntry == null || textureEntry.DefaultTexture == null)
continue;
Color4 texcolor = textureEntry.DefaultTexture.RGBA;
// Not sure why some of these are null, oh well.
int colorr = 255 - (int)(texcolor.R * 255f);
int colorg = 255 - (int)(texcolor.G * 255f);
int colorb = 255 - (int)(texcolor.B * 255f);
if (!(colorr == 255 && colorg == 255 && colorb == 255))
{
//Try to set the map spot color
try
{
// If the color gets goofy somehow, skip it *shakes fist at Color4
mapdotspot = Color.FromArgb(colorr, colorg, colorb);
}
catch (ArgumentException)
{
}
}
}
catch (IndexOutOfRangeException)
{
// Windows Array
}
catch (ArgumentOutOfRangeException)
{
// Mono Array
} }
z_sort.Add(part.LocalId, ds); Vector3 pos = part.GetWorldPosition();
z_localIDs.Add(part.LocalId);
z_sortheights.Add(pos.Z);
//for (int wx = mapdrawstartX; wx < mapdrawendX; wx++) // skip prim outside of retion
//{ if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
//for (wy = mapdrawstartY; wy < mapdrawendY; wy++) continue;
// skip prim in non-finite position
if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) ||
Single.IsInfinity(pos.X) || Single.IsInfinity(pos.Y))
continue;
// Figure out if object is under 256m above the height of the terrain
bool isBelow256AboveTerrain = false;
try
{
isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
}
catch (Exception)
{
}
if (isBelow256AboveTerrain)
{
// Translate scale by rotation so scale is represented properly when object is rotated
Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
Vector3 scale = new Vector3();
Vector3 tScale = new Vector3();
Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z);
Quaternion llrot = part.GetWorldRotation();
Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
scale = lscale * rot;
// negative scales don't work in this situation
scale.X = Math.Abs(scale.X);
scale.Y = Math.Abs(scale.Y);
scale.Z = Math.Abs(scale.Z);
// This scaling isn't very accurate and doesn't take into account the face rotation :P
int mapdrawstartX = (int)(pos.X - scale.X);
int mapdrawstartY = (int)(pos.Y - scale.Y);
int mapdrawendX = (int)(pos.X + scale.X);
int mapdrawendY = (int)(pos.Y + scale.Y);
// If object is beyond the edge of the map, don't draw it to avoid errors
if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1)
|| mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0
|| mapdrawendY > ((int)Constants.RegionSize - 1))
continue;
#region obb face reconstruction part duex
Vector3[] vertexes = new Vector3[8];
// float[] distance = new float[6];
Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
tScale = new Vector3(lscale.X, -lscale.Y, lscale.Z);
scale = ((tScale * rot));
vertexes[0] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[0].x = pos.X + vertexes[0].x;
//vertexes[0].y = pos.Y + vertexes[0].y;
//vertexes[0].z = pos.Z + vertexes[0].z;
FaceA[0] = vertexes[0];
FaceB[3] = vertexes[0];
FaceA[4] = vertexes[0];
tScale = lscale;
scale = ((tScale * rot));
vertexes[1] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[1].x = pos.X + vertexes[1].x;
// vertexes[1].y = pos.Y + vertexes[1].y;
//vertexes[1].z = pos.Z + vertexes[1].z;
FaceB[0] = vertexes[1];
FaceA[1] = vertexes[1];
FaceC[4] = vertexes[1];
tScale = new Vector3(lscale.X, -lscale.Y, -lscale.Z);
scale = ((tScale * rot));
vertexes[2] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
//vertexes[2].x = pos.X + vertexes[2].x;
//vertexes[2].y = pos.Y + vertexes[2].y;
//vertexes[2].z = pos.Z + vertexes[2].z;
FaceC[0] = vertexes[2];
FaceD[3] = vertexes[2];
FaceC[5] = vertexes[2];
tScale = new Vector3(lscale.X, lscale.Y, -lscale.Z);
scale = ((tScale * rot));
vertexes[3] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
//vertexes[3].x = pos.X + vertexes[3].x;
// vertexes[3].y = pos.Y + vertexes[3].y;
// vertexes[3].z = pos.Z + vertexes[3].z;
FaceD[0] = vertexes[3];
FaceC[1] = vertexes[3];
FaceA[5] = vertexes[3];
tScale = new Vector3(-lscale.X, lscale.Y, lscale.Z);
scale = ((tScale * rot));
vertexes[4] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[4].x = pos.X + vertexes[4].x;
// vertexes[4].y = pos.Y + vertexes[4].y;
// vertexes[4].z = pos.Z + vertexes[4].z;
FaceB[1] = vertexes[4];
FaceA[2] = vertexes[4];
FaceD[4] = vertexes[4];
tScale = new Vector3(-lscale.X, lscale.Y, -lscale.Z);
scale = ((tScale * rot));
vertexes[5] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[5].x = pos.X + vertexes[5].x;
// vertexes[5].y = pos.Y + vertexes[5].y;
// vertexes[5].z = pos.Z + vertexes[5].z;
FaceD[1] = vertexes[5];
FaceC[2] = vertexes[5];
FaceB[5] = vertexes[5];
tScale = new Vector3(-lscale.X, -lscale.Y, lscale.Z);
scale = ((tScale * rot));
vertexes[6] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[6].x = pos.X + vertexes[6].x;
// vertexes[6].y = pos.Y + vertexes[6].y;
// vertexes[6].z = pos.Z + vertexes[6].z;
FaceB[2] = vertexes[6];
FaceA[3] = vertexes[6];
FaceB[4] = vertexes[6];
tScale = new Vector3(-lscale.X, -lscale.Y, -lscale.Z);
scale = ((tScale * rot));
vertexes[7] = (new Vector3((pos.X + scale.X), (pos.Y + scale.Y), (pos.Z + scale.Z)));
// vertexes[7].x = pos.X + vertexes[7].x;
// vertexes[7].y = pos.Y + vertexes[7].y;
// vertexes[7].z = pos.Z + vertexes[7].z;
FaceD[2] = vertexes[7];
FaceC[3] = vertexes[7];
FaceD[5] = vertexes[7];
#endregion
//int wy = 0;
//bool breakYN = false; // If we run into an error drawing, break out of the
// loop so we don't lag to death on error handling
DrawStruct ds = new DrawStruct();
ds.brush = new SolidBrush(mapdotspot);
//ds.rect = new Rectangle(mapdrawstartX, (255 - mapdrawstartY), mapdrawendX - mapdrawstartX, mapdrawendY - mapdrawstartY);
ds.trns = new face[FaceA.Length];
for (int i = 0; i < FaceA.Length; i++)
{
Point[] working = new Point[5];
working[0] = project(FaceA[i], axPos);
working[1] = project(FaceB[i], axPos);
working[2] = project(FaceD[i], axPos);
working[3] = project(FaceC[i], axPos);
working[4] = project(FaceA[i], axPos);
face workingface = new face();
workingface.pts = working;
ds.trns[i] = workingface;
}
z_sort.Add(part.LocalId, ds);
z_localIDs.Add(part.LocalId);
z_sortheights.Add(pos.Z);
//for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
//{ //{
//m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy); //for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
//try
//{ //{
// Remember, flip the y! //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
// mapbmp.SetPixel(wx, (255 - wy), mapdotspot); //try
//} //{
//catch (ArgumentException) // Remember, flip the y!
//{ // mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
// breakYN = true; //}
//catch (ArgumentException)
//{
// breakYN = true;
//}
//if (breakYN)
// break;
//} //}
//if (breakYN) //if (breakYN)
// break; // break;
//} //}
} // Object is within 256m Z of terrain
} // object is at least a meter wide
} // loop over group children
} // entitybase is sceneobject group
} // foreach loop over entities
//if (breakYN) float[] sortedZHeights = z_sortheights.ToArray();
// break; uint[] sortedlocalIds = z_localIDs.ToArray();
//}
} // Object is within 256m Z of terrain
} // object is at least a meter wide
} // loop over group children
} // entitybase is sceneobject group
} // foreach loop over entities
float[] sortedZHeights = z_sortheights.ToArray(); // Sort prim by Z position
uint[] sortedlocalIds = z_localIDs.ToArray(); Array.Sort(sortedZHeights, sortedlocalIds);
// Sort prim by Z position using (Graphics g = Graphics.FromImage(mapbmp))
Array.Sort(sortedZHeights, sortedlocalIds);
Graphics g = Graphics.FromImage(mapbmp);
for (int s = 0; s < sortedZHeights.Length; s++)
{
if (z_sort.ContainsKey(sortedlocalIds[s]))
{ {
DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]]; for (int s = 0; s < sortedZHeights.Length; s++)
for (int r = 0; r < rectDrawStruct.trns.Length; r++)
{ {
g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts); if (z_sort.ContainsKey(sortedlocalIds[s]))
{
DrawStruct rectDrawStruct = z_sort[sortedlocalIds[s]];
for (int r = 0; r < rectDrawStruct.trns.Length; r++)
{
g.FillPolygon(rectDrawStruct.brush,rectDrawStruct.trns[r].pts);
}
//g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
}
} }
//g.FillRectangle(rectDrawStruct.brush , rectDrawStruct.rect);
} }
} } // lock entities objs
g.Dispose(); }
} // lock entities objs finally
{
foreach (DrawStruct ds in z_sort.Values)
ds.brush.Dispose();
}
m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms"); m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms");
return mapbmp; return mapbmp;
} }

View File

@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
public void TerrainToBitmap(Bitmap mapbmp) public void TerrainToBitmap(Bitmap mapbmp)
{ {
int tc = Environment.TickCount; int tc = Environment.TickCount;
m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Terrain");
double[,] hm = m_scene.Heightmap.GetDoubles(); double[,] hm = m_scene.Heightmap.GetDoubles();
bool ShadowDebugContinue = true; bool ShadowDebugContinue = true;
@ -199,7 +199,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
{ {
if (!terraincorruptedwarningsaid) if (!terraincorruptedwarningsaid)
{ {
m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName); m_log.WarnFormat("[SHADED MAP TILE RENDERER]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
terraincorruptedwarningsaid = true; terraincorruptedwarningsaid = true;
} }
color = Color.Black; color = Color.Black;
@ -229,7 +229,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
{ {
if (!terraincorruptedwarningsaid) if (!terraincorruptedwarningsaid)
{ {
m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName); m_log.WarnFormat("[SHADED MAP TILE RENDERER]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", m_scene.RegionInfo.RegionName);
terraincorruptedwarningsaid = true; terraincorruptedwarningsaid = true;
} }
Color black = Color.Black; Color black = Color.Black;
@ -238,7 +238,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
} }
} }
} }
m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
} }
} }
} }

View File

@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
private Bitmap fetchTexture(UUID id) private Bitmap fetchTexture(UUID id)
{ {
AssetBase asset = m_scene.AssetService.Get(id.ToString()); AssetBase asset = m_scene.AssetService.Get(id.ToString());
m_log.DebugFormat("[TexturedMapTileRenderer]: Fetched texture {0}, found: {1}", id, asset != null); m_log.DebugFormat("[TEXTURED MAP TILE RENDERER]: Fetched texture {0}, found: {1}", id, asset != null);
if (asset == null) return null; if (asset == null) return null;
ManagedImage managedImage; ManagedImage managedImage;
@ -188,17 +188,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
} }
catch (DllNotFoundException) catch (DllNotFoundException)
{ {
m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id); m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id);
} }
catch (IndexOutOfRangeException) catch (IndexOutOfRangeException)
{ {
m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id);
} }
catch (Exception) catch (Exception)
{ {
m_log.ErrorFormat("[TexturedMapTileRenderer]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id); m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id);
} }
return null; return null;
@ -233,10 +233,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
if (textureID == UUID.Zero) return defaultColor; // not set if (textureID == UUID.Zero) return defaultColor; // not set
if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures if (m_mapping.ContainsKey(textureID)) return m_mapping[textureID]; // one of the predefined textures
Bitmap bmp = fetchTexture(textureID); Color color;
Color color = bmp == null ? defaultColor : computeAverageColor(bmp);
// store it for future reference using (Bitmap bmp = fetchTexture(textureID))
m_mapping[textureID] = color; {
color = bmp == null ? defaultColor : computeAverageColor(bmp);
// store it for future reference
m_mapping[textureID] = color;
}
return color; return color;
} }
@ -278,7 +282,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
public void TerrainToBitmap(Bitmap mapbmp) public void TerrainToBitmap(Bitmap mapbmp)
{ {
int tc = Environment.TickCount; int tc = Environment.TickCount;
m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Terrain");
// These textures should be in the AssetCache anyway, as every client conneting to this // These textures should be in the AssetCache anyway, as every client conneting to this
// region needs them. Except on start, when the map is recreated (before anyone connected), // region needs them. Except on start, when the map is recreated (before anyone connected),
@ -412,7 +416,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
} }
} }
} }
m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
} }
} }
} }

View File

@ -207,7 +207,8 @@ namespace OpenSim.Region.CoreModules.World.LightShare
private void EventManager_OnMakeRootAgent(ScenePresence presence) private void EventManager_OnMakeRootAgent(ScenePresence presence)
{ {
m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client"); // m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client {0}", presence.Name);
SendProfileToClient(presence.ControllingClient); SendProfileToClient(presence.ControllingClient);
} }

View File

@ -46,8 +46,8 @@ namespace OpenSim.Region.CoreModules.World.Region
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")] [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")]
public class RestartModule : INonSharedRegionModule, IRestartModule public class RestartModule : INonSharedRegionModule, IRestartModule
{ {
// private static readonly ILog m_log = private static readonly ILog m_log =
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected Scene m_Scene; protected Scene m_Scene;
protected Timer m_CountdownTimer = null; protected Timer m_CountdownTimer = null;
@ -203,18 +203,30 @@ namespace OpenSim.Region.CoreModules.World.Region
public void SetTimer(int intervalSeconds) public void SetTimer(int intervalSeconds)
{ {
m_CountdownTimer = new Timer(); if (intervalSeconds > 0)
m_CountdownTimer.AutoReset = false; {
m_CountdownTimer.Interval = intervalSeconds * 1000; m_CountdownTimer = new Timer();
m_CountdownTimer.Elapsed += OnTimer; m_CountdownTimer.AutoReset = false;
m_CountdownTimer.Start(); 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) private void OnTimer(object source, ElapsedEventArgs e)
{ {
int nextInterval = DoOneNotice(); SetTimer(DoOneNotice());
SetTimer(nextInterval);
} }
public void AbortRestart(string message) public void AbortRestart(string message)

View File

@ -114,6 +114,11 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
"export-map [<path>]", "export-map [<path>]",
"Save an image of the world map", HandleExportWorldMapConsoleCommand); "Save an image of the world map", HandleExportWorldMapConsoleCommand);
m_scene.AddCommand(
"Regions", this, "generate map",
"generate map",
"Generates and stores a new maptile.", HandleGenerateMapConsoleCommand);
AddHandlers(); AddHandlers();
} }
} }
@ -1255,6 +1260,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
m_scene.RegionInfo.RegionName, exportPath); m_scene.RegionInfo.RegionName, exportPath);
} }
public void HandleGenerateMapConsoleCommand(string module, string[] cmdparams)
{
Scene consoleScene = m_scene.ConsoleScene();
if (consoleScene != null && consoleScene != m_scene)
return;
GenerateMaptile();
}
public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint) public OSD HandleRemoteMapItemRequest(string path, OSD request, string endpoint)
{ {
uint xstart = 0; uint xstart = 0;
@ -1486,62 +1501,69 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
private Byte[] GenerateOverlay() private Byte[] GenerateOverlay()
{ {
Bitmap overlay = new Bitmap(256, 256); using (Bitmap overlay = new Bitmap(256, 256))
bool[,] saleBitmap = new bool[64, 64];
for (int x = 0 ; x < 64 ; x++)
{ {
for (int y = 0 ; y < 64 ; y++) bool[,] saleBitmap = new bool[64, 64];
saleBitmap[x, y] = false; for (int x = 0 ; x < 64 ; x++)
}
bool landForSale = false;
List<ILandObject> parcels = m_scene.LandChannel.AllParcels();
Color background = Color.FromArgb(0, 0, 0, 0);
SolidBrush transparent = new SolidBrush(background);
Graphics g = Graphics.FromImage(overlay);
g.FillRectangle(transparent, 0, 0, 256, 256);
SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9));
foreach (ILandObject land in parcels)
{
// m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
{ {
landForSale = true; for (int y = 0 ; y < 64 ; y++)
saleBitmap[x, y] = false;
}
saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap()); bool landForSale = false;
List<ILandObject> parcels = m_scene.LandChannel.AllParcels();
Color background = Color.FromArgb(0, 0, 0, 0);
using (Graphics g = Graphics.FromImage(overlay))
{
using (SolidBrush transparent = new SolidBrush(background))
g.FillRectangle(transparent, 0, 0, 256, 256);
foreach (ILandObject land in parcels)
{
// m_log.DebugFormat("[WORLD MAP]: Parcel {0} flags {1}", land.LandData.Name, land.LandData.Flags);
if ((land.LandData.Flags & (uint)ParcelFlags.ForSale) != 0)
{
landForSale = true;
saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap());
}
}
if (!landForSale)
{
m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
return null;
}
m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
using (SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)))
{
for (int x = 0 ; x < 64 ; x++)
{
for (int y = 0 ; y < 64 ; y++)
{
if (saleBitmap[x, y])
g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4);
}
}
}
}
try
{
return OpenJPEG.EncodeFromImage(overlay, true);
}
catch (Exception e)
{
m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
} }
} }
if (!landForSale)
{
m_log.DebugFormat("[WORLD MAP]: Region {0} has no parcels for sale, not generating overlay", m_scene.RegionInfo.RegionName);
return null;
}
m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, generating overlay", m_scene.RegionInfo.RegionName);
for (int x = 0 ; x < 64 ; x++)
{
for (int y = 0 ; y < 64 ; y++)
{
if (saleBitmap[x, y])
g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4);
}
}
try
{
return OpenJPEG.EncodeFromImage(overlay, true);
}
catch (Exception e)
{
m_log.DebugFormat("[WORLD MAP]: Error creating parcel overlay: " + e.ToString());
}
return null; return null;
} }
} }

View File

@ -144,7 +144,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered when a new presence is added to the scene /// Triggered when a new presence is added to the scene
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewAgent"/> which is used by both
/// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see> /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
/// </remarks> /// </remarks>
public event OnNewPresenceDelegate OnNewPresence; public event OnNewPresenceDelegate OnNewPresence;
@ -155,7 +155,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered when a presence is removed from the scene /// Triggered when a presence is removed from the scene
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewAgent"/> which is used by both
/// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see> /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
/// ///
/// Triggered under per-agent lock. So if you want to perform any long-running operations, please /// Triggered under per-agent lock. So if you want to perform any long-running operations, please
@ -1102,7 +1102,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.ProcessMoneyTransferRequest"/> /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.ProcessMoneyTransferRequest"/>
/// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientGridEvents"/> /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientGridEvents"/>
/// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientEvents"/> /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientEvents"/>
/// via <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewAgent"/>
/// </remarks> /// </remarks>
public event MoneyTransferEvent OnMoneyTransfer; public event MoneyTransferEvent OnMoneyTransfer;

View File

@ -512,6 +512,9 @@ namespace OpenSim.Region.Framework.Scenes
// This MAY be problematic, if it is, another solution // This MAY be problematic, if it is, another solution
// needs to be found. If inventory item flags are updated // needs to be found. If inventory item flags are updated
// the viewer's notion of the item needs to be refreshed. // the viewer's notion of the item needs to be refreshed.
//
// In other situations we cannot send out a bulk update here, since this will cause editing of clothing to start
// failing frequently. Possibly this is a race with a separate transaction that uploads the asset.
if (sendUpdate) if (sendUpdate)
remoteClient.SendBulkUpdateInventory(item); remoteClient.SendBulkUpdateInventory(item);
} }

View File

@ -731,6 +731,7 @@ namespace OpenSim.Region.Framework.Scenes
m_config = config; m_config = config;
MinFrameTime = 0.089f; MinFrameTime = 0.089f;
MinMaintenanceTime = 1; MinMaintenanceTime = 1;
SeeIntoRegion = true;
Random random = new Random(); Random random = new Random();
@ -841,7 +842,7 @@ namespace OpenSim.Region.Framework.Scenes
//Animation states //Animation states
m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
SeeIntoRegion = startupConfig.GetBoolean("see_into_region", true); SeeIntoRegion = startupConfig.GetBoolean("see_into_region", SeeIntoRegion);
MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20); MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20);
@ -1312,7 +1313,7 @@ namespace OpenSim.Region.Framework.Scenes
Thread.Sleep(500); Thread.Sleep(500);
// Stop all client threads. // Stop all client threads.
ForEachScenePresence(delegate(ScenePresence avatar) { IncomingCloseAgent(avatar.UUID, false); }); ForEachScenePresence(delegate(ScenePresence avatar) { CloseAgent(avatar.UUID, false); });
m_log.Debug("[SCENE]: Persisting changed objects"); m_log.Debug("[SCENE]: Persisting changed objects");
EventManager.TriggerSceneShuttingDown(this); EventManager.TriggerSceneShuttingDown(this);
@ -2801,7 +2802,7 @@ namespace OpenSim.Region.Framework.Scenes
#region Add/Remove Avatar Methods #region Add/Remove Avatar Methods
public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
{ {
ScenePresence sp; ScenePresence sp;
bool vialogin; bool vialogin;
@ -2809,7 +2810,7 @@ namespace OpenSim.Region.Framework.Scenes
// Validation occurs in LLUDPServer // Validation occurs in LLUDPServer
// //
// XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with // XXX: A race condition exists here where two simultaneous calls to AddNewAgent can interfere with
// each other. In practice, this does not currently occur in the code. // each other. In practice, this does not currently occur in the code.
AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
@ -2817,9 +2818,9 @@ namespace OpenSim.Region.Framework.Scenes
// and a simultaneous one that removes it (as can happen if the client is closed at a particular point // and a simultaneous one that removes it (as can happen if the client is closed at a particular point
// whilst connecting). // whilst connecting).
// //
// It would be easier to lock across all NewUserConnection(), AddNewClient() and // It would be easier to lock across all NewUserConnection(), AddNewAgent() and
// RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
// response in some module listening to AddNewClient()) from holding up unrelated agent calls. // response in some module listening to AddNewAgent()) from holding up unrelated agent calls.
// //
// In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
// AddNewClient() operations (though not other ops). // AddNewClient() operations (though not other ops).
@ -2836,7 +2837,7 @@ namespace OpenSim.Region.Framework.Scenes
// XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
// could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
// other problems, and possible the code calling AddNewClient() should ensure that no client is already // other problems, and possibly the code calling AddNewAgent() should ensure that no client is already
// connected. // connected.
if (sp == null) if (sp == null)
{ {
@ -2862,6 +2863,9 @@ namespace OpenSim.Region.Framework.Scenes
// We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
// client is for a root or child agent. // client is for a root or child agent.
// XXX: This may be better set for a new client before that client is added to the client manager.
// But need to know what happens in the case where a ScenePresence is already present (and if this
// actually occurs).
client.SceneAgent = sp; client.SceneAgent = sp;
// This is currently also being done earlier in NewUserConnection for real users to see if this // This is currently also being done earlier in NewUserConnection for real users to see if this
@ -2972,7 +2976,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
PresenceService.LogoutAgent(sp.ControllingClient.SessionId); PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
IncomingCloseAgent(sp.UUID, false); CloseAgent(sp.UUID, false);
} }
else else
{ {
@ -3394,7 +3398,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name='closeChildAgents'> /// <param name='closeChildAgents'>
/// Close the neighbour child agents associated with this client. /// Close the neighbour child agents associated with this client.
/// </param> /// </param>
public override void RemoveClient(UUID agentID, bool closeChildAgents) public void RemoveClient(UUID agentID, bool closeChildAgents)
{ {
AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID); AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
@ -3695,10 +3699,13 @@ namespace OpenSim.Region.Framework.Scenes
// We need to ensure that we are not already removing the scene presence before we ask it not to be // We need to ensure that we are not already removing the scene presence before we ask it not to be
// closed. // closed.
if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running) if (sp != null && sp.IsChildAgent
&& (sp.LifecycleState == ScenePresenceState.Running
|| sp.LifecycleState == ScenePresenceState.PreRemove))
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name); "[SCENE]: Reusing existing child scene presence for {0}, state {1} in {2}",
sp.Name, sp.LifecycleState, Name);
// In the case where, for example, an A B C D region layout, an avatar may // In the case where, for example, an A B C D region layout, an avatar may
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
@ -3720,6 +3727,8 @@ namespace OpenSim.Region.Framework.Scenes
// } // }
// else if (EntityTransferModule.IsInTransit(sp.UUID)) // else if (EntityTransferModule.IsInTransit(sp.UUID))
sp.LifecycleState = ScenePresenceState.Running;
if (EntityTransferModule.IsInTransit(sp.UUID)) if (EntityTransferModule.IsInTransit(sp.UUID))
{ {
sp.DoNotCloseAfterTeleport = true; sp.DoNotCloseAfterTeleport = true;
@ -3774,7 +3783,7 @@ namespace OpenSim.Region.Framework.Scenes
sp.Name, sp.UUID, RegionInfo.RegionName); sp.Name, sp.UUID, RegionInfo.RegionName);
if (sp.ControllingClient != null) if (sp.ControllingClient != null)
IncomingCloseAgent(sp.UUID, true); CloseAgent(sp.UUID, true);
sp = null; sp = null;
} }
@ -3824,7 +3833,7 @@ namespace OpenSim.Region.Framework.Scenes
try try
{ {
if (!AuthorizeUser(acd, SeeIntoRegion, out reason)) if (!AuthorizeUser(acd, (vialogin ? false : SeeIntoRegion), out reason))
{ {
m_authenticateHandler.RemoveCircuit(acd.circuitcode); m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false; return false;
@ -3937,32 +3946,52 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
// m_log.DebugFormat(
// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
// RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
// Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags // Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags
if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero &&
RegionInfo.EstateSettings.AllowDirectTeleport == false && RegionInfo.EstateSettings.AllowDirectTeleport == false &&
!viahome && !godlike) !viahome && !godlike)
{ {
SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject); SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject);
// Can have multiple SpawnPoints
List<SpawnPoint> spawnpoints = RegionInfo.RegionSettings.SpawnPoints(); if (telehub != null)
if (spawnpoints.Count > 1)
{ {
// We have multiple SpawnPoints, Route the agent to a random or sequential one // Can have multiple SpawnPoints
if (SpawnPointRouting == "random") List<SpawnPoint> spawnpoints = RegionInfo.RegionSettings.SpawnPoints();
acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( if (spawnpoints.Count > 1)
telehub.AbsolutePosition, {
telehub.GroupRotation // We have multiple SpawnPoints, Route the agent to a random or sequential one
); if (SpawnPointRouting == "random")
acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
telehub.AbsolutePosition,
telehub.GroupRotation
);
else
acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
telehub.AbsolutePosition,
telehub.GroupRotation
);
}
else if (spawnpoints.Count == 1)
{
// We have a single SpawnPoint and will route the agent to it
acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
}
else else
acd.startpos = spawnpoints[SpawnPoint()].GetLocation( {
telehub.AbsolutePosition, m_log.DebugFormat(
telehub.GroupRotation "[SCENE]: No spawnpoints defined for telehub {0} for {1} in {2}. Continuing.",
); RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
}
} }
else else
{ {
// We have a single SpawnPoint and will route the agent to it m_log.DebugFormat(
acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); "[SCENE]: No telehub {0} found to direct {1} in {2}. Continuing.",
RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
} }
return true; return true;
@ -4278,7 +4307,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="cAgentData">Agent that contains all of the relevant things about an agent. /// <param name="cAgentData">Agent that contains all of the relevant things about an agent.
/// Appearance, animations, position, etc.</param> /// Appearance, animations, position, etc.</param>
/// <returns>true if we handled it.</returns> /// <returns>true if we handled it.</returns>
public virtual bool IncomingChildAgentDataUpdate(AgentData cAgentData) public virtual bool IncomingUpdateChildAgent(AgentData cAgentData)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName); "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
@ -4287,7 +4316,7 @@ namespace OpenSim.Region.Framework.Scenes
ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2);
if (nearestParcel == null) if (nearestParcel == null)
{ {
m_log.DebugFormat( m_log.InfoFormat(
"[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel", "[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel",
cAgentData.AgentID, RegionInfo.RegionName); cAgentData.AgentID, RegionInfo.RegionName);
@ -4297,7 +4326,7 @@ namespace OpenSim.Region.Framework.Scenes
// We have to wait until the viewer contacts this region // We have to wait until the viewer contacts this region
// after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol) // after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol)
// or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send // or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send
// a UseCircuitCode packet which in turn calls AddNewClient which finally creates the ScenePresence. // a UseCircuitCode packet which in turn calls AddNewAgent which finally creates the ScenePresence.
ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID); ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID);
if (sp != null) if (sp != null)
@ -4312,7 +4341,7 @@ namespace OpenSim.Region.Framework.Scenes
sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID)); sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID));
} }
sp.ChildAgentDataUpdate(cAgentData); sp.UpdateChildAgent(cAgentData);
int ntimes = 20; int ntimes = 20;
if (cAgentData.SenderWantsToWaitForRoot) if (cAgentData.SenderWantsToWaitForRoot)
@ -4320,9 +4349,14 @@ namespace OpenSim.Region.Framework.Scenes
while (sp.IsChildAgent && ntimes-- > 0) while (sp.IsChildAgent && ntimes-- > 0)
Thread.Sleep(1000); Thread.Sleep(1000);
m_log.DebugFormat( if (sp.IsChildAgent)
"[SCENE]: Found presence {0} {1} {2} in {3} after {4} waits", m_log.WarnFormat(
sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", Name, 20 - ntimes); "[SCENE]: Found presence {0} {1} unexpectedly still child in {2}",
sp.Name, sp.UUID, Name);
else
m_log.InfoFormat(
"[SCENE]: Found presence {0} {1} as root in {2} after {3} waits",
sp.Name, sp.UUID, Name, 20 - ntimes);
if (sp.IsChildAgent) if (sp.IsChildAgent)
return false; return false;
@ -4340,16 +4374,16 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
/// <param name="cAgentData">AgentPosition that contains agent positional data so we can know what to send</param> /// <param name="cAgentData">AgentPosition that contains agent positional data so we can know what to send</param>
/// <returns>true if we handled it.</returns> /// <returns>true if we handled it.</returns>
public virtual bool IncomingChildAgentDataUpdate(AgentPosition cAgentData) public virtual bool IncomingUpdateChildAgent(AgentPosition cAgentData)
{ {
//m_log.Debug(" XXX Scene IncomingChildAgentDataUpdate POSITION in " + RegionInfo.RegionName); //m_log.Debug(" XXX Scene IncomingChildAgentDataUpdate POSITION in " + RegionInfo.RegionName);
ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
if (childAgentUpdate != null) if (childAgentUpdate != null)
{ {
if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID) // if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
// Only warn for now // // Only warn for now
m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?", // m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
childAgentUpdate.UUID, cAgentData.SessionID); // childAgentUpdate.UUID, cAgentData.SessionID);
// I can't imagine *yet* why we would get an update if the agent is a root agent.. // I can't imagine *yet* why we would get an update if the agent is a root agent..
// however to avoid a race condition crossing borders.. // however to avoid a race condition crossing borders..
@ -4360,7 +4394,7 @@ namespace OpenSim.Region.Framework.Scenes
uint tRegionX = RegionInfo.RegionLocX; uint tRegionX = RegionInfo.RegionLocX;
uint tRegionY = RegionInfo.RegionLocY; uint tRegionY = RegionInfo.RegionLocY;
//Send Data to ScenePresence //Send Data to ScenePresence
childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); childAgentUpdate.UpdateChildAgent(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
// Not Implemented: // Not Implemented:
//TODO: Do we need to pass the message on to one of our neighbors? //TODO: Do we need to pass the message on to one of our neighbors?
} }
@ -4410,7 +4444,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="force"></param> /// <param name="force"></param>
/// <param name="auth_token"></param> /// <param name="auth_token"></param>
/// <returns></returns> /// <returns></returns>
public bool IncomingCloseAgent(UUID agentID, bool force, string auth_token) public bool CloseAgent(UUID agentID, bool force, string auth_token)
{ {
//m_log.DebugFormat("[SCENE]: Processing incoming close agent {0} in region {1} with auth_token {2}", agentID, RegionInfo.RegionName, auth_token); //m_log.DebugFormat("[SCENE]: Processing incoming close agent {0} in region {1} with auth_token {2}", agentID, RegionInfo.RegionName, auth_token);
@ -4428,7 +4462,7 @@ namespace OpenSim.Region.Framework.Scenes
if (acd.SessionID.ToString() == auth_token) if (acd.SessionID.ToString() == auth_token)
{ {
return IncomingCloseAgent(agentID, force); return CloseAgent(agentID, force);
} }
else else
{ {
@ -4440,6 +4474,50 @@ namespace OpenSim.Region.Framework.Scenes
return false; return false;
} }
/// <summary>
/// Tell a single client to prepare to close.
/// </summary>
/// <remarks>
/// This should only be called if we may close the client but there will be some delay in so doing. Meant for
/// internal use - other callers should almost certainly called CloseClient().
/// </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 IncomingPreCloseClient(ScenePresence sp)
{
lock (m_removeClientLock)
{
// We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
// teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
// want to obey this close since C may have renewed the child agent lease on B.
if (sp.DoNotCloseAfterTeleport)
{
m_log.DebugFormat(
"[SCENE]: Not pre-closing {0} agent {1} in {2} since another simulator has re-established the child connection",
sp.IsChildAgent ? "child" : "root", sp.Name, Name);
// Need to reset the flag so that a subsequent close after another teleport can succeed.
sp.DoNotCloseAfterTeleport = false;
return false;
}
if (sp.LifecycleState != ScenePresenceState.Running)
{
m_log.DebugFormat(
"[SCENE]: Called IncomingPreCloseAgent() for {0} in {1} but presence is already in state {2}",
sp.Name, Name, sp.LifecycleState);
return false;
}
sp.LifecycleState = ScenePresenceState.PreRemove;
return true;
}
}
/// <summary> /// <summary>
/// Tell a single agent to disconnect from the region. /// Tell a single agent to disconnect from the region.
/// </summary> /// </summary>
@ -4448,7 +4526,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Force the agent to close even if it might be in the middle of some other operation. You do not want to /// Force the agent to close even if it might be in the middle of some other operation. You do not want to
/// force unless you are absolutely sure that the agent is dead and a normal close is not working. /// force unless you are absolutely sure that the agent is dead and a normal close is not working.
/// </param> /// </param>
public bool IncomingCloseAgent(UUID agentID, bool force) public override bool CloseAgent(UUID agentID, bool force)
{ {
ScenePresence sp; ScenePresence sp;
@ -4459,16 +4537,16 @@ namespace OpenSim.Region.Framework.Scenes
if (sp == null) if (sp == null)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}", "[SCENE]: Called CloseClient() with agent ID {0} but no such presence is in {1}",
agentID, Name); agentID, Name);
return false; return false;
} }
if (sp.LifecycleState != ScenePresenceState.Running) if (sp.LifecycleState != ScenePresenceState.Running && sp.LifecycleState != ScenePresenceState.PreRemove)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}", "[SCENE]: Called CloseClient() for {0} in {1} but presence is already in state {2}",
sp.Name, Name, sp.LifecycleState); sp.Name, Name, sp.LifecycleState);
return false; return false;
@ -5741,7 +5819,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
if (!AuthorizeUser(aCircuit, false, out reason)) if (!AuthorizeUser(aCircuit, false, out reason))
{ {
// m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
return false; return false;
} }
} }

View File

@ -216,21 +216,9 @@ namespace OpenSim.Region.Framework.Scenes
#region Add/Remove Agent/Avatar #region Add/Remove Agent/Avatar
public abstract ISceneAgent AddNewClient(IClientAPI client, PresenceType type); public abstract ISceneAgent AddNewAgent(IClientAPI client, PresenceType type);
/// <summary> public abstract bool CloseAgent(UUID agentID, bool force);
/// Remove the given client from the scene.
/// </summary>
/// <remarks>
/// Only clientstack code should call this directly. All other code should call IncomingCloseAgent() instead
/// to properly operate the state machine and avoid race conditions with other close requests (such as directly
/// from viewers).
/// </remarks>
/// <param name='agentID'>ID of agent to close</param>
/// <param name='closeChildAgents'>
/// Close the neighbour child agents associated with this client.
/// </param>
public abstract void RemoveClient(UUID agentID, bool closeChildAgents);
public bool TryGetScenePresence(UUID agentID, out object scenePresence) public bool TryGetScenePresence(UUID agentID, out object scenePresence)
{ {

View File

@ -561,39 +561,15 @@ namespace OpenSim.Region.Framework.Scenes
protected internal ScenePresence CreateAndAddChildScenePresence( protected internal ScenePresence CreateAndAddChildScenePresence(
IClientAPI client, AvatarAppearance appearance, PresenceType type) IClientAPI client, AvatarAppearance appearance, PresenceType type)
{ {
ScenePresence newAvatar = null;
// ScenePresence always defaults to child agent // ScenePresence always defaults to child agent
newAvatar = new ScenePresence(client, m_parentScene, appearance, type); ScenePresence presence = 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);
}
Entities[presence.UUID] = presence; Entities[presence.UUID] = presence;
lock (m_presenceLock) lock (m_presenceLock)
{ {
m_numChildAgents++;
Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@ -604,7 +580,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
else else
{ {
// Remember the old presene reference from the dictionary // Remember the old presence reference from the dictionary
ScenePresence oldref = newmap[presence.UUID]; ScenePresence oldref = newmap[presence.UUID];
// Replace the presence reference in the dictionary with the new value // Replace the presence reference in the dictionary with the new value
newmap[presence.UUID] = presence; newmap[presence.UUID] = presence;
@ -616,6 +592,8 @@ namespace OpenSim.Region.Framework.Scenes
m_scenePresenceMap = newmap; m_scenePresenceMap = newmap;
m_scenePresenceArray = newlist; m_scenePresenceArray = newlist;
} }
return presence;
} }
/// <summary> /// <summary>

View File

@ -2464,12 +2464,9 @@ namespace OpenSim.Region.Framework.Scenes
SendCollisionEvent(scriptEvents.collision_end , endedColliders , ParentGroup.Scene.EventManager.TriggerScriptCollidingEnd); SendCollisionEvent(scriptEvents.collision_end , endedColliders , ParentGroup.Scene.EventManager.TriggerScriptCollidingEnd);
if (startedColliders.Contains(0)) if (startedColliders.Contains(0))
{ SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart);
if (m_lastColliders.Contains(0)) if (m_lastColliders.Contains(0))
SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding); SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding);
else
SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart);
}
if (endedColliders.Contains(0)) if (endedColliders.Contains(0))
SendLandCollisionEvent(scriptEvents.land_collision_end, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd); SendLandCollisionEvent(scriptEvents.land_collision_end, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd);
} }
@ -2505,6 +2502,26 @@ namespace OpenSim.Region.Framework.Scenes
//ParentGroup.RootPart.m_groupPosition = newpos; //ParentGroup.RootPart.m_groupPosition = newpos;
} }
if (pa != null && ParentID != 0 && ParentGroup != null)
{
// Special case where a child object is requesting property updates.
// This happens when linksets are modified to use flexible links rather than
// the default links.
// The simulator code presumes that child parts are only modified by scripts
// so the logic for changing position/rotation/etc does not take into
// account the physical object actually moving.
// This code updates the offset position and rotation of the child and then
// lets the update code push the update to the viewer.
// Since physics engines do not normally generate this event for linkset children,
// this code will not be active unless you have a specially configured
// physics engine.
Quaternion invRootRotation = Quaternion.Normalize(Quaternion.Inverse(ParentGroup.RootPart.RotationOffset));
m_offsetPosition = pa.Position - m_groupPosition;
RotationOffset = pa.Orientation * invRootRotation;
// m_log.DebugFormat("{0} PhysicsRequestingTerseUpdate child: pos={1}, rot={2}, offPos={3}, offRot={4}",
// "[SCENE OBJECT PART]", pa.Position, pa.Orientation, m_offsetPosition, RotationOffset);
}
ScheduleTerseUpdate(); ScheduleTerseUpdate();
} }

View File

@ -108,6 +108,16 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
/// <summary>
/// This exists to prevent race conditions between two CompleteMovement threads if the simulator is slow and
/// the viewer fires these in quick succession.
/// </summary>
/// <remarks>
/// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement
/// regulation done there.
/// </remarks>
private object m_completeMovementLock = new object();
// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@ -311,7 +321,21 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
private string m_callbackURI; private string m_callbackURI;
public UUID m_originRegionID; /// <summary>
/// Records the region from which this presence originated, if not from login.
/// </summary>
/// <remarks>
/// Also acts as a signal in the teleport V2 process to release UpdateAgent after a viewer has triggered
/// CompleteMovement and made the previous child agent a root agent.
/// </remarks>
private UUID m_originRegionID;
/// <summary>
/// This object is used as a lock before accessing m_originRegionID to make sure that every thread is seeing
/// the very latest value and not using some cached version. Cannot make m_originRegionID itself volatite as
/// it is a value type.
/// </summary>
private object m_originRegionIDAccessLock = new object();
/// <summary> /// <summary>
/// Used by the entity transfer module to signal when the presence should not be closed because a subsequent /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
@ -890,6 +914,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// Turns a child agent into a root agent. /// Turns a child agent into a root agent.
/// </summary> /// </summary>
/// <remarks>
/// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the /// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the
/// avatar is actual in the sim. They can perform all actions. /// avatar is actual in the sim. They can perform all actions.
/// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim, /// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim,
@ -897,16 +922,22 @@ namespace OpenSim.Region.Framework.Scenes
/// ///
/// This method is on the critical path for transferring an avatar from one region to another. Delay here /// This method is on the critical path for transferring an avatar from one region to another. Delay here
/// delays that crossing. /// delays that crossing.
/// </summary> /// </remarks>
public void MakeRootAgent(Vector3 pos, bool isFlying) private bool MakeRootAgent(Vector3 pos, bool isFlying)
{ {
m_log.InfoFormat( // m_log.InfoFormat(
"[SCENE]: Upgrading child to root agent for {0} in {1}", // "[SCENE]: Upgrading child to root agent for {0} in {1}",
Name, m_scene.RegionInfo.RegionName); // Name, m_scene.RegionInfo.RegionName);
//m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
IsChildAgent = false; lock (m_completeMovementLock)
{
if (!IsChildAgent)
return false;
IsChildAgent = false;
}
// Must reset this here so that a teleport to a region next to an existing region does not keep the flag // Must reset this here so that a teleport to a region next to an existing region does not keep the flag
// set and prevent the close of the connection on a subsequent re-teleport. // set and prevent the close of the connection on a subsequent re-teleport.
@ -1055,6 +1086,7 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.EventManager.TriggerOnMakeRootAgent(this); m_scene.EventManager.TriggerOnMakeRootAgent(this);
return true;
} }
public int GetStateSource() public int GetStateSource()
@ -1354,15 +1386,26 @@ namespace OpenSim.Region.Framework.Scenes
private bool WaitForUpdateAgent(IClientAPI client) private bool WaitForUpdateAgent(IClientAPI client)
{ {
// Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero // Before the source region executes UpdateAgent
// (which triggers Scene.IncomingUpdateChildAgent(AgentData cAgentData) here in the destination,
// m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the
// viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero
int count = 50; int count = 50;
while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) UUID originID;
lock (m_originRegionIDAccessLock)
originID = m_originRegionID;
while (originID.Equals(UUID.Zero) && count-- > 0)
{ {
lock (m_originRegionIDAccessLock)
originID = m_originRegionID;
m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name); m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name);
Thread.Sleep(200); Thread.Sleep(200);
} }
if (m_originRegionID.Equals(UUID.Zero)) if (originID.Equals(UUID.Zero))
{ {
// Movement into region will fail // Movement into region will fail
m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name); m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name);
@ -1385,9 +1428,9 @@ namespace OpenSim.Region.Framework.Scenes
{ {
// DateTime startTime = DateTime.Now; // DateTime startTime = DateTime.Now;
m_log.DebugFormat( m_log.InfoFormat(
"[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}",
client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); client.Name, Scene.Name, AbsolutePosition);
// Make sure it's not a login agent. We don't want to wait for updates during login // Make sure it's not a login agent. We don't want to wait for updates during login
if (PresenceType != PresenceType.Npc && (m_teleportFlags & TeleportFlags.ViaLogin) == 0) if (PresenceType != PresenceType.Npc && (m_teleportFlags & TeleportFlags.ViaLogin) == 0)
@ -1417,7 +1460,14 @@ namespace OpenSim.Region.Framework.Scenes
} }
bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
MakeRootAgent(AbsolutePosition, flying); if (!MakeRootAgent(AbsolutePosition, flying))
{
m_log.DebugFormat(
"[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root",
Name, Scene.Name);
return;
}
// Tell the client that we're totally ready // Tell the client that we're totally ready
ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
@ -1441,7 +1491,12 @@ namespace OpenSim.Region.Framework.Scenes
"[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}",
client.Name, client.AgentId, m_callbackURI); client.Name, client.AgentId, m_callbackURI);
Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); UUID originID;
lock (m_originRegionIDAccessLock)
originID = m_originRegionID;
Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI);
m_callbackURI = null; m_callbackURI = null;
} }
// else // else
@ -2879,7 +2934,7 @@ namespace OpenSim.Region.Framework.Scenes
// If we are using the the cached appearance then send it out to everyone // If we are using the the cached appearance then send it out to everyone
if (cachedappearance) if (cachedappearance)
{ {
m_log.DebugFormat("[SCENE PRESENCE]: baked textures are in the cache for {0}", Name); m_log.DebugFormat("[SCENE PRESENCE]: Baked textures are in the cache for {0} in {1}", Name, m_scene.Name);
// If the avatars baked textures are all in the cache, then we have a // If the avatars baked textures are all in the cache, then we have a
// complete appearance... send it out, if not, then we'll send it when // complete appearance... send it out, if not, then we'll send it when
@ -3243,11 +3298,6 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
public void RestoreInCurrentScene()
{
AddToPhysicalScene(false); // not exactly false
}
public void Reset() public void Reset()
{ {
// m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName); // m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName);
@ -3343,7 +3393,7 @@ namespace OpenSim.Region.Framework.Scenes
#region Child Agent Updates #region Child Agent Updates
public void ChildAgentDataUpdate(AgentData cAgentData) public void UpdateChildAgent(AgentData cAgentData)
{ {
// m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName); // m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName);
if (!IsChildAgent) if (!IsChildAgent)
@ -3353,11 +3403,12 @@ namespace OpenSim.Region.Framework.Scenes
} }
private static Vector3 marker = new Vector3(-1f, -1f, -1f); private static Vector3 marker = new Vector3(-1f, -1f, -1f);
/// <summary> /// <summary>
/// This updates important decision making data about a child agent /// This updates important decision making data about a child agent
/// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region
/// </summary> /// </summary>
public void ChildAgentDataUpdate(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY) public void UpdateChildAgent(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY)
{ {
if (!IsChildAgent) if (!IsChildAgent)
return; return;
@ -3462,7 +3513,8 @@ namespace OpenSim.Region.Framework.Scenes
private void CopyFrom(AgentData cAgent) private void CopyFrom(AgentData cAgent)
{ {
m_originRegionID = cAgent.RegionID; lock (m_originRegionIDAccessLock)
m_originRegionID = cAgent.RegionID;
m_callbackURI = cAgent.CallbackURI; m_callbackURI = cAgent.CallbackURI;
// m_log.DebugFormat( // m_log.DebugFormat(

View File

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

View File

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

View File

@ -79,7 +79,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// TODO: Need to add tests for other ICapabiltiesModule methods. // TODO: Need to add tests for other ICapabiltiesModule methods.
scene.IncomingCloseAgent(sp.UUID, false); scene.CloseAgent(sp.UUID, false);
Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null); Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null);
// TODO: Need to add tests for other ICapabiltiesModule methods. // TODO: Need to add tests for other ICapabiltiesModule methods.

View File

@ -38,6 +38,7 @@ using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.CoreModules.Framework; using OpenSim.Region.CoreModules.Framework;
using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.CoreModules.Framework.EntityTransfer;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Region.CoreModules.World.Permissions;
using OpenSim.Tests.Common; using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock; using OpenSim.Tests.Common.Mock;
@ -159,5 +160,90 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Assert.That(agentMovementCompleteReceived, Is.EqualTo(1)); Assert.That(agentMovementCompleteReceived, Is.EqualTo(1));
Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False); Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False);
} }
/// <summary>
/// Test a cross attempt where the user can see into the neighbour but does not have permission to become
/// root there.
/// </summary>
[Test]
public void TestCrossOnSameSimulatorNoRootDestPerm()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID userId = TestHelpers.ParseTail(0x1);
EntityTransferModule etmA = new EntityTransferModule();
EntityTransferModule etmB = new EntityTransferModule();
LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
IConfigSource config = new IniConfigSource();
IConfig modulesConfig = config.AddConfig("Modules");
modulesConfig.Set("EntityTransferModule", etmA.Name);
modulesConfig.Set("SimulationServices", lscm.Name);
SceneHelpers sh = new SceneHelpers();
TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA);
// We need to set up the permisions module on scene B so that our later use of agent limit to deny
// QueryAccess won't succeed anyway because administrators are always allowed in and the default
// IsAdministrator if no permissions module is present is true.
SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), new PermissionsModule(), etmB);
AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
TestClient tc = new TestClient(acd, sceneA);
List<TestClient> destinationTestClients = new List<TestClient>();
EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
// Make sure sceneB will not accept this avatar.
sceneB.RegionInfo.EstateSettings.PublicAccess = false;
ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
originalSp.AbsolutePosition = new Vector3(128, 32, 10);
AgentUpdateArgs moveArgs = new AgentUpdateArgs();
//moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero);
moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2)));
moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS;
moveArgs.SessionID = acd.SessionID;
originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs);
sceneA.Update(1);
// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition);
// FIXME: This is a sufficient number of updates to for the presence to reach the northern border.
// But really we want to do this in a more robust way.
for (int i = 0; i < 100; i++)
{
sceneA.Update(1);
// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition);
}
// sceneA agent should still be root
ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID);
Assert.That(spAfterCrossSceneA.IsChildAgent, Is.False);
ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID);
// sceneB agent should also still be root
Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True);
// sceneB should ignore unauthorized attempt to upgrade agent to root
TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient);
int agentMovementCompleteReceived = 0;
sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++;
sceneBTc.CompleteMovement();
Assert.That(agentMovementCompleteReceived, Is.EqualTo(0));
Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True);
}
} }
} }

View File

@ -0,0 +1,119 @@
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.CoreModules.World.Estate;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Services.Interfaces;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.Framework.Scenes.Tests
{
/// <summary>
/// Scene telehub tests
/// </summary>
/// <remarks>
/// TODO: Tests which run through normal functionality. Currently, the only test is one that checks behaviour
/// in the case of an error condition
/// </remarks>
[TestFixture]
public class SceneTelehubTests : OpenSimTestCase
{
/// <summary>
/// Test for desired behaviour when a telehub has no spawn points
/// </summary>
[Test]
public void TestNoTelehubSpawnPoints()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
EstateManagementModule emm = new EstateManagementModule();
SceneHelpers sh = new SceneHelpers();
Scene scene = sh.SetupScene();
SceneHelpers.SetupSceneModules(scene, emm);
UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1);
SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner);
emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId);
scene.RegionInfo.EstateSettings.AllowDirectTeleport = false;
// Must still be possible to successfully log in
UUID loggingInUserId = TestHelpers.ParseTail(0x2);
UserAccount ua
= UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password");
SceneHelpers.AddScenePresence(scene, ua);
Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null);
}
/// <summary>
/// Test for desired behaviour when the scene object nominated as a telehub object does not exist.
/// </summary>
[Test]
public void TestNoTelehubSceneObject()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
EstateManagementModule emm = new EstateManagementModule();
SceneHelpers sh = new SceneHelpers();
Scene scene = sh.SetupScene();
SceneHelpers.SetupSceneModules(scene, emm);
UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1);
SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner);
SceneObjectGroup spawnPointSo = SceneHelpers.AddSceneObject(scene, "spawnpointObject", telehubSceneObjectOwner);
emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId);
emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "spawnpoint add", spawnPointSo.LocalId);
scene.RegionInfo.EstateSettings.AllowDirectTeleport = false;
scene.DeleteSceneObject(telehubSo, false);
// Must still be possible to successfully log in
UUID loggingInUserId = TestHelpers.ParseTail(0x2);
UserAccount ua
= UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password");
SceneHelpers.AddScenePresence(scene, ua);
Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null);
}
}
}

View File

@ -172,7 +172,29 @@ namespace OpenSim.Region.Framework.Scenes
// If the prim is a sculpt then preserve this information too // If the prim is a sculpt then preserve this information too
if (part.Shape.SculptTexture != UUID.Zero) if (part.Shape.SculptTexture != UUID.Zero)
assetUuids[part.Shape.SculptTexture] = AssetType.Texture; assetUuids[part.Shape.SculptTexture] = AssetType.Texture;
if (part.Shape.ProjectionTextureUUID != UUID.Zero)
assetUuids[part.Shape.ProjectionTextureUUID] = AssetType.Texture;
if (part.CollisionSound != UUID.Zero)
assetUuids[part.CollisionSound] = AssetType.Sound;
if (part.ParticleSystem.Length > 0)
{
try
{
Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0);
if (ps.Texture != UUID.Zero)
assetUuids[ps.Texture] = AssetType.Texture;
}
catch (Exception e)
{
m_log.WarnFormat(
"[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.",
part.Name, part.UUID, sceneObject.Name, sceneObject.UUID);
}
}
TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
// Now analyze this prim's inventory items to preserve all the uuids that they reference // Now analyze this prim's inventory items to preserve all the uuids that they reference

View File

@ -903,7 +903,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
public void Start() public void Start()
{ {
m_scene.AddNewClient(this, PresenceType.User); m_scene.AddNewAgent(this, PresenceType.User);
// Mimicking LLClientView which gets always set appearance from client. // Mimicking LLClientView which gets always set appearance from client.
AvatarAppearance appearance; AvatarAppearance appearance;

View File

@ -304,7 +304,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
private string GetImageQueuesReport(string[] showParams) private string GetImageQueuesReport(string[] showParams)
{ {
if (showParams.Length < 5 || showParams.Length > 6) if (showParams.Length < 5 || showParams.Length > 6)
return "Usage: image queues show <first-name> <last-name> [full]"; return "Usage: show image queues <first-name> <last-name> [full]";
string firstName = showParams[3]; string firstName = showParams[3];
string lastName = showParams[4]; string lastName = showParams[4];
@ -395,7 +395,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding)); report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
report.AppendFormat( report.AppendFormat(
"{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7} {12,7}\n", "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7}\n",
"Since", "Since",
"Pkts", "Pkts",
"Pkts", "Pkts",
@ -407,12 +407,11 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
"Q Pkts", "Q Pkts",
"Q Pkts", "Q Pkts",
"Q Pkts", "Q Pkts",
"Q Pkts",
"Q Pkts"); "Q Pkts");
report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", ""); report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", "");
report.AppendFormat( report.AppendFormat(
"{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7} {12,7}\n", "{0,7} {1,7} {2,7} {3,7} {4,9} {5,7} {6,7} {7,7} {8,7} {9,7} {10,8} {11,7}\n",
"Last In", "Last In",
"In", "In",
"Out", "Out",
@ -424,8 +423,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
"Cloud", "Cloud",
"Task", "Task",
"Texture", "Texture",
"Asset", "Asset");
"State");
lock (m_scenes) lock (m_scenes)
{ {
@ -434,24 +432,24 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
scene.ForEachClient( scene.ForEachClient(
delegate(IClientAPI client) delegate(IClientAPI client)
{ {
bool isChild = client.SceneAgent.IsChildAgent;
if (isChild && !showChildren)
return;
string name = client.Name;
if (pname != "" && name != pname)
return;
string regionName = scene.RegionInfo.RegionName;
report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
if (client is IStatsCollector) if (client is IStatsCollector)
{ {
IStatsCollector stats = (IStatsCollector)client;
bool isChild = client.SceneAgent.IsChildAgent;
if (isChild && !showChildren)
return;
string name = client.Name;
if (pname != "" && name != pname)
return;
string regionName = scene.RegionInfo.RegionName;
report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
IStatsCollector stats = (IStatsCollector)client;
report.AppendLine(stats.Report()); report.AppendLine(stats.Report());
} }
}); });
@ -624,9 +622,16 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum(); int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
string childAgentStatus;
if (llClient.SceneAgent != null)
childAgentStatus = llClient.SceneAgent.IsChildAgent ? "N" : "Y";
else
childAgentStatus = "Off!";
m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
scene.RegionInfo.RegionName, llClient.Name, scene.RegionInfo.RegionName, llClient.Name,
llClient.SceneAgent.IsChildAgent ? "N" : "Y", childAgentStatus,
(DateTime.Now - cinfo.StartedTime).Minutes, (DateTime.Now - cinfo.StartedTime).Minutes,
avg_reqs, avg_reqs,
string.Format( string.Format(

View File

@ -39,6 +39,7 @@ using OpenSim.Framework.Communications;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
using System.Text;
using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
@ -421,44 +422,75 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
string Subject = im.message.Substring(0, im.message.IndexOf('|')); string Subject = im.message.Substring(0, im.message.IndexOf('|'));
string Message = im.message.Substring(Subject.Length + 1); string Message = im.message.Substring(Subject.Length + 1);
InventoryItemBase item = null;
bool hasAttachment = false;
UUID itemID = UUID.Zero; //Assignment to quiet compiler
UUID ownerID = UUID.Zero; //Assignment to quiet compiler
byte[] bucket; byte[] bucket;
if ((im.binaryBucket.Length == 1) && (im.binaryBucket[0] == 0)) if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0)
{
bucket = new byte[19];
bucket[0] = 0; //dunno
bucket[1] = 0; //dunno
GroupID.ToBytes(bucket, 2);
bucket[18] = 0; //dunno
}
else
{ {
string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket); string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
binBucket = binBucket.Remove(0, 14).Trim(); binBucket = binBucket.Remove(0, 14).Trim();
if (m_debugEnabled)
{
m_log.WarnFormat("I don't understand a group notice binary bucket of: {0}", binBucket);
OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket); OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket);
if (binBucketOSD is OSD)
foreach (string key in binBucketOSD.Keys) {
OSDMap binBucketMap = (OSDMap)binBucketOSD;
itemID = binBucketMap["item_id"].AsUUID();
ownerID = binBucketMap["owner_id"].AsUUID();
//Attempt to get the details of the attached item.
//If sender doesn't own the attachment, the item
//variable will be set to null and attachment will
//not be included with the group notice.
Scene scene = (Scene)remoteClient.Scene;
item = new InventoryItemBase(itemID, ownerID);
item = scene.InventoryService.GetItem(item);
if (item != null)
{ {
if (binBucketOSD.ContainsKey(key)) //Got item details so include the attachment.
{ hasAttachment = true;
m_log.WarnFormat("{0}: {1}", key, binBucketOSD[key].ToString());
}
} }
} }
else
// treat as if no attachment {
bucket = new byte[19]; m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType());
bucket[0] = 0; //dunno }
bucket[1] = 0; //dunno }
GroupID.ToBytes(bucket, 2);
bucket[18] = 0; //dunno if (hasAttachment)
{
//Bucket contains information about attachment.
//
//Byte offset and description of bucket data:
//0: 1 byte indicating if attachment is present
//1: 1 byte indicating the type of attachment
//2: 16 bytes - Group UUID
//18: 16 bytes - UUID of the attachment owner
//34: 16 bytes - UUID of the attachment
//50: variable - Name of the attachment
//??: NUL byte to terminate the attachment name
byte[] name = Encoding.UTF8.GetBytes(item.Name);
bucket = new byte[51 + name.Length];//3 bytes, 3 UUIDs, and name
bucket[0] = 1; //Has attachment flag
bucket[1] = (byte)item.InvType; //Type of Attachment
GroupID.ToBytes(bucket, 2);
ownerID.ToBytes(bucket, 18);
itemID.ToBytes(bucket, 34);
name.CopyTo(bucket, 50);
}
else
{
bucket = new byte[19];
bucket[0] = 0; //Has attachment flag
bucket[1] = 0; //Type of attachment
GroupID.ToBytes(bucket, 2);
bucket[18] = 0; //NUL terminate name of attachment
} }
m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket); m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket);
if (OnNewGroupNotice != null) if (OnNewGroupNotice != null)
{ {
@ -483,7 +515,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
if (member.AcceptNotices) if (member.AcceptNotices)
{ {
// Build notice IIM // Build notice IM
GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice); GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
msg.toAgentID = member.AgentID.Guid; msg.toAgentID = member.AgentID.Guid;
@ -492,10 +524,40 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
} }
} }
} }
if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted)
{
//Is bucket large enough to hold UUID of the attachment?
if (im.binaryBucket.Length < 16)
return;
UUID noticeID = new UUID(im.imSessionID);
GroupNoticeInfo notice = m_groupData.GetGroupNotice(GetRequestingAgentID(remoteClient), noticeID);
if (notice != null)
{
UUID giver = new UUID(notice.BinaryBucket, 18);
UUID attachmentUUID = new UUID(notice.BinaryBucket, 34);
if (m_debugEnabled)
m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId);
InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId,
giver, attachmentUUID);
if (itemCopy == null)
{
remoteClient.SendAgentAlertMessage("Can't find item to give. Nothing given.", false);
return;
}
remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0);
}
}
// Interop, received special 210 code for ejecting a group member // Interop, received special 210 code for ejecting a group member
// this only works within the comms servers domain, and won't work hypergrid // this only works within the comms servers domain, and won't work hypergrid
// TODO:FIXME: Use a presense server of some kind to find out where the // TODO:FIXME: Use a presence server of some kind to find out where the
// client actually is, and try contacting that region directly to notify them, // client actually is, and try contacting that region directly to notify them,
// or provide the notification via xmlrpc update queue // or provide the notification via xmlrpc update queue
if ((im.dialog == 210)) if ((im.dialog == 210))
@ -873,26 +935,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
if (data != null) if (data != null)
{ {
GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null); GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested);
GridInstantMessage msg = new GridInstantMessage();
msg.imSessionID = UUID.Zero.Guid;
msg.fromAgentID = data.GroupID.Guid;
msg.toAgentID = GetRequestingAgentID(remoteClient).Guid;
msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName;
msg.message = data.noticeData.Subject + "|" + data.Message;
msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested;
msg.fromGroup = true;
msg.offline = (byte)0;
msg.ParentEstateID = 0;
msg.Position = Vector3.Zero;
msg.RegionID = UUID.Zero.Guid;
msg.binaryBucket = data.BinaryBucket;
OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient)); OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
} }
} }
public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog) public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
@ -900,10 +946,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
GridInstantMessage msg = new GridInstantMessage(); GridInstantMessage msg = new GridInstantMessage();
msg.imSessionID = UUID.Zero.Guid; byte[] bucket;
msg.imSessionID = groupNoticeID.Guid;
msg.toAgentID = agentID.Guid; msg.toAgentID = agentID.Guid;
msg.dialog = dialog; msg.dialog = dialog;
// msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
msg.fromGroup = true; msg.fromGroup = true;
msg.offline = (byte)0; msg.offline = (byte)0;
msg.ParentEstateID = 0; msg.ParentEstateID = 0;
@ -917,13 +964,38 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
msg.timestamp = info.noticeData.Timestamp; msg.timestamp = info.noticeData.Timestamp;
msg.fromAgentName = info.noticeData.FromName; msg.fromAgentName = info.noticeData.FromName;
msg.message = info.noticeData.Subject + "|" + info.Message; msg.message = info.noticeData.Subject + "|" + info.Message;
msg.binaryBucket = info.BinaryBucket;
if (info.BinaryBucket[0] > 0)
{
//32 is due to not needing space for two of the UUIDs.
//(Don't need UUID of attachment or its owner in IM)
//50 offset gets us to start of attachment name.
//We are skipping the attachment flag, type, and
//the three UUID fields at the start of the bucket.
bucket = new byte[info.BinaryBucket.Length-32];
bucket[0] = 1; //Has attachment
bucket[1] = info.BinaryBucket[1];
Array.Copy(info.BinaryBucket, 50,
bucket, 18, info.BinaryBucket.Length-50);
}
else
{
bucket = new byte[19];
bucket[0] = 0; //No attachment
bucket[1] = 0; //Attachment type
bucket[18] = 0; //NUL terminate name
}
info.GroupID.ToBytes(bucket, 2);
msg.binaryBucket = bucket;
} }
else else
{ {
if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID); if (m_debugEnabled)
m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID);
msg.fromAgentID = UUID.Zero.Guid; msg.fromAgentID = UUID.Zero.Guid;
msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ; msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
msg.fromAgentName = string.Empty; msg.fromAgentName = string.Empty;
msg.message = string.Empty; msg.message = string.Empty;
msg.binaryBucket = new byte[0]; msg.binaryBucket = new byte[0];
@ -1047,7 +1119,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
// Message to ejector // Message to ejector
// Interop, received special 210 code for ejecting a group member // Interop, received special 210 code for ejecting a group member
// this only works within the comms servers domain, and won't work hypergrid // this only works within the comms servers domain, and won't work hypergrid
// TODO:FIXME: Use a presense server of some kind to find out where the // TODO:FIXME: Use a presence server of some kind to find out where the
// client actually is, and try contacting that region directly to notify them, // client actually is, and try contacting that region directly to notify them,
// or provide the notification via xmlrpc update queue // or provide the notification via xmlrpc update queue

View File

@ -29,12 +29,14 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.CoreModules; using OpenSim.Region.CoreModules;
using OpenSim.Region.Framework; using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Physics.Manager;
using Mono.Addins; using Mono.Addins;
using Nini.Config; using Nini.Config;
@ -60,6 +62,10 @@ public class ExtendedPhysics : INonSharedRegionModule
// Per prim functions. See BSPrim. // Per prim functions. See BSPrim.
public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed";
public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType";
public const string PhysFunctGetLinkType = "BulletSim.GetLinkType";
public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams";
// ============================================================= // =============================================================
@ -155,7 +161,7 @@ public class ExtendedPhysics : INonSharedRegionModule
} }
[ScriptConstant] [ScriptConstant]
public static int PHYS_CENTER_OF_MASS = 1 << 0; public const int PHYS_CENTER_OF_MASS = 1 << 0;
[ScriptInvocation] [ScriptInvocation]
public string physGetEngineType(UUID hostID, UUID scriptID) public string physGetEngineType(UUID hostID, UUID scriptID)
@ -171,11 +177,11 @@ public class ExtendedPhysics : INonSharedRegionModule
} }
[ScriptConstant] [ScriptConstant]
public static int PHYS_LINKSET_TYPE_CONSTRAINT = 0; public const int PHYS_LINKSET_TYPE_CONSTRAINT = 0;
[ScriptConstant] [ScriptConstant]
public static int PHYS_LINKSET_TYPE_COMPOUND = 1; public const int PHYS_LINKSET_TYPE_COMPOUND = 1;
[ScriptConstant] [ScriptConstant]
public static int PHYS_LINKSET_TYPE_MANUAL = 2; public const int PHYS_LINKSET_TYPE_MANUAL = 2;
[ScriptInvocation] [ScriptInvocation]
public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
@ -195,10 +201,38 @@ public class ExtendedPhysics : INonSharedRegionModule
if (rootPart != null) if (rootPart != null)
{ {
Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; PhysicsActor rootPhysActor = rootPart.PhysActor;
if (rootPhysActor != null) 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);
object[] parms2 = { rootPhysActor, null, linksetType };
ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2));
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.
object[] parms2 = { rootPhysActor, null, linksetType };
ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2));
}
} }
else else
{ {
@ -223,7 +257,6 @@ public class ExtendedPhysics : INonSharedRegionModule
public int physGetLinksetType(UUID hostID, UUID scriptID) public int physGetLinksetType(UUID hostID, UUID scriptID)
{ {
int ret = -1; int ret = -1;
if (!Enabled) return ret; if (!Enabled) return ret;
// The part that is requesting the change. // The part that is requesting the change.
@ -237,10 +270,11 @@ public class ExtendedPhysics : INonSharedRegionModule
if (rootPart != null) if (rootPart != null)
{ {
Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; PhysicsActor rootPhysActor = rootPart.PhysActor;
if (rootPhysActor != null) if (rootPhysActor != null)
{ {
ret = (int)rootPhysActor.Extension(PhysFunctGetLinksetType); object[] parms2 = { rootPhysActor, null };
ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType, parms2));
} }
else else
{ {
@ -260,5 +294,288 @@ public class ExtendedPhysics : INonSharedRegionModule
} }
return ret; return ret;
} }
[ScriptConstant]
public const int PHYS_LINK_TYPE_FIXED = 1234;
[ScriptConstant]
public const int PHYS_LINK_TYPE_HINGE = 4;
[ScriptConstant]
public const int PHYS_LINK_TYPE_SPRING = 9;
[ScriptConstant]
public const int PHYS_LINK_TYPE_6DOF = 6;
[ScriptConstant]
public const 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))
{
object[] parms2 = { rootPhysActor, childPhysActor, typeCode };
ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2));
}
return ret;
}
// physGetLinkType(integer linkNum)
[ScriptInvocation]
public int physGetLinkType(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))
{
object[] parms2 = { rootPhysActor, childPhysActor };
ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, parms2));
}
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))
{
object[] parms2 = { rootPhysActor, childPhysActor , PHYS_LINK_TYPE_FIXED };
ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2));
}
return ret;
}
// Code for specifying params.
// The choice if 14400 is arbitrary and only serves to catch parameter code misuse.
public const int PHYS_PARAM_MIN = 14401;
[ScriptConstant]
public const int PHYS_PARAM_FRAMEINA_LOC = 14401;
[ScriptConstant]
public const int PHYS_PARAM_FRAMEINA_ROT = 14402;
[ScriptConstant]
public const int PHYS_PARAM_FRAMEINB_LOC = 14403;
[ScriptConstant]
public const int PHYS_PARAM_FRAMEINB_ROT = 14404;
[ScriptConstant]
public const int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405;
[ScriptConstant]
public const int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406;
[ScriptConstant]
public const int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407;
[ScriptConstant]
public const int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408;
[ScriptConstant]
public const int PHYS_PARAM_USE_FRAME_OFFSET = 14409;
[ScriptConstant]
public const int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410;
[ScriptConstant]
public const int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411;
[ScriptConstant]
public const int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412;
[ScriptConstant]
public const int PHYS_PARAM_CFM = 14413;
[ScriptConstant]
public const int PHYS_PARAM_ERP = 14414;
[ScriptConstant]
public const int PHYS_PARAM_SOLVER_ITERATIONS = 14415;
[ScriptConstant]
public const int PHYS_PARAM_SPRING_AXIS_ENABLE = 14416;
[ScriptConstant]
public const int PHYS_PARAM_SPRING_DAMPING = 14417;
[ScriptConstant]
public const int PHYS_PARAM_SPRING_STIFFNESS = 14418;
[ScriptConstant]
public const int PHYS_PARAM_LINK_TYPE = 14419;
[ScriptConstant]
public const int PHYS_PARAM_USE_LINEAR_FRAMEA = 14420;
[ScriptConstant]
public const int PHYS_PARAM_SPRING_EQUILIBRIUM_POINT = 14421;
public const int PHYS_PARAM_MAX = 14421;
// Used when specifying a parameter that has settings for the three linear and three angular axis
[ScriptConstant]
public const int PHYS_AXIS_ALL = -1;
[ScriptConstant]
public const int PHYS_AXIS_LINEAR_ALL = -2;
[ScriptConstant]
public const int PHYS_AXIS_ANGULAR_ALL = -3;
[ScriptConstant]
public const int PHYS_AXIS_LINEAR_X = 0;
[ScriptConstant]
public const int PHYS_AXIS_LINEAR_Y = 1;
[ScriptConstant]
public const int PHYS_AXIS_LINEAR_Z = 2;
[ScriptConstant]
public const int PHYS_AXIS_ANGULAR_X = 3;
[ScriptConstant]
public const int PHYS_AXIS_ANGULAR_Y = 4;
[ScriptConstant]
public const int PHYS_AXIS_ANGULAR_Z = 5;
// 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))
{
object[] parms2 = AddToBeginningOfArray(rootPhysActor, childPhysActor, parms);
ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, parms2));
}
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;
}
// Return an array of objects with the passed object as the first object of a new array
private object[] AddToBeginningOfArray(object firstOne, object secondOne, object[] prevArray)
{
object[] newArray = new object[2 + prevArray.Length];
newArray[0] = firstOne;
newArray[1] = secondOne;
prevArray.CopyTo(newArray, 2);
return newArray;
}
// 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

@ -44,6 +44,20 @@ namespace OpenSim.Region.OptionalModules.World.NPC
{ {
public bool SenseAsAgent { get; set; } public bool SenseAsAgent { get; set; }
public delegate void ChatToNPC(
string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, UUID ownerID, byte source, byte audible);
/// <summary>
/// Fired when the NPC receives a chat message.
/// </summary>
public event ChatToNPC OnChatToNPC;
/// <summary>
/// Fired when the NPC receives an instant message.
/// </summary>
public event Action<GridInstantMessage> OnInstantMessageToNPC;
private readonly string m_firstname; private readonly string m_firstname;
private readonly string m_lastname; private readonly string m_lastname;
private readonly Vector3 m_startPos; private readonly Vector3 m_startPos;
@ -614,17 +628,18 @@ namespace OpenSim.Region.OptionalModules.World.NPC
string message, byte type, Vector3 fromPos, string fromName, string message, byte type, Vector3 fromPos, string fromName,
UUID fromAgentID, UUID ownerID, byte source, byte audible) UUID fromAgentID, UUID ownerID, byte source, byte audible)
{ {
} ChatToNPC ctn = OnChatToNPC;
public virtual void SendChatMessage( if (ctn != null)
byte[] message, byte type, Vector3 fromPos, string fromName, ctn(message, type, fromPos, fromName, fromAgentID, ownerID, source, audible);
UUID fromAgentID, UUID ownerID, byte source, byte audible)
{
} }
public void SendInstantMessage(GridInstantMessage im) public void SendInstantMessage(GridInstantMessage im)
{ {
Action<GridInstantMessage> oimtn = OnInstantMessageToNPC;
if (oimtn != null)
oimtn(im);
} }
public void SendGenericMessage(string method, UUID invoice, List<string> message) public void SendGenericMessage(string method, UUID invoice, List<string> message)

View File

@ -146,9 +146,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC
int.MaxValue); int.MaxValue);
m_log.DebugFormat( m_log.DebugFormat(
"[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}",
firstname, lastname, npcAvatar.AgentId, owner, firstname, lastname, npcAvatar.AgentId, owner,
senseAsAgent, position, scene.RegionInfo.RegionName); senseAsAgent, position, scene.RegionInfo.RegionName);
AgentCircuitData acd = new AgentCircuitData(); AgentCircuitData acd = new AgentCircuitData();
acd.AgentID = npcAvatar.AgentId; acd.AgentID = npcAvatar.AgentId;
@ -175,7 +175,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
{ {
scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode,
acd); acd);
scene.AddNewClient(npcAvatar, PresenceType.Npc); scene.AddNewAgent(npcAvatar, PresenceType.Npc);
ScenePresence sp; ScenePresence sp;
if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp))
@ -188,16 +188,16 @@ namespace OpenSim.Region.OptionalModules.World.NPC
sp.CompleteMovement(npcAvatar, false); sp.CompleteMovement(npcAvatar, false);
m_avatars.Add(npcAvatar.AgentId, npcAvatar); m_avatars.Add(npcAvatar.AgentId, npcAvatar);
m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name);
npcAvatar.AgentId, sp.Name);
return npcAvatar.AgentId; return npcAvatar.AgentId;
} }
else else
{ {
m_log.WarnFormat( m_log.WarnFormat(
"[NPC MODULE]: Could not find scene presence for NPC {0} {1}", "[NPC MODULE]: Could not find scene presence for NPC {0} {1}",
sp.Name, sp.UUID); sp.Name, sp.UUID);
return UUID.Zero; return UUID.Zero;
} }
} }
@ -213,10 +213,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC
ScenePresence sp; ScenePresence sp;
if (scene.TryGetScenePresence(agentID, out sp)) if (scene.TryGetScenePresence(agentID, out sp))
{ {
m_log.DebugFormat( // m_log.DebugFormat(
"[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", // "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}",
sp.Name, pos, scene.RegionInfo.RegionName, // sp.Name, pos, scene.RegionInfo.RegionName,
noFly, landAtTarget); // noFly, landAtTarget);
sp.MoveToTarget(pos, noFly, landAtTarget); sp.MoveToTarget(pos, noFly, landAtTarget);
sp.SetAlwaysRun = running; sp.SetAlwaysRun = running;
@ -293,9 +293,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
ScenePresence sp; ScenePresence sp;
if (scene.TryGetScenePresence(agentID, out sp)) if (scene.TryGetScenePresence(agentID, out sp))
{ {
sp.HandleAgentRequestSit(m_avatars[agentID], agentID, sp.HandleAgentRequestSit(m_avatars[agentID], agentID, partID, Vector3.Zero);
partID, Vector3.Zero);
//sp.HandleAgentSit(m_avatars[agentID], agentID);
return true; return true;
} }
@ -386,9 +384,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC
agentID, av.Name); agentID, av.Name);
*/ */
scene.IncomingCloseAgent(agentID, false); scene.CloseAgent(agentID, false);
// scene.RemoveClient(agentID, false);
m_avatars.Remove(agentID); m_avatars.Remove(agentID);
/* /*
m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}", m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}",
agentID, av.Name); agentID, av.Name);
@ -427,4 +426,4 @@ namespace OpenSim.Region.OptionalModules.World.NPC
av.OwnerID == callerID; av.OwnerID == callerID;
} }
} }
} }

View File

@ -596,6 +596,60 @@ public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, flo
return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); 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) public override bool CalculateTransforms(BulletConstraint constrain)
{ {
BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
@ -671,6 +725,13 @@ public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
} }
public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj)
{
BulletWorldUnman worldu = world as BulletWorldUnman;
BulletBodyUnman bodyu = obj as BulletBodyUnman;
return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr);
}
public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
{ {
BulletWorldUnman worldu = world as BulletWorldUnman; BulletWorldUnman worldu = world as BulletWorldUnman;
@ -1600,6 +1661,33 @@ public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enabl
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); 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] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CalculateTransforms2(IntPtr constrain); public static extern bool CalculateTransforms2(IntPtr constrain);
@ -1631,6 +1719,9 @@ public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);

View File

@ -169,6 +169,19 @@ private sealed class BulletConstraintXNA : BulletConstraint
return true; return true;
} }
public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody)
{
DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null)
{
world.RemoveCollisionObject(collisionObject);
world.AddCollisionObject(collisionObject);
}
return true;
}
public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
{ {
DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
@ -752,6 +765,214 @@ private sealed class BulletConstraintXNA : BulletConstraint
constraint.SetBreakingImpulseThreshold(threshold); constraint.SetBreakingImpulseThreshold(threshold);
return true; 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); //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
public override void SetAngularDamping(BulletBody pBody, float angularDamping) public override void SetAngularDamping(BulletBody pBody, float angularDamping)
{ {

View File

@ -105,7 +105,7 @@ public class BSActorAvatarMove : BSActor
// into the movement motor. // into the movement motor.
public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
{ {
m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate() m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate()
{ {
if (m_velocityMotor != null) if (m_velocityMotor != null)
{ {
@ -128,6 +128,7 @@ public class BSActorAvatarMove : BSActor
BSMotor.Infinite, // decay time scale BSMotor.Infinite, // decay time scale
1f // efficiency 1f // efficiency
); );
m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold;
// _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
@ -278,6 +279,7 @@ public class BSActorAvatarMove : BSActor
if (m_controllingPrim.IsStationary) if (m_controllingPrim.IsStationary)
{ {
entprop.Position = m_controllingPrim.RawPosition; entprop.Position = m_controllingPrim.RawPosition;
entprop.Velocity = OMV.Vector3.Zero;
m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation);
} }

View File

@ -43,7 +43,9 @@ public enum ConstraintType : int
SLIDER_CONSTRAINT_TYPE, SLIDER_CONSTRAINT_TYPE,
CONTACT_CONSTRAINT_TYPE, CONTACT_CONSTRAINT_TYPE,
D6_SPRING_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
} }
// =============================================================================== // ===============================================================================
@ -290,7 +292,7 @@ public enum ConstraintParamAxis : int
AXIS_ANGULAR_X, AXIS_ANGULAR_X,
AXIS_ANGULAR_Y, AXIS_ANGULAR_Y,
AXIS_ANGULAR_Z, AXIS_ANGULAR_Z,
AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls
AXIS_ANGULAR_ALL, AXIS_ANGULAR_ALL,
AXIS_ALL AXIS_ALL
}; };
@ -441,6 +443,38 @@ public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float e
public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); 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 CalculateTransforms(BulletConstraint constrain);
public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
@ -464,6 +498,8 @@ public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj);
public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);

View File

@ -93,7 +93,7 @@ public sealed class BSCharacter : BSPhysObject
LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos); LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos);
// do actual creation in taint time // do actual creation in taint time
PhysScene.TaintedObject("BSCharacter.create", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
{ {
DetailLog("{0},BSCharacter.create,taint", LocalID); DetailLog("{0},BSCharacter.create,taint", LocalID);
// New body and shape into PhysBody and PhysShape // New body and shape into PhysBody and PhysShape
@ -121,7 +121,7 @@ public sealed class BSCharacter : BSPhysObject
base.Destroy(); base.Destroy();
DetailLog("{0},BSCharacter.Destroy", LocalID); DetailLog("{0},BSCharacter.Destroy", LocalID);
PhysScene.TaintedObject("BSCharacter.destroy", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
{ {
PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
PhysBody.Clear(); PhysBody.Clear();
@ -209,7 +209,7 @@ public sealed class BSCharacter : BSPhysObject
DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, Density, _avatarVolume, RawMass); LocalID, _size, Scale, Density, _avatarVolume, RawMass);
PhysScene.TaintedObject("BSCharacter.setSize", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
{ {
if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
{ {
@ -257,7 +257,7 @@ public sealed class BSCharacter : BSPhysObject
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties directly into the physics engine // Zero some other properties directly into the physics engine
PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
{ {
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
PhysScene.PE.ClearAllForces(PhysBody); PhysScene.PE.ClearAllForces(PhysBody);
@ -267,7 +267,7 @@ public sealed class BSCharacter : BSPhysObject
{ {
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
{ {
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
{ {
@ -291,7 +291,7 @@ public sealed class BSCharacter : BSPhysObject
set { set {
RawPosition = value; RawPosition = value;
PhysScene.TaintedObject("BSCharacter.setPosition", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
{ {
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
PositionSanityCheck(); PositionSanityCheck();
@ -363,7 +363,7 @@ public sealed class BSCharacter : BSPhysObject
{ {
// The new position value must be pushed into the physics engine but we can't // The new position value must be pushed into the physics engine but we can't
// just assign to "Position" because of potential call loops. // just assign to "Position" because of potential call loops.
PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
{ {
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
ForcePosition = RawPosition; ForcePosition = RawPosition;
@ -390,7 +390,7 @@ public sealed class BSCharacter : BSPhysObject
set { set {
RawForce = value; RawForce = value;
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
PhysScene.TaintedObject("BSCharacter.SetForce", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
{ {
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
@ -438,7 +438,7 @@ public sealed class BSCharacter : BSPhysObject
set { set {
RawVelocity = value; RawVelocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
PhysScene.TaintedObject("BSCharacter.setVelocity", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
{ {
if (m_moveActor != null) if (m_moveActor != null)
m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
@ -480,7 +480,7 @@ public sealed class BSCharacter : BSPhysObject
if (RawOrientation != value) if (RawOrientation != value)
{ {
RawOrientation = value; RawOrientation = value;
PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
{ {
// Bullet assumes we know what we are doing when forcing orientation // Bullet assumes we know what we are doing when forcing orientation
// so it lets us go against all the rules and just compensates for them later. // so it lets us go against all the rules and just compensates for them later.
@ -560,7 +560,7 @@ public sealed class BSCharacter : BSPhysObject
public override bool FloatOnWater { public override bool FloatOnWater {
set { set {
_floatOnWater = value; _floatOnWater = value;
PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
{ {
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
{ {
@ -588,7 +588,7 @@ public sealed class BSCharacter : BSPhysObject
public override float Buoyancy { public override float Buoyancy {
get { return _buoyancy; } get { return _buoyancy; }
set { _buoyancy = value; set { _buoyancy = value;
PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate() PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
{ {
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
ForceBuoyancy = _buoyancy; ForceBuoyancy = _buoyancy;
@ -633,7 +633,7 @@ public sealed class BSCharacter : BSPhysObject
OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
// DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
{ {
// Bullet adds this central force to the total force for this tick // Bullet adds this central force to the total force for this tick
// DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
@ -676,18 +676,20 @@ public sealed class BSCharacter : BSPhysObject
float heightAdjust = BSParam.AvatarHeightMidFudge; float heightAdjust = BSParam.AvatarHeightMidFudge;
if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
{ {
// An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m. const float AVATAR_LOW = 1.1f;
// The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25 const float AVATAR_MID = 1.775f; // 1.87f
float midHeightOffset = size.Z - 1.87f; const float AVATAR_HI = 2.45f;
// An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
float midHeightOffset = size.Z - AVATAR_MID;
if (midHeightOffset < 0f) if (midHeightOffset < 0f)
{ {
// Small avatar. Add the adjustment based on the distance from midheight // Small avatar. Add the adjustment based on the distance from midheight
heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge; heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
} }
else else
{ {
// Large avatar. Add the adjustment based on the distance from midheight // Large avatar. Add the adjustment based on the distance from midheight
heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge; heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
} }
} }
// The total scale height is the central cylindar plus the caps on the two ends. // The total scale height is the central cylindar plus the caps on the two ends.
@ -698,6 +700,9 @@ public sealed class BSCharacter : BSPhysObject
if (newScale.Z < 0) if (newScale.Z < 0)
newScale.Z = 0.1f; newScale.Z = 0.1f;
DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
return newScale; return newScale;
} }

View File

@ -64,7 +64,7 @@ public abstract class BSConstraint : IDisposable
{ {
bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
BSScene.DetailLogZero, m_body1.ID,
m_body1.ID, m_body1.AddrString, m_body1.ID, m_body1.AddrString,
m_body2.ID, m_body2.AddrString, m_body2.ID, m_body2.AddrString,
success); success);
@ -77,7 +77,10 @@ public abstract class BSConstraint : IDisposable
{ {
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
{
m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high);
ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
}
return ret; return ret;
} }
@ -86,6 +89,7 @@ public abstract class BSConstraint : IDisposable
bool ret = false; bool ret = false;
if (m_enabled) if (m_enabled)
{ {
m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high);
ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
} }
return ret; return ret;

View File

@ -32,12 +32,19 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public sealed class BSConstraint6Dof : BSConstraint public class BSConstraint6Dof : BSConstraint
{ {
private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 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 // Create a btGeneric6DofConstraint
public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
Vector3 frame1, Quaternion frame1rot, Vector3 frame1, Quaternion frame1rot,
@ -52,9 +59,11 @@ public sealed class BSConstraint6Dof : BSConstraint
frame2, frame2rot, frame2, frame2rot,
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
m_enabled = true; m_enabled = true;
world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
BSScene.DetailLogZero, world.worldID, m_body1.ID, world.worldID,
obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
} }
// 6 Dof constraint based on a midpoint between the two constrained bodies // 6 Dof constraint based on a midpoint between the two constrained bodies
@ -79,9 +88,11 @@ public sealed class BSConstraint6Dof : BSConstraint
m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
joinPoint, joinPoint,
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
BSScene.DetailLogZero, world.worldID, m_constraint.AddrString, m_body1.ID, world.worldID, m_constraint.AddrString,
obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
if (!m_constraint.HasPhysicalConstraint) if (!m_constraint.HasPhysicalConstraint)
{ {
world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
@ -106,8 +117,10 @@ public sealed class BSConstraint6Dof : BSConstraint
frameInBloc, frameInBrot, frameInBloc, frameInBrot,
useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
m_enabled = true; m_enabled = true;
world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); m_body1.ID, world.worldID, obj1.ID, obj1.AddrString);
PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}",
m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
} }
public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)

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,103 @@
/*
* 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;
PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
}
public bool SetAxisEnable(int pIndex, bool pAxisEnable)
{
PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}",
m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable);
PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable));
return true;
}
public bool SetStiffness(int pIndex, float pStiffness)
{
PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}",
m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness);
PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness);
return true;
}
public bool SetDamping(int pIndex, float pDamping)
{
PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}",
m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping);
PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping);
return true;
}
public bool SetEquilibriumPoint(int pIndex, float pEqPoint)
{
PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}",
m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint);
PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint);
return true;
}
public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq)
{
PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}",
m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq);
PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X);
PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y);
PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z);
PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X);
PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y);
PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z);
return true;
}
}
}

View File

@ -77,6 +77,10 @@ public abstract class BSLinkset
{ {
member = pMember; 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; } 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 // Returns a new linkset for the child which is a linkset of one (just the
// orphened child). // orphened child).
// Called at runtime. // Called at runtime.
public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child) public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
{ {
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
@ -157,7 +161,7 @@ public abstract class BSLinkset
// Cannot remove the root from a linkset. // Cannot remove the root from a linkset.
return this; return this;
} }
RemoveChildFromLinkset(child); RemoveChildFromLinkset(child, inTaintTime);
LinksetMass = ComputeLinksetMass(); LinksetMass = ComputeLinksetMass();
} }
@ -205,6 +209,17 @@ public abstract class BSLinkset
return ret; return ret;
} }
public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
{
bool ret = false;
BSLinkInfo found = null;
lock (m_linksetActivityLock)
{
ret = m_children.TryGetValue(child, out found);
}
foundInfo = found;
return ret;
}
// Perform an action on each member of the linkset including root prim. // Perform an action on each member of the linkset including root prim.
// Depends on the action on whether this should be done at taint time. // Depends on the action on whether this should be done at taint time.
public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
@ -222,6 +237,21 @@ public abstract class BSLinkset
return ret; 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. // 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 // 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. // anything to add for the collision and it should be passed through normal processing.
@ -255,7 +285,7 @@ public abstract class BSLinkset
// I am the root of a linkset and one of my children is being removed. // 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. // 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 // When physical properties are changed the linkset needs to recalculate
// its internal properties. // its internal properties.
@ -430,6 +460,13 @@ public abstract class BSLinkset
return com; 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. // Invoke the detailed logger and output something if it's enabled.
protected void DetailLog(string msg, params Object[] args) protected void DetailLog(string msg, params Object[] args)
{ {

View File

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

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
@ -28,6 +28,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using OpenSim.Region.OptionalModules.Scripting;
using OMV = OpenMetaverse; using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin namespace OpenSim.Region.Physics.BulletSPlugin
@ -51,18 +53,32 @@ public sealed class BSLinksetConstraints : BSLinkset
public float cfm; public float cfm;
public float erp; public float erp;
public float solverIterations; public float solverIterations;
//
public OMV.Vector3 frameInAloc;
public OMV.Quaternion frameInArot;
public OMV.Vector3 frameInBloc;
public OMV.Quaternion frameInBrot;
public bool useLinearReferenceFrameA;
// Spring
public bool[] springAxisEnable;
public float[] springDamping;
public float[] springStiffness;
public OMV.Vector3 springLinearEquilibriumPoint;
public OMV.Vector3 springAngularEquilibriumPoint;
public BSLinkInfoConstraint(BSPrimLinkable pMember) public BSLinkInfoConstraint(BSPrimLinkable pMember)
: base(pMember) : base(pMember)
{ {
constraint = null; constraint = null;
ResetToFixedConstraint(); ResetLink();
member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID);
} }
// Set all the parameters for this constraint to a fixed, non-movable constraint. // 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; linearLimitLow = OMV.Vector3.Zero;
linearLimitHigh = OMV.Vector3.Zero; linearLimitHigh = OMV.Vector3.Zero;
angularLimitLow = OMV.Vector3.Zero; angularLimitLow = OMV.Vector3.Zero;
@ -74,17 +90,37 @@ public sealed class BSLinksetConstraints : BSLinkset
cfm = BSParam.LinkConstraintCFM; cfm = BSParam.LinkConstraintCFM;
erp = BSParam.LinkConstraintERP; erp = BSParam.LinkConstraintERP;
solverIterations = BSParam.LinkConstraintSolverIterations; solverIterations = BSParam.LinkConstraintSolverIterations;
frameInAloc = OMV.Vector3.Zero;
frameInArot = OMV.Quaternion.Identity;
frameInBloc = OMV.Vector3.Zero;
frameInBrot = OMV.Quaternion.Identity;
useLinearReferenceFrameA = true;
springAxisEnable = new bool[6];
springDamping = new float[6];
springStiffness = new float[6];
for (int ii = 0; ii < springAxisEnable.Length; ii++)
{
springAxisEnable[ii] = false;
springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
}
springLinearEquilibriumPoint = OMV.Vector3.Zero;
springAngularEquilibriumPoint = OMV.Vector3.Zero;
member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID);
} }
// Given a constraint, apply the current constraint parameters to same. // Given a constraint, apply the current constraint parameters to same.
public void SetConstraintParameters(BSConstraint constrain) public override void SetLinkParameters(BSConstraint constrain)
{ {
member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType);
switch (constraintType) switch (constraintType)
{ {
case ConstraintType.FIXED_CONSTRAINT_TYPE:
case ConstraintType.D6_CONSTRAINT_TYPE: case ConstraintType.D6_CONSTRAINT_TYPE:
BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
if (constrain6dof != null) 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 // zero linear and angular limits makes the objects unable to move in relation to each other
constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
@ -99,10 +135,55 @@ public sealed class BSLinksetConstraints : BSLinkset
} }
} }
break; 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 < springAxisEnable.Length; ii++)
{
constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]);
if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
constrainSpring.SetDamping(ii, springDamping[ii]);
if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
constrainSpring.SetStiffness(ii, springStiffness[ii]);
}
constrainSpring.CalculateTransforms();
if (springLinearEquilibriumPoint != OMV.Vector3.Zero)
constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint);
else
constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED);
}
break;
default: default:
break; 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) public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
@ -110,12 +191,15 @@ public sealed class BSLinksetConstraints : BSLinkset
LinksetImpl = LinksetImplementation.Constraint; LinksetImpl = LinksetImplementation.Constraint;
} }
private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]";
// When physical properties are changed the linkset needs to recalculate // When physical properties are changed the linkset needs to recalculate
// its internal properties. // its internal properties.
// This is queued in the 'post taint' queue so the // This is queued in the 'post taint' queue so the
// refresh will happen once after all the other taints are applied. // refresh will happen once after all the other taints are applied.
public override void Refresh(BSPrimLinkable requestor) public override void Refresh(BSPrimLinkable requestor)
{ {
ScheduleRebuild(requestor);
base.Refresh(requestor); base.Refresh(requestor);
} }
@ -132,10 +216,16 @@ public sealed class BSLinksetConstraints : BSLinkset
{ {
// Queue to happen after all the other taint processing // Queue to happen after all the other taint processing
m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
{
if (HasAnyChildren)
{ {
if (HasAnyChildren) // Constraints that have not been changed are not rebuild but make sure
RecomputeLinksetConstraints(); // the constraint of the requestor is rebuilt.
}); PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor);
// Rebuild the linkset and all its constraints.
RecomputeLinksetConstraints();
}
});
} }
} }
@ -152,7 +242,7 @@ public sealed class BSLinksetConstraints : BSLinkset
if (IsRoot(child)) if (IsRoot(child))
{ {
// The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
ScheduleRebuild(LinksetRoot); Refresh(LinksetRoot);
} }
return ret; return ret;
} }
@ -171,7 +261,7 @@ public sealed class BSLinksetConstraints : BSLinkset
if (IsRoot(child)) if (IsRoot(child))
{ {
// Schedule a rebuild to verify that the root shape is set to the real shape. // Schedule a rebuild to verify that the root shape is set to the real shape.
ScheduleRebuild(LinksetRoot); Refresh(LinksetRoot);
} }
return ret; return ret;
} }
@ -199,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// Just undo all the constraints for this linkset. Rebuild at the end of the step. // Just undo all the constraints for this linkset. Rebuild at the end of the step.
ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
// Cause the constraints, et al to be rebuilt before the next simulation step. // Cause the constraints, et al to be rebuilt before the next simulation step.
ScheduleRebuild(LinksetRoot); Refresh(LinksetRoot);
} }
return ret; return ret;
} }
@ -217,14 +307,14 @@ public sealed class BSLinksetConstraints : BSLinkset
DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
// Cause constraints and assorted properties to be recomputed before the next simulation step. // Cause constraints and assorted properties to be recomputed before the next simulation step.
ScheduleRebuild(LinksetRoot); Refresh(LinksetRoot);
} }
return; return;
} }
// Remove the specified child from the linkset. // Remove the specified child from the linkset.
// Safe to call even if the child is not really in my 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)) if (m_children.Remove(child))
{ {
@ -236,12 +326,12 @@ public sealed class BSLinksetConstraints : BSLinkset
rootx.LocalID, rootx.PhysBody.AddrString, rootx.LocalID, rootx.PhysBody.AddrString,
childx.LocalID, childx.PhysBody.AddrString); childx.LocalID, childx.PhysBody.AddrString);
m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate()
{ {
PhysicallyUnlinkAChildFromRoot(rootx, childx); PhysicallyUnlinkAChildFromRoot(rootx, childx);
}); });
// See that the linkset parameters are recomputed at the end of the taint time. // See that the linkset parameters are recomputed at the end of the taint time.
ScheduleRebuild(LinksetRoot); Refresh(LinksetRoot);
} }
else else
{ {
@ -262,8 +352,8 @@ public sealed class BSLinksetConstraints : BSLinkset
// Create a static constraint between the two passed objects // Create a static constraint between the two passed objects
private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
{ {
BSLinkInfoConstraint liConstraint = li as BSLinkInfoConstraint; BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint;
if (liConstraint == null) if (linkInfo == null)
return null; return null;
// Zero motion for children so they don't interpolate // Zero motion for children so they don't interpolate
@ -271,27 +361,26 @@ public sealed class BSLinksetConstraints : BSLinkset
BSConstraint constrain = null; BSConstraint constrain = null;
switch (liConstraint.constraintType) switch (linkInfo.constraintType)
{ {
case ConstraintType.FIXED_CONSTRAINT_TYPE:
case ConstraintType.D6_CONSTRAINT_TYPE: case ConstraintType.D6_CONSTRAINT_TYPE:
// Relative position normalized to the root prim // Relative position normalized to the root prim
// Essentually a vector pointing from center of rootPrim to center of li.member // 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 // real world coordinate of midpoint between the two objects
OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 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}", DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}",
rootPrim.LocalID, rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody,
rootPrim.LocalID, rootPrim.PhysBody.AddrString, rootPrim.Position, linkInfo.member.Position, midPoint);
liConstraint.member.LocalID, liConstraint.member.PhysBody.AddrString,
rootPrim.Position, liConstraint.member.Position, midPoint);
// create a constraint that allows no freedom of movement between the two objects // create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
constrain = new BSConstraint6Dof( 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. /* 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 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
@ -319,12 +408,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,
linkInfo.useLinearReferenceFrameA,
true /*disableCollisionsBetweenLinkedBodies*/);
DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}",
rootPrim.LocalID,
rootPrim.LocalID, rootPrim.PhysBody.AddrString,
linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString,
rootPrim.Position, linkInfo.member.Position);
break; break;
default: default:
break; break;
} }
liConstraint.SetConstraintParameters(constrain); linkInfo.SetLinkParameters(constrain);
m_physicsScene.Constraints.AddConstraint(constrain); m_physicsScene.Constraints.AddConstraint(constrain);
@ -343,13 +444,22 @@ public sealed class BSLinksetConstraints : BSLinkset
rootPrim.LocalID, rootPrim.PhysBody.AddrString, rootPrim.LocalID, rootPrim.PhysBody.AddrString,
childPrim.LocalID, childPrim.PhysBody.AddrString); childPrim.LocalID, childPrim.PhysBody.AddrString);
// Find the constraint for this link and get rid of it from the overall collection and from my list // If asked to unlink root from root, just remove all the constraints
if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) if (rootPrim == childPrim || childPrim == LinksetRoot)
{ {
// Make the child refresh its location PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
ret = true; ret = true;
} }
else
{
// Find the constraint for this link and get rid of it from the overall collection and from my list
if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
{
// Make the child refresh its location
m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
ret = true;
}
}
return ret; return ret;
} }
@ -382,9 +492,9 @@ public sealed class BSLinksetConstraints : BSLinkset
Rebuilding = true; Rebuilding = true;
// There is no reason to build all this physical stuff for a non-physical linkset. // 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. return; // Note the 'finally' clause at the botton which will get executed.
} }
@ -401,6 +511,7 @@ public sealed class BSLinksetConstraints : BSLinkset
// If constraint doesn't exist yet, create it. // If constraint doesn't exist yet, create it.
constrain = BuildConstraint(LinksetRoot, li); constrain = BuildConstraint(LinksetRoot, li);
} }
li.SetLinkParameters(constrain);
constrain.RecomputeConstraintVariables(linksetMass); constrain.RecomputeConstraintVariables(linksetMass);
// PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
@ -412,5 +523,324 @@ public sealed class BSLinksetConstraints : BSLinkset
Rebuilding = false; Rebuilding = false;
} }
} }
#region Extension
public override object Extension(string pFunct, params object[] pParams)
{
object ret = null;
switch (pFunct)
{
// pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
case ExtendedPhysics.PhysFunctChangeLinkType:
if (pParams.Length > 2)
{
int requestedType = (int)pParams[2];
DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType);
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[1] as BSPrimLinkable;
if (child != null)
{
DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}",
LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType);
m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate()
{
// Pick up all the constraints currently created.
RemoveDependencies(child);
BSLinkInfo linkInfo = null;
if (TryGetLinkInfo(child, out linkInfo))
{
BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
if (linkInfoC != null)
{
linkInfoC.constraintType = (ConstraintType)requestedType;
ret = (object)true;
DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}",
linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
}
else
{
DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID);
}
}
else
{
DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID);
}
// Cause the whole linkset to be rebuilt in post-taint time.
Refresh(child);
});
}
else
{
DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID);
}
}
else
{
DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}",
LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE));
}
}
break;
// pParams = [ BSPhysObject root, BSPhysObject child ]
case ExtendedPhysics.PhysFunctGetLinkType:
if (pParams.Length > 0)
{
BSPrimLinkable child = pParams[1] as BSPrimLinkable;
if (child != null)
{
BSLinkInfo linkInfo = null;
if (TryGetLinkInfo(child, out linkInfo))
{
BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
if (linkInfoC != null)
{
ret = (object)(int)linkInfoC.constraintType;
DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}",
linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
}
}
}
}
break;
// pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ]
case ExtendedPhysics.PhysFunctChangeLinkParams:
// There should be two parameters: the childActor and a list of parameters to set
if (pParams.Length > 2)
{
BSPrimLinkable child = pParams[1] as BSPrimLinkable;
BSLinkInfo baseLinkInfo = null;
if (TryGetLinkInfo(child, out baseLinkInfo))
{
BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint;
if (linkInfo != null)
{
int valueInt;
float valueFloat;
bool valueBool;
OMV.Vector3 valueVector;
OMV.Vector3 valueVector2;
OMV.Quaternion valueQuaternion;
int axisLow, axisHigh;
int opIndex = 2;
while (opIndex < pParams.Length)
{
int thisOp = 0;
string errMsg = "";
try
{
thisOp = (int)pParams[opIndex];
DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}",
linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]);
switch (thisOp)
{
case ExtendedPhysics.PHYS_PARAM_LINK_TYPE:
valueInt = (int)pParams[opIndex + 1];
ConstraintType valueType = (ConstraintType)valueInt;
if (valueType == ConstraintType.FIXED_CONSTRAINT_TYPE
|| valueType == ConstraintType.D6_CONSTRAINT_TYPE
|| valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE
|| valueType == ConstraintType.HINGE_CONSTRAINT_TYPE
|| valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE
|| valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE)
{
linkInfo.constraintType = valueType;
}
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC:
errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector";
valueVector = (OMV.Vector3)pParams[opIndex + 1];
linkInfo.frameInAloc = valueVector;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT:
errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation";
valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
linkInfo.frameInArot = valueQuaternion;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC:
errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector";
valueVector = (OMV.Vector3)pParams[opIndex + 1];
linkInfo.frameInBloc = valueVector;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT:
errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation";
valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
linkInfo.frameInBrot = valueQuaternion;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW:
errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector";
valueVector = (OMV.Vector3)pParams[opIndex + 1];
linkInfo.linearLimitLow = valueVector;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH:
errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector";
valueVector = (OMV.Vector3)pParams[opIndex + 1];
linkInfo.linearLimitHigh = valueVector;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW:
errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector";
valueVector = (OMV.Vector3)pParams[opIndex + 1];
linkInfo.angularLimitLow = valueVector;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH:
errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector";
valueVector = (OMV.Vector3)pParams[opIndex + 1];
linkInfo.angularLimitHigh = valueVector;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET:
errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)";
valueBool = ((int)pParams[opIndex + 1]) != 0;
linkInfo.useFrameOffset = valueBool;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR:
errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)";
valueBool = ((int)pParams[opIndex + 1]) != 0;
linkInfo.enableTransMotor = valueBool;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL:
errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float";
valueFloat = (float)pParams[opIndex + 1];
linkInfo.transMotorMaxVel = valueFloat;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE:
errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float";
valueFloat = (float)pParams[opIndex + 1];
linkInfo.transMotorMaxForce = valueFloat;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_CFM:
errMsg = "PHYS_PARAM_CFM takes one parameter of type float";
valueFloat = (float)pParams[opIndex + 1];
linkInfo.cfm = valueFloat;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_ERP:
errMsg = "PHYS_PARAM_ERP takes one parameter of type float";
valueFloat = (float)pParams[opIndex + 1];
linkInfo.erp = valueFloat;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS:
errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float";
valueFloat = (float)pParams[opIndex + 1];
linkInfo.solverIterations = valueFloat;
opIndex += 2;
break;
case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE:
errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)";
valueInt = (int)pParams[opIndex + 1];
valueBool = ((int)pParams[opIndex + 2]) != 0;
GetAxisRange(valueInt, out axisLow, out axisHigh);
for (int ii = axisLow; ii <= axisHigh; ii++)
linkInfo.springAxisEnable[ii] = valueBool;
opIndex += 3;
break;
case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING:
errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float";
valueInt = (int)pParams[opIndex + 1];
valueFloat = (float)pParams[opIndex + 2];
GetAxisRange(valueInt, out axisLow, out axisHigh);
for (int ii = axisLow; ii <= axisHigh; ii++)
linkInfo.springDamping[ii] = valueFloat;
opIndex += 3;
break;
case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS:
errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float";
valueInt = (int)pParams[opIndex + 1];
valueFloat = (float)pParams[opIndex + 2];
GetAxisRange(valueInt, out axisLow, out axisHigh);
for (int ii = axisLow; ii <= axisHigh; ii++)
linkInfo.springStiffness[ii] = valueFloat;
opIndex += 3;
break;
case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT:
errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector";
valueVector = (OMV.Vector3)pParams[opIndex + 1];
valueVector2 = (OMV.Vector3)pParams[opIndex + 2];
linkInfo.springLinearEquilibriumPoint = valueVector;
linkInfo.springAngularEquilibriumPoint = valueVector2;
opIndex += 3;
break;
case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA:
errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)";
valueBool = ((int)pParams[opIndex + 1]) != 0;
linkInfo.useLinearReferenceFrameA = valueBool;
opIndex += 2;
break;
default:
break;
}
}
catch (InvalidCastException e)
{
m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}",
LogHeader, errMsg, e);
}
catch (Exception e)
{
m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e);
}
}
}
// Something changed so a rebuild is in order
Refresh(child);
}
}
break;
default:
ret = base.Extension(pFunct, pParams);
break;
}
return ret;
}
// Bullet constraints keep some limit parameters for each linear and angular axis.
// Setting same is easier if there is an easy way to see all or types.
// This routine returns the array limits for the set of axis.
private void GetAxisRange(int rangeSpec, out int low, out int high)
{
switch (rangeSpec)
{
case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL:
low = 0;
high = 2;
break;
case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL:
low = 3;
high = 5;
break;
case ExtendedPhysics.PHYS_AXIS_ALL:
low = 0;
high = 5;
break;
default:
low = high = rangeSpec;
break;
}
return;
}
#endregion // Extension
} }
} }

View File

@ -134,6 +134,7 @@ public static class BSParam
public static float AvatarHeightMidFudge { get; private set; } public static float AvatarHeightMidFudge { get; private set; }
public static float AvatarHeightHighFudge { get; private set; } public static float AvatarHeightHighFudge { get; private set; }
public static float AvatarContactProcessingThreshold { get; private set; } public static float AvatarContactProcessingThreshold { get; private set; }
public static float AvatarStopZeroThreshold { get; private set; }
public static int AvatarJumpFrames { get; private set; } public static int AvatarJumpFrames { get; private set; }
public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
public static float AvatarStepHeight { get; private set; } public static float AvatarStepHeight { get; private set; }
@ -570,11 +571,13 @@ public static class BSParam
new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
-0.2f ), -0.2f ),
new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
0.2f ), 0.1f ),
new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
0.2f ), 0.1f ),
new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
0.1f ), 0.1f ),
new ParameterDefn<float>("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped",
0.1f ),
new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
1.0f ), 1.0f ),
new ParameterDefn<int>("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", new ParameterDefn<int>("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.",
@ -683,21 +686,21 @@ public static class BSParam
0f ), 0f ),
new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", 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", 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", 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", 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", 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", 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", 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", 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", new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
false ), false ),
@ -826,7 +829,7 @@ public static class BSParam
private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
{ {
BSScene physScene = pPhysScene; BSScene physScene = pPhysScene;
physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate() physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate()
{ {
physScene.PE.ResetConstraintSolver(physScene.World); physScene.PE.ResetConstraintSolver(physScene.World);
}); });

View File

@ -121,7 +121,7 @@ public abstract class BSPhysObject : PhysicsActor
public virtual void Destroy() public virtual void Destroy()
{ {
PhysicalActors.Enable(false); PhysicalActors.Enable(false);
PhysScene.TaintedObject("BSPhysObject.Destroy", delegate() PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate()
{ {
PhysicalActors.Dispose(); PhysicalActors.Dispose();
}); });
@ -300,8 +300,19 @@ public abstract class BSPhysObject : PhysicsActor
// Called in taint-time!! // Called in taint-time!!
public void ActivateIfPhysical(bool forceIt) public void ActivateIfPhysical(bool forceIt)
{ {
if (IsPhysical && PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
PhysScene.PE.Activate(PhysBody, forceIt); {
if (IsPhysical)
{
// Physical objects might need activating
PhysScene.PE.Activate(PhysBody, forceIt);
}
else
{
// Clear the collision cache since we've changed some properties.
PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody);
}
}
} }
// 'actors' act on the physical object to change or constrain its motion. These can range from // 'actors' act on the physical object to change or constrain its motion. These can range from
@ -509,7 +520,7 @@ public abstract class BSPhysObject : PhysicsActor
// make sure first collision happens // make sure first collision happens
NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate() PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate()
{ {
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
@ -524,7 +535,7 @@ public abstract class BSPhysObject : PhysicsActor
public override void UnSubscribeEvents() { public override void UnSubscribeEvents() {
// DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
SubscribedEventsMs = 0; SubscribedEventsMs = 0;
PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate()
{ {
// Make sure there is a body there because sometimes destruction happens in an un-ideal order. // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)

View File

@ -41,7 +41,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
[Serializable] [Serializable]
public class BSPrim : BSPhysObject 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]"; 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. // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
@ -102,7 +102,7 @@ public class BSPrim : BSPhysObject
// DetailLog("{0},BSPrim.constructor,call", LocalID); // DetailLog("{0},BSPrim.constructor,call", LocalID);
// do the actual object creation at taint time // do the actual object creation at taint time
PhysScene.TaintedObject("BSPrim.create", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
{ {
// Make sure the object is being created with some sanity. // Make sure the object is being created with some sanity.
ExtremeSanityCheck(true /* inTaintTime */); ExtremeSanityCheck(true /* inTaintTime */);
@ -126,7 +126,7 @@ public class BSPrim : BSPhysObject
// Undo any vehicle properties // Undo any vehicle properties
this.VehicleType = (int)Vehicle.TYPE_NONE; this.VehicleType = (int)Vehicle.TYPE_NONE;
PhysScene.TaintedObject("BSPrim.Destroy", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate()
{ {
DetailLog("{0},BSPrim.Destroy,taint,", LocalID); DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
// If there are physical body and shape, release my use of same. // If there are physical body and shape, release my use of same.
@ -161,7 +161,7 @@ public class BSPrim : BSPhysObject
} }
public override bool ForceBodyShapeRebuild(bool inTaintTime) public override bool ForceBodyShapeRebuild(bool inTaintTime)
{ {
PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
{ {
_mass = CalculateMass(); // changing the shape changes the mass _mass = CalculateMass(); // changing the shape changes the mass
CreateGeomAndObject(true); CreateGeomAndObject(true);
@ -178,7 +178,7 @@ public class BSPrim : BSPhysObject
if (value != _isSelected) if (value != _isSelected)
{ {
_isSelected = value; _isSelected = value;
PhysScene.TaintedObject("BSPrim.setSelected", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
{ {
DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
SetObjectDynamic(false); SetObjectDynamic(false);
@ -224,7 +224,7 @@ public class BSPrim : BSPhysObject
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties in the physics engine // Zero some other properties in the physics engine
PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
{ {
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
PhysScene.PE.ClearAllForces(PhysBody); PhysScene.PE.ClearAllForces(PhysBody);
@ -234,7 +234,7 @@ public class BSPrim : BSPhysObject
{ {
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties in the physics engine // Zero some other properties in the physics engine
PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
{ {
// DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
@ -262,7 +262,7 @@ public class BSPrim : BSPhysObject
}); });
// Update parameters so the new actor's Refresh() action is called at the right time. // Update parameters so the new actor's Refresh() action is called at the right time.
PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.LockAngularMotion", delegate()
{ {
UpdatePhysicalParameters(); UpdatePhysicalParameters();
}); });
@ -287,7 +287,7 @@ public class BSPrim : BSPhysObject
RawPosition = value; RawPosition = value;
PositionSanityCheck(false); PositionSanityCheck(false);
PhysScene.TaintedObject("BSPrim.setPosition", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
{ {
DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
ForcePosition = RawPosition; ForcePosition = RawPosition;
@ -531,7 +531,7 @@ public class BSPrim : BSPhysObject
set { set {
Vehicle type = (Vehicle)value; Vehicle type = (Vehicle)value;
PhysScene.TaintedObject("setVehicleType", delegate() PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
{ {
// Some vehicle scripts change vehicle type on the fly as an easy way to // Some vehicle scripts change vehicle type on the fly as an easy way to
// change all the parameters. Like a plane changing to CAR when on the // change all the parameters. Like a plane changing to CAR when on the
@ -561,7 +561,7 @@ public class BSPrim : BSPhysObject
} }
public override void VehicleFloatParam(int param, float value) public override void VehicleFloatParam(int param, float value)
{ {
PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
{ {
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null) if (vehicleActor != null)
@ -573,7 +573,7 @@ public class BSPrim : BSPhysObject
} }
public override void VehicleVectorParam(int param, OMV.Vector3 value) public override void VehicleVectorParam(int param, OMV.Vector3 value)
{ {
PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
{ {
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null) if (vehicleActor != null)
@ -585,7 +585,7 @@ public class BSPrim : BSPhysObject
} }
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
{ {
PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
{ {
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null) if (vehicleActor != null)
@ -597,7 +597,7 @@ public class BSPrim : BSPhysObject
} }
public override void VehicleFlags(int param, bool remove) public override void VehicleFlags(int param, bool remove)
{ {
PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
{ {
BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
if (vehicleActor != null) if (vehicleActor != null)
@ -613,7 +613,7 @@ public class BSPrim : BSPhysObject
if (_isVolumeDetect != newValue) if (_isVolumeDetect != newValue)
{ {
_isVolumeDetect = newValue; _isVolumeDetect = newValue;
PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
{ {
// DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
SetObjectDynamic(true); SetObjectDynamic(true);
@ -628,7 +628,7 @@ public class BSPrim : BSPhysObject
public override void SetMaterial(int material) public override void SetMaterial(int material)
{ {
base.SetMaterial(material); base.SetMaterial(material);
PhysScene.TaintedObject("BSPrim.SetMaterial", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
{ {
UpdatePhysicalParameters(); UpdatePhysicalParameters();
}); });
@ -641,7 +641,7 @@ public class BSPrim : BSPhysObject
if (base.Friction != value) if (base.Friction != value)
{ {
base.Friction = value; base.Friction = value;
PhysScene.TaintedObject("BSPrim.setFriction", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
{ {
UpdatePhysicalParameters(); UpdatePhysicalParameters();
}); });
@ -656,7 +656,7 @@ public class BSPrim : BSPhysObject
if (base.Restitution != value) if (base.Restitution != value)
{ {
base.Restitution = value; base.Restitution = value;
PhysScene.TaintedObject("BSPrim.setRestitution", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
{ {
UpdatePhysicalParameters(); UpdatePhysicalParameters();
}); });
@ -673,7 +673,7 @@ public class BSPrim : BSPhysObject
if (base.Density != value) if (base.Density != value)
{ {
base.Density = value; base.Density = value;
PhysScene.TaintedObject("BSPrim.setDensity", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
{ {
UpdatePhysicalParameters(); UpdatePhysicalParameters();
}); });
@ -688,7 +688,7 @@ public class BSPrim : BSPhysObject
if (base.GravModifier != value) if (base.GravModifier != value)
{ {
base.GravModifier = value; base.GravModifier = value;
PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
{ {
UpdatePhysicalParameters(); UpdatePhysicalParameters();
}); });
@ -699,7 +699,7 @@ public class BSPrim : BSPhysObject
get { return RawVelocity; } get { return RawVelocity; }
set { set {
RawVelocity = value; RawVelocity = value;
PhysScene.TaintedObject("BSPrim.setVelocity", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
{ {
// DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
ForceVelocity = RawVelocity; ForceVelocity = RawVelocity;
@ -745,7 +745,7 @@ public class BSPrim : BSPhysObject
return; return;
RawOrientation = value; RawOrientation = value;
PhysScene.TaintedObject("BSPrim.setOrientation", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
{ {
ForceOrientation = RawOrientation; ForceOrientation = RawOrientation;
}); });
@ -776,7 +776,7 @@ public class BSPrim : BSPhysObject
if (_isPhysical != value) if (_isPhysical != value)
{ {
_isPhysical = value; _isPhysical = value;
PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
{ {
DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
SetObjectDynamic(true); SetObjectDynamic(true);
@ -1020,7 +1020,7 @@ public class BSPrim : BSPhysObject
public override bool FloatOnWater { public override bool FloatOnWater {
set { set {
_floatOnWater = value; _floatOnWater = value;
PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
{ {
if (_floatOnWater) if (_floatOnWater)
CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
@ -1037,7 +1037,7 @@ public class BSPrim : BSPhysObject
_rotationalVelocity = value; _rotationalVelocity = value;
Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
// m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
{ {
ForceRotationalVelocity = _rotationalVelocity; ForceRotationalVelocity = _rotationalVelocity;
}); });
@ -1068,7 +1068,7 @@ public class BSPrim : BSPhysObject
get { return _buoyancy; } get { return _buoyancy; }
set { set {
_buoyancy = value; _buoyancy = value;
PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate() PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
{ {
ForceBuoyancy = _buoyancy; ForceBuoyancy = _buoyancy;
}); });
@ -1142,7 +1142,7 @@ public class BSPrim : BSPhysObject
// DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
OMV.Vector3 addForce = force; OMV.Vector3 addForce = force;
PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
{ {
// Bullet adds this central force to the total force for this tick. // Bullet adds this central force to the total force for this tick.
// Deep down in Bullet: // Deep down in Bullet:
@ -1172,7 +1172,7 @@ public class BSPrim : BSPhysObject
OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
// DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
{ {
// Bullet adds this impulse immediately to the velocity // Bullet adds this impulse immediately to the velocity
DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
@ -1197,7 +1197,7 @@ public class BSPrim : BSPhysObject
if (force.IsFinite()) if (force.IsFinite())
{ {
OMV.Vector3 angForce = force; OMV.Vector3 angForce = force;
PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
{ {
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
{ {
@ -1221,7 +1221,7 @@ public class BSPrim : BSPhysObject
public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
{ {
OMV.Vector3 applyImpulse = impulse; OMV.Vector3 applyImpulse = impulse;
PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
{ {
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
{ {
@ -1552,39 +1552,10 @@ public class BSPrim : BSPhysObject
#region Extension #region Extension
public override object Extension(string pFunct, params object[] pParams) public override object Extension(string pFunct, params object[] pParams)
{ {
DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
object ret = null; object ret = null;
switch (pFunct) 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: default:
ret = base.Extension(pFunct, pParams); ret = base.Extension(pFunct, pParams);
break; break;

View File

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

View File

@ -157,12 +157,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public delegate void TaintCallback(); public delegate void TaintCallback();
private struct TaintCallbackEntry private struct TaintCallbackEntry
{ {
public String originator;
public String ident; public String ident;
public TaintCallback callback; public TaintCallback callback;
public TaintCallbackEntry(string i, TaintCallback c) public TaintCallbackEntry(string pIdent, TaintCallback pCallBack)
{ {
ident = i; originator = BSScene.DetailLogZero;
callback = c; ident = pIdent;
callback = pCallBack;
}
public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack)
{
originator = pOrigin;
ident = pIdent;
callback = pCallBack;
} }
} }
private Object _taintLock = new Object(); // lock for using the next object private Object _taintLock = new Object(); // lock for using the next object
@ -867,18 +875,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public override bool IsThreaded { get { return false; } } public override bool IsThreaded { get { return false; } }
#region Extensions #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) public override object Extension(string pFunct, params object[] pParams)
{ {
DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct);
return base.Extension(pFunct, pParams); return base.Extension(pFunct, pParams);
} }
#endregion // Extensions #endregion // Extensions
@ -897,26 +896,37 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// Calls to the PhysicsActors can't directly call into the physics engine // Calls to the PhysicsActors can't directly call into the physics engine
// because it might be busy. We delay changes to a known time. // because it might be busy. We delay changes to a known time.
// We rely on C#'s closure to save and restore the context for the delegate. // We rely on C#'s closure to save and restore the context for the delegate.
public void TaintedObject(String ident, TaintCallback callback) public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
{
TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback);
}
public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
{
TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
}
public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
{
TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
}
public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
{
TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
}
// Sometimes a potentially tainted operation can be used in and out of taint time.
// This routine executes the command immediately if in taint-time otherwise it is queued.
public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback)
{ {
if (!m_initialized) return; if (!m_initialized) return;
lock (_taintLock)
{
_taintOperations.Add(new TaintCallbackEntry(ident, callback));
}
return;
}
// Sometimes a potentially tainted operation can be used in and out of taint time.
// This routine executes the command immediately if in taint-time otherwise it is queued.
public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
{
if (inTaintTime) if (inTaintTime)
callback(); pCallback();
else else
TaintedObject(ident, callback); {
lock (_taintLock)
{
_taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
}
}
} }
private void TriggerPreStepEvent(float timeStep) private void TriggerPreStepEvent(float timeStep)
@ -960,7 +970,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
{ {
try try
{ {
DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
tcbe.callback(); tcbe.callback();
} }
catch (Exception e) catch (Exception e)
@ -977,10 +987,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// will replace any previous operation by the same object. // will replace any previous operation by the same object.
public void PostTaintObject(String ident, uint ID, TaintCallback callback) public void PostTaintObject(String ident, uint ID, TaintCallback callback)
{ {
string uniqueIdent = ident + "-" + ID.ToString(); string IDAsString = ID.ToString();
string uniqueIdent = ident + "-" + IDAsString;
lock (_taintLock) lock (_taintLock)
{ {
_postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback);
} }
return; return;
@ -1090,7 +1101,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
string xval = val; string xval = val;
List<uint> xlIDs = lIDs; List<uint> xlIDs = lIDs;
string xparm = parm; string xparm = parm;
TaintedObject("BSScene.UpdateParameterSet", delegate() { TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() {
BSParam.ParameterDefnBase thisParam; BSParam.ParameterDefnBase thisParam;
if (BSParam.TryGetParameter(xparm, out thisParam)) if (BSParam.TryGetParameter(xparm, out thisParam))
{ {

View File

@ -8190,12 +8190,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
while (true) while (true)
{ {
// m_log.DebugFormat(
// "[LSL API]: GetEntityParams has {0} rules with scene entity named {1}",
// rules.Length, entity != null ? entity.Name : "NULL");
if (entity == null)
return result;
if (entity is SceneObjectPart) if (entity is SceneObjectPart)
remaining = GetPrimParams((SceneObjectPart)entity, rules, ref result); remaining = GetPrimParams((SceneObjectPart)entity, rules, ref result);
else else
remaining = GetAgentParams((ScenePresence)entity, rules, ref result); remaining = GetAgentParams((ScenePresence)entity, rules, ref result);
if (remaining == null || remaining.Length <= 2) if (remaining == null || remaining.Length < 2)
return result; return result;
int linknumber = remaining.GetLSLIntegerItem(0); int linknumber = remaining.GetLSLIntegerItem(0);
@ -8400,7 +8407,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
while (idx < rules.Length) while (idx < rules.Length)
{ {
int code = (int)rules.GetLSLIntegerItem(idx++); int code = (int)rules.GetLSLIntegerItem(idx++);
int remain = rules.Length-idx; int remain = rules.Length - idx;
switch (code) switch (code)
{ {
@ -8483,7 +8490,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
break; break;
case ScriptBaseClass.PRIM_TYPE_SCULPT: case ScriptBaseClass.PRIM_TYPE_SCULPT:
res.Add(Shape.SculptTexture.ToString()); res.Add(new LSL_String(Shape.SculptTexture.ToString()));
res.Add(new LSL_Integer(Shape.SculptType)); res.Add(new LSL_Integer(Shape.SculptType));
break; break;
@ -8777,7 +8784,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
)); ));
break; break;
case (int)ScriptBaseClass.PRIM_LINK_TARGET: case (int)ScriptBaseClass.PRIM_LINK_TARGET:
if(remain < 3)
// TODO: Should be issuing a runtime script warning in this case.
if (remain < 2)
return null; return null;
return rules.GetSublist(idx, -1); return rules.GetSublist(idx, -1);

View File

@ -2964,7 +2964,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
sp.ControllingClient.Kick(alert); sp.ControllingClient.Kick(alert);
// ...and close on our side // ...and close on our side
sp.Scene.IncomingCloseAgent(sp.UUID, false); sp.Scene.CloseAgent(sp.UUID, false);
} }
}); });
} }

View File

@ -0,0 +1,399 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using log4net;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenMetaverse.Assets;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Region.CoreModules.Avatar.AvatarFactory;
using OpenSim.Region.OptionalModules.World.NPC;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.Instance;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Services.Interfaces;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
namespace OpenSim.Region.ScriptEngine.Shared.Tests
{
[TestFixture]
public class LSL_ApiObjectTests : OpenSimTestCase
{
private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d;
private const float FLOAT_ACCURACY = 0.00005f;
protected Scene m_scene;
protected XEngine.XEngine m_engine;
[SetUp]
public override void SetUp()
{
base.SetUp();
IConfigSource initConfigSource = new IniConfigSource();
IConfig config = initConfigSource.AddConfig("XEngine");
config.Set("Enabled", "true");
m_scene = new SceneHelpers().SetupScene();
SceneHelpers.SetupSceneModules(m_scene, initConfigSource);
m_engine = new XEngine.XEngine();
m_engine.Initialise(initConfigSource);
m_engine.AddRegion(m_scene);
}
[Test]
public void TestllGetLinkPrimitiveParams()
{
TestHelpers.InMethod();
TestHelpers.EnableLogging();
UUID ownerId = TestHelpers.ParseTail(0x1);
SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(2, ownerId, "grp1-", 0x10);
grp1.AbsolutePosition = new Vector3(10, 11, 12);
m_scene.AddSceneObject(grp1);
LSL_Api apiGrp1 = new LSL_Api();
apiGrp1.Initialize(m_engine, grp1.RootPart, null, null);
// Check simple 1 prim case
{
LSL_List resList
= apiGrp1.llGetLinkPrimitiveParams(1, new LSL_List(new LSL_Integer(ScriptBaseClass.PRIM_ROTATION)));
Assert.That(resList.Length, Is.EqualTo(1));
}
// Check 2 prim case
{
LSL_List resList
= apiGrp1.llGetLinkPrimitiveParams(
1,
new LSL_List(
new LSL_Integer(ScriptBaseClass.PRIM_ROTATION),
new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET),
new LSL_Integer(2),
new LSL_Integer(ScriptBaseClass.PRIM_ROTATION)));
Assert.That(resList.Length, Is.EqualTo(2));
}
// Check invalid parameters are ignored
{
LSL_List resList
= apiGrp1.llGetLinkPrimitiveParams(3, new LSL_List(new LSL_Integer(ScriptBaseClass.PRIM_ROTATION)));
Assert.That(resList.Length, Is.EqualTo(0));
}
// Check all parameters are ignored if an initial bad link is given
{
LSL_List resList
= apiGrp1.llGetLinkPrimitiveParams(
3,
new LSL_List(
new LSL_Integer(ScriptBaseClass.PRIM_ROTATION),
new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET),
new LSL_Integer(1),
new LSL_Integer(ScriptBaseClass.PRIM_ROTATION)));
Assert.That(resList.Length, Is.EqualTo(0));
}
// Check only subsequent parameters are ignored when we hit the first bad link number
{
LSL_List resList
= apiGrp1.llGetLinkPrimitiveParams(
1,
new LSL_List(
new LSL_Integer(ScriptBaseClass.PRIM_ROTATION),
new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET),
new LSL_Integer(3),
new LSL_Integer(ScriptBaseClass.PRIM_ROTATION)));
Assert.That(resList.Length, Is.EqualTo(1));
}
}
[Test]
// llSetPrimitiveParams and llGetPrimitiveParams test.
public void TestllSetPrimitiveParams()
{
TestHelpers.InMethod();
// Create Prim1.
Scene scene = new SceneHelpers().SetupScene();
string obj1Name = "Prim1";
UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001");
SceneObjectPart part1 =
new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default,
Vector3.Zero, Quaternion.Identity,
Vector3.Zero) { Name = obj1Name, UUID = objUuid };
Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True);
LSL_Api apiGrp1 = new LSL_Api();
apiGrp1.Initialize(m_engine, part1, null, null);
// Note that prim hollow check is passed with the other prim params in order to allow the
// specification of a different check value from the prim param. A cylinder, prism, sphere,
// torus or ring, with a hole shape of square, is limited to a hollow of 70%. Test 5 below
// specifies a value of 95% and checks to see if 70% was properly returned.
// Test a sphere.
CheckllSetPrimitiveParams(
apiGrp1,
"test 1", // Prim test identification string
new LSL_Types.Vector3(6.0d, 9.9d, 9.9d), // Prim size
ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type
ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type
new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut
0.80f, // Prim hollow
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist
new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple
0.80f); // Prim hollow check
// Test a prism.
CheckllSetPrimitiveParams(
apiGrp1,
"test 2", // Prim test identification string
new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size
ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type
ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut
0.90f, // Prim hollow
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist
new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear
0.90f); // Prim hollow check
// Test a box.
CheckllSetPrimitiveParams(
apiGrp1,
"test 3", // Prim test identification string
new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size
ScriptBaseClass.PRIM_TYPE_BOX, // Prim type
ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut
0.95f, // Prim hollow
new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist
new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear
0.95f); // Prim hollow check
// Test a tube.
CheckllSetPrimitiveParams(
apiGrp1,
"test 4", // Prim test identification string
new LSL_Types.Vector3(4.2d, 4.2d, 4.2d), // Prim size
ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type
ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut
0.00f, // Prim hollow
new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist
new LSL_Types.Vector3(1.0d, 0.05d, 0.0d), // Prim hole size
// Expression for y selected to test precision problems during byte
// cast in SetPrimitiveShapeParams.
new LSL_Types.Vector3(0.0d, 0.35d + 0.1d, 0.0d), // Prim shear
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut
// Expression for y selected to test precision problems during sbyte
// cast in SetPrimitiveShapeParams.
new LSL_Types.Vector3(-1.0d, 0.70d + 0.1d + 0.1d, 0.0d), // Prim taper
1.11f, // Prim revolutions
0.88f, // Prim radius
0.95f, // Prim skew
0.00f); // Prim hollow check
// Test a prism.
CheckllSetPrimitiveParams(
apiGrp1,
"test 5", // Prim test identification string
new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size
ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type
ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut
0.95f, // Prim hollow
// Expression for x selected to test precision problems during sbyte
// cast in SetPrimitiveShapeBlockParams.
new LSL_Types.Vector3(0.7d + 0.2d, 0.0d, 0.0d), // Prim twist
// Expression for y selected to test precision problems during sbyte
// cast in SetPrimitiveShapeParams.
new LSL_Types.Vector3(2.0d, (1.3d + 0.1d), 0.0d), // Prim taper
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear
0.70f); // Prim hollow check
// Test a sculpted prim.
CheckllSetPrimitiveParams(
apiGrp1,
"test 6", // Prim test identification string
new LSL_Types.Vector3(2.0d, 2.0d, 2.0d), // Prim size
ScriptBaseClass.PRIM_TYPE_SCULPT, // Prim type
"be293869-d0d9-0a69-5989-ad27f1946fd4", // Prim map
ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE); // Prim sculpt type
}
// Set prim params for a box, cylinder or prism and check results.
public void CheckllSetPrimitiveParams(LSL_Api api, string primTest,
LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut,
float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear,
float primHollowCheck)
{
// Set the prim params.
api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize,
ScriptBaseClass.PRIM_TYPE, primType, primHoleType,
primCut, primHollow, primTwist, primTaper, primShear));
// Get params for prim to validate settings.
LSL_Types.list primParams =
api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE));
// Validate settings.
CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size");
Assert.AreEqual(primType, api.llList2Integer(primParams, 1),
"TestllSetPrimitiveParams " + primTest + " prim type check fail");
Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2),
"TestllSetPrimitiveParams " + primTest + " prim hole default check fail");
CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut");
Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim hollow check fail");
CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist");
CheckllSetPrimitiveParamsVector(primTaper, api.llList2Vector(primParams, 6), primTest + " prim taper");
CheckllSetPrimitiveParamsVector(primShear, api.llList2Vector(primParams, 7), primTest + " prim shear");
}
// Set prim params for a sphere and check results.
public void CheckllSetPrimitiveParams(LSL_Api api, string primTest,
LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut,
float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, float primHollowCheck)
{
// Set the prim params.
api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize,
ScriptBaseClass.PRIM_TYPE, primType, primHoleType,
primCut, primHollow, primTwist, primDimple));
// Get params for prim to validate settings.
LSL_Types.list primParams =
api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE));
// Validate settings.
CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size");
Assert.AreEqual(primType, api.llList2Integer(primParams, 1),
"TestllSetPrimitiveParams " + primTest + " prim type check fail");
Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2),
"TestllSetPrimitiveParams " + primTest + " prim hole default check fail");
CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut");
Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim hollow check fail");
CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist");
CheckllSetPrimitiveParamsVector(primDimple, api.llList2Vector(primParams, 6), primTest + " prim dimple");
}
// Set prim params for a torus, tube or ring and check results.
public void CheckllSetPrimitiveParams(LSL_Api api, string primTest,
LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut,
float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize,
LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper,
float primRev, float primRadius, float primSkew, float primHollowCheck)
{
// Set the prim params.
api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize,
ScriptBaseClass.PRIM_TYPE, primType, primHoleType,
primCut, primHollow, primTwist, primHoleSize, primShear, primProfCut,
primTaper, primRev, primRadius, primSkew));
// Get params for prim to validate settings.
LSL_Types.list primParams =
api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE));
// Valdate settings.
CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size");
Assert.AreEqual(primType, api.llList2Integer(primParams, 1),
"TestllSetPrimitiveParams " + primTest + " prim type check fail");
Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2),
"TestllSetPrimitiveParams " + primTest + " prim hole default check fail");
CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut");
Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim hollow check fail");
CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist");
CheckllSetPrimitiveParamsVector(primHoleSize, api.llList2Vector(primParams, 6), primTest + " prim hole size");
CheckllSetPrimitiveParamsVector(primShear, api.llList2Vector(primParams, 7), primTest + " prim shear");
CheckllSetPrimitiveParamsVector(primProfCut, api.llList2Vector(primParams, 8), primTest + " prim profile cut");
CheckllSetPrimitiveParamsVector(primTaper, api.llList2Vector(primParams, 9), primTest + " prim taper");
Assert.AreEqual(primRev, api.llList2Float(primParams, 10), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim revolutions fail");
Assert.AreEqual(primRadius, api.llList2Float(primParams, 11), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim radius fail");
Assert.AreEqual(primSkew, api.llList2Float(primParams, 12), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim skew fail");
}
// Set prim params for a sculpted prim and check results.
public void CheckllSetPrimitiveParams(LSL_Api api, string primTest,
LSL_Types.Vector3 primSize, int primType, string primMap, int primSculptType)
{
// Set the prim params.
api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize,
ScriptBaseClass.PRIM_TYPE, primType, primMap, primSculptType));
// Get params for prim to validate settings.
LSL_Types.list primParams =
api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE));
// Validate settings.
CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size");
Assert.AreEqual(primType, api.llList2Integer(primParams, 1),
"TestllSetPrimitiveParams " + primTest + " prim type check fail");
Assert.AreEqual(primMap, (string)api.llList2String(primParams, 2),
"TestllSetPrimitiveParams " + primTest + " prim map check fail");
Assert.AreEqual(primSculptType, api.llList2Integer(primParams, 3),
"TestllSetPrimitiveParams " + primTest + " prim type scuplt check fail");
}
public void CheckllSetPrimitiveParamsVector(LSL_Types.Vector3 vecCheck, LSL_Types.Vector3 vecReturned, string msg)
{
// Check each vector component against expected result.
Assert.AreEqual(vecCheck.x, vecReturned.x, VECTOR_COMPONENT_ACCURACY,
"TestllSetPrimitiveParams " + msg + " vector check fail on x component");
Assert.AreEqual(vecCheck.y, vecReturned.y, VECTOR_COMPONENT_ACCURACY,
"TestllSetPrimitiveParams " + msg + " vector check fail on y component");
Assert.AreEqual(vecCheck.z, vecReturned.z, VECTOR_COMPONENT_ACCURACY,
"TestllSetPrimitiveParams " + msg + " vector check fail on z component");
}
}
}

View File

@ -47,9 +47,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
[TestFixture, LongRunning] [TestFixture, LongRunning]
public class LSL_ApiTest public class LSL_ApiTest
{ {
private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6;
private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d;
private const float FLOAT_ACCURACY = 0.00005f; private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6;
private LSL_Api m_lslApi; private LSL_Api m_lslApi;
[SetUp] [SetUp]
@ -254,241 +253,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
Assert.AreEqual(0.0, check.z, VECTOR_COMPONENT_ACCURACY, "TestllRot2Euler Z bounds check fail"); Assert.AreEqual(0.0, check.z, VECTOR_COMPONENT_ACCURACY, "TestllRot2Euler Z bounds check fail");
} }
[Test]
// llSetPrimitiveParams and llGetPrimitiveParams test.
public void TestllSetPrimitiveParams()
{
TestHelpers.InMethod();
// Create Prim1.
Scene scene = new SceneHelpers().SetupScene();
string obj1Name = "Prim1";
UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001");
SceneObjectPart part1 =
new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default,
Vector3.Zero, Quaternion.Identity,
Vector3.Zero) { Name = obj1Name, UUID = objUuid };
Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True);
// Note that prim hollow check is passed with the other prim params in order to allow the
// specification of a different check value from the prim param. A cylinder, prism, sphere,
// torus or ring, with a hole shape of square, is limited to a hollow of 70%. Test 5 below
// specifies a value of 95% and checks to see if 70% was properly returned.
// Test a sphere.
CheckllSetPrimitiveParams(
"test 1", // Prim test identification string
new LSL_Types.Vector3(6.0d, 9.9d, 9.9d), // Prim size
ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type
ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type
new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut
0.80f, // Prim hollow
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist
new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple
0.80f); // Prim hollow check
// Test a prism.
CheckllSetPrimitiveParams(
"test 2", // Prim test identification string
new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size
ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type
ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut
0.90f, // Prim hollow
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist
new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear
0.90f); // Prim hollow check
// Test a box.
CheckllSetPrimitiveParams(
"test 3", // Prim test identification string
new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size
ScriptBaseClass.PRIM_TYPE_BOX, // Prim type
ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut
0.95f, // Prim hollow
new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist
new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear
0.95f); // Prim hollow check
// Test a tube.
CheckllSetPrimitiveParams(
"test 4", // Prim test identification string
new LSL_Types.Vector3(4.2d, 4.2d, 4.2d), // Prim size
ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type
ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut
0.00f, // Prim hollow
new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist
new LSL_Types.Vector3(1.0d, 0.05d, 0.0d), // Prim hole size
// Expression for y selected to test precision problems during byte
// cast in SetPrimitiveShapeParams.
new LSL_Types.Vector3(0.0d, 0.35d + 0.1d, 0.0d), // Prim shear
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut
// Expression for y selected to test precision problems during sbyte
// cast in SetPrimitiveShapeParams.
new LSL_Types.Vector3(-1.0d, 0.70d + 0.1d + 0.1d, 0.0d), // Prim taper
1.11f, // Prim revolutions
0.88f, // Prim radius
0.95f, // Prim skew
0.00f); // Prim hollow check
// Test a prism.
CheckllSetPrimitiveParams(
"test 5", // Prim test identification string
new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size
ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type
ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type
new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut
0.95f, // Prim hollow
// Expression for x selected to test precision problems during sbyte
// cast in SetPrimitiveShapeBlockParams.
new LSL_Types.Vector3(0.7d + 0.2d, 0.0d, 0.0d), // Prim twist
// Expression for y selected to test precision problems during sbyte
// cast in SetPrimitiveShapeParams.
new LSL_Types.Vector3(2.0d, (1.3d + 0.1d), 0.0d), // Prim taper
new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear
0.70f); // Prim hollow check
// Test a sculpted prim.
CheckllSetPrimitiveParams(
"test 6", // Prim test identification string
new LSL_Types.Vector3(2.0d, 2.0d, 2.0d), // Prim size
ScriptBaseClass.PRIM_TYPE_SCULPT, // Prim type
"be293869-d0d9-0a69-5989-ad27f1946fd4", // Prim map
ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE); // Prim sculpt type
}
// Set prim params for a box, cylinder or prism and check results.
public void CheckllSetPrimitiveParams(string primTest,
LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut,
float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear,
float primHollowCheck)
{
// Set the prim params.
m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize,
ScriptBaseClass.PRIM_TYPE, primType, primHoleType,
primCut, primHollow, primTwist, primTaper, primShear));
// Get params for prim to validate settings.
LSL_Types.list primParams =
m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE));
// Validate settings.
CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size");
Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1),
"TestllSetPrimitiveParams " + primTest + " prim type check fail");
Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2),
"TestllSetPrimitiveParams " + primTest + " prim hole default check fail");
CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut");
Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim hollow check fail");
CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist");
CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 6), primTest + " prim taper");
CheckllSetPrimitiveParamsVector(primShear, m_lslApi.llList2Vector(primParams, 7), primTest + " prim shear");
}
// Set prim params for a sphere and check results.
public void CheckllSetPrimitiveParams(string primTest,
LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut,
float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, float primHollowCheck)
{
// Set the prim params.
m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize,
ScriptBaseClass.PRIM_TYPE, primType, primHoleType,
primCut, primHollow, primTwist, primDimple));
// Get params for prim to validate settings.
LSL_Types.list primParams =
m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE));
// Validate settings.
CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size");
Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1),
"TestllSetPrimitiveParams " + primTest + " prim type check fail");
Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2),
"TestllSetPrimitiveParams " + primTest + " prim hole default check fail");
CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut");
Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim hollow check fail");
CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist");
CheckllSetPrimitiveParamsVector(primDimple, m_lslApi.llList2Vector(primParams, 6), primTest + " prim dimple");
}
// Set prim params for a torus, tube or ring and check results.
public void CheckllSetPrimitiveParams(string primTest,
LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut,
float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize,
LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper,
float primRev, float primRadius, float primSkew, float primHollowCheck)
{
// Set the prim params.
m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize,
ScriptBaseClass.PRIM_TYPE, primType, primHoleType,
primCut, primHollow, primTwist, primHoleSize, primShear, primProfCut,
primTaper, primRev, primRadius, primSkew));
// Get params for prim to validate settings.
LSL_Types.list primParams =
m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE));
// Valdate settings.
CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size");
Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1),
"TestllSetPrimitiveParams " + primTest + " prim type check fail");
Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2),
"TestllSetPrimitiveParams " + primTest + " prim hole default check fail");
CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut");
Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim hollow check fail");
CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist");
CheckllSetPrimitiveParamsVector(primHoleSize, m_lslApi.llList2Vector(primParams, 6), primTest + " prim hole size");
CheckllSetPrimitiveParamsVector(primShear, m_lslApi.llList2Vector(primParams, 7), primTest + " prim shear");
CheckllSetPrimitiveParamsVector(primProfCut, m_lslApi.llList2Vector(primParams, 8), primTest + " prim profile cut");
CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 9), primTest + " prim taper");
Assert.AreEqual(primRev, m_lslApi.llList2Float(primParams, 10), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim revolutions fail");
Assert.AreEqual(primRadius, m_lslApi.llList2Float(primParams, 11), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim radius fail");
Assert.AreEqual(primSkew, m_lslApi.llList2Float(primParams, 12), FLOAT_ACCURACY,
"TestllSetPrimitiveParams " + primTest + " prim skew fail");
}
// Set prim params for a sculpted prim and check results.
public void CheckllSetPrimitiveParams(string primTest,
LSL_Types.Vector3 primSize, int primType, string primMap, int primSculptType)
{
// Set the prim params.
m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize,
ScriptBaseClass.PRIM_TYPE, primType, primMap, primSculptType));
// Get params for prim to validate settings.
LSL_Types.list primParams =
m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE));
// Validate settings.
CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size");
Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1),
"TestllSetPrimitiveParams " + primTest + " prim type check fail");
Assert.AreEqual(primMap, (string)m_lslApi.llList2String(primParams, 2),
"TestllSetPrimitiveParams " + primTest + " prim map check fail");
Assert.AreEqual(primSculptType, m_lslApi.llList2Integer(primParams, 3),
"TestllSetPrimitiveParams " + primTest + " prim type scuplt check fail");
}
public void CheckllSetPrimitiveParamsVector(LSL_Types.Vector3 vecCheck, LSL_Types.Vector3 vecReturned, string msg)
{
// Check each vector component against expected result.
Assert.AreEqual(vecCheck.x, vecReturned.x, VECTOR_COMPONENT_ACCURACY,
"TestllSetPrimitiveParams " + msg + " vector check fail on x component");
Assert.AreEqual(vecCheck.y, vecReturned.y, VECTOR_COMPONENT_ACCURACY,
"TestllSetPrimitiveParams " + msg + " vector check fail on y component");
Assert.AreEqual(vecCheck.z, vecReturned.z, VECTOR_COMPONENT_ACCURACY,
"TestllSetPrimitiveParams " + msg + " vector check fail on z component");
}
[Test] [Test]
public void TestllVecNorm() public void TestllVecNorm()
{ {

View File

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

View File

@ -104,6 +104,8 @@ namespace OpenSim.Server.Handlers.Profiles
Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest); Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest);
Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate); Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate);
Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate); Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate);
Server.AddJsonRPCHandler("user_preferences_update", handler.UserPreferenecesUpdate);
Server.AddJsonRPCHandler("user_preferences_request", handler.UserPreferencesRequest);
Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest); Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest);
Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData); Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData);
Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData);

View File

@ -381,6 +381,59 @@ namespace OpenSim.Server.Handlers
} }
#endregion Interests #endregion Interests
#region User Preferences
public bool UserPreferencesRequest(OSDMap json, ref JsonRpcResponse response)
{
if(!json.ContainsKey("params"))
{
response.Error.Code = ErrorCode.ParseError;
m_log.DebugFormat ("User Preferences Request");
return false;
}
string result = string.Empty;
UserPreferences prefs = new UserPreferences();
object Prefs = (object)prefs;
OSD.DeserializeMembers(ref Prefs, (OSDMap)json["params"]);
if(Service.UserPreferencesRequest(ref prefs, ref result))
{
response.Result = OSD.SerializeMembers(prefs);
return true;
}
response.Error.Code = ErrorCode.InternalError;
response.Error.Message = string.Format("{0}", result);
m_log.InfoFormat("[PROFILES]: User preferences request error - {0}", response.Error.Message);
return false;
}
public bool UserPreferenecesUpdate(OSDMap json, ref JsonRpcResponse response)
{
if(!json.ContainsKey("params"))
{
response.Error.Code = ErrorCode.ParseError;
response.Error.Message = "no parameters supplied";
m_log.DebugFormat ("User Preferences Update Request");
return false;
}
string result = string.Empty;
UserPreferences prefs = new UserPreferences();
object Prefs = (object)prefs;
OSD.DeserializeMembers(ref Prefs, (OSDMap)json["params"]);
if(Service.UserPreferencesUpdate(ref prefs, ref result))
{
response.Result = OSD.SerializeMembers(prefs);
return true;
}
response.Error.Code = ErrorCode.InternalError;
response.Error.Message = string.Format("{0}", result);
m_log.InfoFormat("[PROFILES]: User preferences update error - {0}", response.Error.Message);
return false;
}
#endregion User Preferences
#region Utility #region Utility
public bool AvatarImageAssetsRequest(OSDMap json, ref JsonRpcResponse response) public bool AvatarImageAssetsRequest(OSDMap json, ref JsonRpcResponse response)
{ {

View File

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

View File

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

View File

@ -86,7 +86,7 @@ namespace OpenSim.Services.GridService
{ {
MainConsole.Instance.Commands.AddCommand("Regions", true, MainConsole.Instance.Commands.AddCommand("Regions", true,
"deregister region id", "deregister region id",
"deregister region id <Region UUID>", "deregister region id <region-id>+",
"Deregister a region manually.", "Deregister a region manually.",
String.Empty, String.Empty,
HandleDeregisterRegion); HandleDeregisterRegion);
@ -265,8 +265,9 @@ namespace OpenSim.Services.GridService
m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e); m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e);
} }
m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3}", m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3} with flags {4}",
regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY); regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY,
(OpenSim.Framework.RegionFlags)flags);
return String.Empty; return String.Empty;
} }
@ -478,6 +479,33 @@ namespace OpenSim.Services.GridService
return ret; return ret;
} }
public List<GridRegion> GetDefaultHypergridRegions(UUID scopeID)
{
List<GridRegion> ret = new List<GridRegion>();
List<RegionData> regions = m_Database.GetDefaultHypergridRegions(scopeID);
foreach (RegionData r in regions)
{
if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0)
ret.Add(RegionData2RegionInfo(r));
}
int hgDefaultRegionsFoundOnline = regions.Count;
// For now, hypergrid default regions will always be given precedence but we will also return simple default
// regions in case no specific hypergrid regions are specified.
ret.AddRange(GetDefaultRegions(scopeID));
int normalDefaultRegionsFoundOnline = ret.Count - hgDefaultRegionsFoundOnline;
m_log.DebugFormat(
"[GRID SERVICE]: GetDefaultHypergridRegions returning {0} hypergrid default and {1} normal default regions",
hgDefaultRegionsFoundOnline, normalDefaultRegionsFoundOnline);
return ret;
}
public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y)
{ {
List<GridRegion> ret = new List<GridRegion>(); List<GridRegion> ret = new List<GridRegion>();
@ -526,40 +554,41 @@ namespace OpenSim.Services.GridService
private void HandleDeregisterRegion(string module, string[] cmd) 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; return;
} }
string rawRegionUuid = cmd[3]; for (int i = 3; i < cmd.Length; i++)
UUID regionUuid;
if (!UUID.TryParse(rawRegionUuid, out regionUuid))
{ {
MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid); string rawRegionUuid = cmd[i];
return; 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) GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid);
{
MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid);
return;
}
if (DeregisterRegion(regionUuid)) if (region == null)
{ {
MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid); MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid);
} return;
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);
}
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) private void HandleShowRegions(string module, string[] cmd)

View File

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

View File

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

View File

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

View File

@ -57,6 +57,11 @@ namespace OpenSim.Services.Interfaces
bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result); bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result);
bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result); bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result);
#endregion Profile Properties #endregion Profile Properties
#region User Preferences
bool UserPreferencesRequest(ref UserPreferences pref, ref string result);
bool UserPreferencesUpdate(ref UserPreferences pref, ref string result);
#endregion User Preferences
#region Interests #region Interests
bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result); bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result);

Some files were not shown because too many files have changed in this diff Show More