aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authornlin2009-04-10 06:39:52 +0000
committernlin2009-04-10 06:39:52 +0000
commit8e6c20b27fdb95b9008614eb36678508407a4d19 (patch)
tree562e0363e5e551c8d3fee03736d319f9e8963c64
parent* Updated BulletDotNET dll with the ContactFlags definition. (diff)
downloadopensim-SC-8e6c20b27fdb95b9008614eb36678508407a4d19.zip
opensim-SC-8e6c20b27fdb95b9008614eb36678508407a4d19.tar.gz
opensim-SC-8e6c20b27fdb95b9008614eb36678508407a4d19.tar.bz2
opensim-SC-8e6c20b27fdb95b9008614eb36678508407a4d19.tar.xz
Handle ObjectSpin* packets to spin physical prims on Ctrl+Shift+Drag
Addresses Mantis #3381 The current implementation works as expected if the object has no rotation or only rotation around the Z axis; you can spin the object left or right (around the world Z axis). It works a little unexpectedly if the object has a non-Z-axis rotation; in this case the body is spun about its local Z axis, not the world Z-axis. (But SL also behaves oddly with a spin on an arbitrarily rotated object.)
Diffstat (limited to '')
-rw-r--r--OpenSim/Client/MXP/ClientStack/MXPClientView.cs3
-rw-r--r--OpenSim/Framework/IClientAPI.cs5
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs4
-rw-r--r--OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs3
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs32
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs41
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs100
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs5
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs3
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs3
11 files changed, 198 insertions, 3 deletions
diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
index c29e895..687c02a 100644
--- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
+++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
@@ -607,6 +607,9 @@ namespace OpenSim.Client.MXP.ClientStack
607 public event GrabObject OnGrabObject; 607 public event GrabObject OnGrabObject;
608 public event ObjectSelect OnDeGrabObject; 608 public event ObjectSelect OnDeGrabObject;
609 public event MoveObject OnGrabUpdate; 609 public event MoveObject OnGrabUpdate;
610 public event SpinStart OnSpinStart;
611 public event SpinObject OnSpinUpdate;
612 public event SpinStop OnSpinStop;
610 public event UpdateShape OnUpdatePrimShape; 613 public event UpdateShape OnUpdatePrimShape;
611 public event ObjectExtraParams OnUpdateExtraParams; 614 public event ObjectExtraParams OnUpdateExtraParams;
612 public event ObjectSelect OnObjectSelect; 615 public event ObjectSelect OnObjectSelect;
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 1fa5ae2..e0983e8 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -160,7 +160,7 @@ namespace OpenSim.Framework
160 ); 160 );
161 161
162 public delegate void SpinStart(UUID objectID, IClientAPI remoteClient); 162 public delegate void SpinStart(UUID objectID, IClientAPI remoteClient);
163 public delegate void SpinUpdate(UUID objectID, Quaternion rotation, IClientAPI remoteClient); 163 public delegate void SpinObject(UUID objectID, Quaternion rotation, IClientAPI remoteClient);
164 public delegate void SpinStop(UUID objectID, IClientAPI remoteClient); 164 public delegate void SpinStop(UUID objectID, IClientAPI remoteClient);
165 165
166 public delegate void ParcelAccessListRequest( 166 public delegate void ParcelAccessListRequest(
@@ -607,6 +607,9 @@ namespace OpenSim.Framework
607 event GrabObject OnGrabObject; 607 event GrabObject OnGrabObject;
608 event ObjectSelect OnDeGrabObject; 608 event ObjectSelect OnDeGrabObject;
609 event MoveObject OnGrabUpdate; 609 event MoveObject OnGrabUpdate;
610 event SpinStart OnSpinStart;
611 event SpinObject OnSpinUpdate;
612 event SpinStop OnSpinStop;
610 613
611 event UpdateShape OnUpdatePrimShape; 614 event UpdateShape OnUpdatePrimShape;
612 event ObjectExtraParams OnUpdateExtraParams; 615 event ObjectExtraParams OnUpdateExtraParams;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 24d04de..239c4b3 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -172,7 +172,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
172 private MoveObject handlerGrabUpdate; //OnGrabUpdate; 172 private MoveObject handlerGrabUpdate; //OnGrabUpdate;
173 private ObjectSelect handlerDeGrabObject; //OnDeGrabObject; 173 private ObjectSelect handlerDeGrabObject; //OnDeGrabObject;
174 private SpinStart handlerSpinStart; //OnSpinStart; 174 private SpinStart handlerSpinStart; //OnSpinStart;
175 private SpinUpdate handlerSpinUpdate; //OnSpinUpdate; 175 private SpinObject handlerSpinUpdate; //OnSpinUpdate;
176 private SpinStop handlerSpinStop; //OnSpinStop; 176 private SpinStop handlerSpinStop; //OnSpinStop;
177 private GenericCall7 handlerObjectDescription; 177 private GenericCall7 handlerObjectDescription;
178 private GenericCall7 handlerObjectName; 178 private GenericCall7 handlerObjectName;
@@ -939,7 +939,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
939 public event ObjectDuplicate OnObjectDuplicate; 939 public event ObjectDuplicate OnObjectDuplicate;
940 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; 940 public event ObjectDuplicateOnRay OnObjectDuplicateOnRay;
941 public event MoveObject OnGrabUpdate; 941 public event MoveObject OnGrabUpdate;
942 public event SpinUpdate OnSpinUpdate; 942 public event SpinObject OnSpinUpdate;
943 public event AddNewPrim OnAddPrim; 943 public event AddNewPrim OnAddPrim;
944 public event RequestGodlikePowers OnRequestGodlikePowers; 944 public event RequestGodlikePowers OnRequestGodlikePowers;
945 public event GodKickUser OnGodKickUser; 945 public event GodKickUser OnGodKickUser;
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
index 90ed9ae..26839f3 100644
--- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
+++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
@@ -96,6 +96,9 @@ namespace OpenSim.Region.Examples.SimpleModule
96 public event GrabObject OnGrabObject; 96 public event GrabObject OnGrabObject;
97 public event ObjectSelect OnDeGrabObject; 97 public event ObjectSelect OnDeGrabObject;
98 public event MoveObject OnGrabUpdate; 98 public event MoveObject OnGrabUpdate;
99 public event SpinStart OnSpinStart;
100 public event SpinObject OnSpinUpdate;
101 public event SpinStop OnSpinStop;
99 public event ViewerEffectEventHandler OnViewerEffect; 102 public event ViewerEffectEventHandler OnViewerEffect;
100 103
101 public event FetchInventory OnAgentDataUpdateRequest; 104 public event FetchInventory OnAgentDataUpdateRequest;
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 8621f70..7496af0 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -132,6 +132,14 @@ namespace OpenSim.Region.Framework.Scenes
132 132
133 public event SceneGroupGrabed OnSceneGroupGrab; 133 public event SceneGroupGrabed OnSceneGroupGrab;
134 134
135 public delegate bool SceneGroupSpinStarted(UUID groupID);
136
137 public event SceneGroupSpinStarted OnSceneGroupSpinStart;
138
139 public delegate bool SceneGroupSpun(UUID groupID, Quaternion rotation);
140
141 public event SceneGroupSpun OnSceneGroupSpin;
142
135 public delegate void LandObjectAdded(ILandObject newParcel); 143 public delegate void LandObjectAdded(ILandObject newParcel);
136 144
137 public event LandObjectAdded OnLandObjectAdded; 145 public event LandObjectAdded OnLandObjectAdded;
@@ -381,6 +389,8 @@ namespace OpenSim.Region.Framework.Scenes
381 private StopScript handlerStopScript = null; //OnStopScript; 389 private StopScript handlerStopScript = null; //OnStopScript;
382 private SceneGroupMoved handlerSceneGroupMove = null; //OnSceneGroupMove; 390 private SceneGroupMoved handlerSceneGroupMove = null; //OnSceneGroupMove;
383 private SceneGroupGrabed handlerSceneGroupGrab = null; //OnSceneGroupGrab; 391 private SceneGroupGrabed handlerSceneGroupGrab = null; //OnSceneGroupGrab;
392 private SceneGroupSpinStarted handlerSceneGroupSpinStarted = null; //OnSceneGroupSpinStart;
393 private SceneGroupSpun handlerSceneGroupSpin = null; //OnSceneGroupSpin;
384 private LandObjectAdded handlerLandObjectAdded = null; //OnLandObjectAdded; 394 private LandObjectAdded handlerLandObjectAdded = null; //OnLandObjectAdded;
385 private LandObjectRemoved handlerLandObjectRemoved = null; //OnLandObjectRemoved; 395 private LandObjectRemoved handlerLandObjectRemoved = null; //OnLandObjectRemoved;
386 private AvatarEnteringNewParcel handlerAvatarEnteringNewParcel = null; //OnAvatarEnteringNewParcel; 396 private AvatarEnteringNewParcel handlerAvatarEnteringNewParcel = null; //OnAvatarEnteringNewParcel;
@@ -636,6 +646,28 @@ namespace OpenSim.Region.Framework.Scenes
636 return true; 646 return true;
637 } 647 }
638 648
649 public bool TriggerGroupSpinStart(UUID groupID)
650 {
651 handlerSceneGroupSpinStarted = OnSceneGroupSpinStart;
652
653 if (handlerSceneGroupSpinStarted != null)
654 {
655 return handlerSceneGroupSpinStarted(groupID);
656 }
657 return true;
658 }
659
660 public bool TriggerGroupSpin(UUID groupID, Quaternion rotation)
661 {
662 handlerSceneGroupSpin = OnSceneGroupSpin;
663
664 if (handlerSceneGroupSpin != null)
665 {
666 return handlerSceneGroupSpin(groupID, rotation);
667 }
668 return true;
669 }
670
639 public void TriggerGroupGrab(UUID groupID, Vector3 offset, UUID userID) 671 public void TriggerGroupGrab(UUID groupID, Vector3 offset, UUID userID)
640 { 672 {
641 handlerSceneGroupGrab = OnSceneGroupGrab; 673 handlerSceneGroupGrab = OnSceneGroupGrab;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 0fe27a5..54c420d 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1933,6 +1933,8 @@ namespace OpenSim.Region.Framework.Scenes
1933 client.OnObjectSelect += SelectPrim; 1933 client.OnObjectSelect += SelectPrim;
1934 client.OnObjectDeselect += DeselectPrim; 1934 client.OnObjectDeselect += DeselectPrim;
1935 client.OnGrabUpdate += m_sceneGraph.MoveObject; 1935 client.OnGrabUpdate += m_sceneGraph.MoveObject;
1936 client.OnSpinStart += m_sceneGraph.SpinStart;
1937 client.OnSpinUpdate += m_sceneGraph.SpinObject;
1936 client.OnDeRezObject += DeRezObject; 1938 client.OnDeRezObject += DeRezObject;
1937 client.OnRezObject += RezObject; 1939 client.OnRezObject += RezObject;
1938 client.OnRezSingleAttachmentFromInv += RezSingleAttachment; 1940 client.OnRezSingleAttachmentFromInv += RezSingleAttachment;
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index c2f9fd2..e6328dc 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -1342,6 +1342,47 @@ namespace OpenSim.Region.Framework.Scenes
1342 } 1342 }
1343 1343
1344 /// <summary> 1344 /// <summary>
1345 /// Start spinning the given object
1346 /// </summary>
1347 /// <param name="objectID"></param>
1348 /// <param name="rotation"></param>
1349 /// <param name="remoteClient"></param>
1350 protected internal void SpinStart(UUID objectID, IClientAPI remoteClient)
1351 {
1352 SceneObjectGroup group = GetGroupByPrim(objectID);
1353 if (group != null)
1354 {
1355 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1356 {
1357 group.SpinStart(remoteClient);
1358 }
1359 }
1360 }
1361
1362 /// <summary>
1363 /// Spin the given object
1364 /// </summary>
1365 /// <param name="objectID"></param>
1366 /// <param name="rotation"></param>
1367 /// <param name="remoteClient"></param>
1368 protected internal void SpinObject(UUID objectID, Quaternion rotation, IClientAPI remoteClient)
1369 {
1370 SceneObjectGroup group = GetGroupByPrim(objectID);
1371 if (group != null)
1372 {
1373 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1374 {
1375 group.SpinMovement(rotation, remoteClient);
1376 }
1377 // This is outside the above permissions condition
1378 // so that if the object is locked the client moving the object
1379 // get's it's position on the simulator even if it was the same as before
1380 // This keeps the moving user's client in sync with the rest of the world.
1381 group.SendGroupTerseUpdate();
1382 }
1383 }
1384
1385 /// <summary>
1345 /// 1386 ///
1346 /// </summary> 1387 /// </summary>
1347 /// <param name="primLocalID"></param> 1388 /// <param name="primLocalID"></param>
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 1834215..4fdc71e 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -2299,6 +2299,106 @@ namespace OpenSim.Region.Framework.Scenes
2299 } 2299 }
2300 2300
2301 /// <summary> 2301 /// <summary>
2302 /// If object is physical, prepare for spinning torques (set flag to save old orientation)
2303 /// </summary>
2304 /// <param name="rotation">Rotation. We do the math here to turn it into a torque</param>
2305 /// <param name="remoteClient"></param>
2306 public void SpinStart(IClientAPI remoteClient)
2307 {
2308 if (m_scene.EventManager.TriggerGroupSpinStart(UUID))
2309 {
2310 if (m_rootPart.PhysActor != null)
2311 {
2312 if (m_rootPart.PhysActor.IsPhysical)
2313 {
2314 m_rootPart.IsWaitingForFirstSpinUpdatePacket = true;
2315 }
2316 }
2317 }
2318 }
2319
2320 /// <summary>
2321 /// If object is physical, apply torque to spin it around
2322 /// </summary>
2323 /// <param name="rotation">Rotation. We do the math here to turn it into a torque</param>
2324 /// <param name="remoteClient"></param>
2325 public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient)
2326 {
2327 // The incoming newOrientation, sent by the client, "seems" to be the
2328 // desired target orientation. This needs further verification; in particular,
2329 // one would expect that the initial incoming newOrientation should be
2330 // fairly close to the original prim's physical orientation,
2331 // m_rootPart.PhysActor.Orientation. This however does not seem to be the
2332 // case (might just be an issue with different quaternions representing the
2333 // same rotation, or it might be a coordinate system issue).
2334 //
2335 // Since it's not clear what the relationship is between the PhysActor.Orientation
2336 // and the incoming orientations sent by the client, we take an alternative approach
2337 // of calculating the delta rotation between the orientations being sent by the
2338 // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect
2339 // a steady stream of several new orientations coming in from the client.)
2340 // This ensures that the delta rotations are being calculated from self-consistent
2341 // pairs of old/new rotations. Given the delta rotation, we apply a torque around
2342 // the delta rotation axis, scaled by the object mass times an arbitrary scaling
2343 // factor (to ensure the resulting torque is not "too strong" or "too weak").
2344 //
2345 // Ideally we need to calculate (probably iteratively) the exact torque or series
2346 // of torques needed to arrive exactly at the destination orientation. However, since
2347 // it is not yet clear how to map the destination orientation (provided by the viewer)
2348 // into PhysActor orientations (needed by the physics engine), we omit this step.
2349 // This means that the resulting torque will at least be in the correct direction,
2350 // but it will result in over-shoot or under-shoot of the target orientation.
2351 // For the end user, this means that ctrl+shift+drag can be used for relative,
2352 // but not absolute, adjustments of orientation for physical prims.
2353
2354 if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation))
2355 {
2356 if (m_rootPart.PhysActor != null)
2357 {
2358 if (m_rootPart.PhysActor.IsPhysical)
2359 {
2360 if(m_rootPart.IsWaitingForFirstSpinUpdatePacket)
2361 {
2362 // first time initialization of "old" orientation for calculation of delta rotations
2363 m_rootPart.SpinOldOrientation = newOrientation;
2364 m_rootPart.IsWaitingForFirstSpinUpdatePacket = false;
2365 }
2366 else
2367 {
2368 // save and update old orientation
2369 Quaternion old = m_rootPart.SpinOldOrientation;
2370 m_rootPart.SpinOldOrientation = newOrientation;
2371 //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old);
2372 //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation);
2373
2374 // compute difference between previous old rotation and new incoming rotation
2375 Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation;
2376
2377 float rotationAngle;
2378 Vector3 rotationAxis;
2379 minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle);
2380 rotationAxis.Normalize();
2381
2382 //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis);
2383 PhysicsVector spinforce = new PhysicsVector(rotationAxis.X, rotationAxis.Y, rotationAxis.Z);
2384 spinforce = (spinforce/8) * m_rootPart.PhysActor.Mass; // 8 is an arbitrary torque scaling factor
2385 m_rootPart.PhysActor.AddAngularForce(spinforce,true);
2386 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2387 }
2388 }
2389 else
2390 {
2391 //NonPhysicalSpinMovement(pos);
2392 }
2393 }
2394 else
2395 {
2396 //NonPhysicalSpinMovement(pos);
2397 }
2398 }
2399 }
2400
2401 /// <summary>
2302 /// Return metadata about a prim (name, description, sale price, etc.) 2402 /// Return metadata about a prim (name, description, sale price, etc.)
2303 /// </summary> 2403 /// </summary>
2304 /// <param name="client"></param> 2404 /// <param name="client"></param>
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 2a5a563..1a5dd6d 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -176,6 +176,11 @@ namespace OpenSim.Region.Framework.Scenes
176 public bool VolumeDetectActive = false; // XmlIgnore set to avoid problems with persistance until I come to care for this 176 public bool VolumeDetectActive = false; // XmlIgnore set to avoid problems with persistance until I come to care for this
177 // Certainly this must be a persistant setting finally 177 // Certainly this must be a persistant setting finally
178 178
179 [XmlIgnore]
180 public bool IsWaitingForFirstSpinUpdatePacket = false;
181 [XmlIgnore]
182 public Quaternion SpinOldOrientation = new Quaternion();
183
179 /// <summary> 184 /// <summary>
180 /// This part's inventory 185 /// This part's inventory
181 /// </summary> 186 /// </summary>
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 644f429..edd6b67 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -202,6 +202,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC
202 public event GrabObject OnGrabObject; 202 public event GrabObject OnGrabObject;
203 public event ObjectSelect OnDeGrabObject; 203 public event ObjectSelect OnDeGrabObject;
204 public event MoveObject OnGrabUpdate; 204 public event MoveObject OnGrabUpdate;
205 public event SpinStart OnSpinStart;
206 public event SpinObject OnSpinUpdate;
207 public event SpinStop OnSpinStop;
205 public event ViewerEffectEventHandler OnViewerEffect; 208 public event ViewerEffectEventHandler OnViewerEffect;
206 209
207 public event FetchInventory OnAgentDataUpdateRequest; 210 public event FetchInventory OnAgentDataUpdateRequest;
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index e82c26d..4647349 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -107,6 +107,9 @@ namespace OpenSim.Tests.Common.Mock
107 public event GrabObject OnGrabObject; 107 public event GrabObject OnGrabObject;
108 public event ObjectSelect OnDeGrabObject; 108 public event ObjectSelect OnDeGrabObject;
109 public event MoveObject OnGrabUpdate; 109 public event MoveObject OnGrabUpdate;
110 public event SpinStart OnSpinStart;
111 public event SpinObject OnSpinUpdate;
112 public event SpinStop OnSpinStop;
110 public event ViewerEffectEventHandler OnViewerEffect; 113 public event ViewerEffectEventHandler OnViewerEffect;
111 114
112 public event FetchInventory OnAgentDataUpdateRequest; 115 public event FetchInventory OnAgentDataUpdateRequest;