corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Threading;
29 using OpenMetaverse;
30 using OpenMetaverse.Packets;
31  
32 namespace OpenMetaverse
33 {
34 public partial class AgentManager
35 {
36 #region Enums
37  
38 /// <summary>
39 /// Used to specify movement actions for your agent
40 /// </summary>
41 [Flags]
42 public enum ControlFlags
43 {
44 /// <summary>Empty flag</summary>
45 NONE = 0,
46 /// <summary>Move Forward (SL Keybinding: W/Up Arrow)</summary>
47 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX,
48 /// <summary>Move Backward (SL Keybinding: S/Down Arrow)</summary>
49 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX,
50 /// <summary>Move Left (SL Keybinding: Shift-(A/Left Arrow))</summary>
51 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX,
52 /// <summary>Move Right (SL Keybinding: Shift-(D/Right Arrow))</summary>
53 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX,
54 /// <summary>Not Flying: Jump/Flying: Move Up (SL Keybinding: E)</summary>
55 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX,
56 /// <summary>Not Flying: Croutch/Flying: Move Down (SL Keybinding: C)</summary>
57 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX,
58 /// <summary>Unused</summary>
59 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX,
60 /// <summary>Unused</summary>
61 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX,
62 /// <summary>Unused</summary>
63 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX,
64 /// <summary>Unused</summary>
65 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX,
66 /// <summary>ORed with AGENT_CONTROL_AT_* if the keyboard is being used</summary>
67 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX,
68 /// <summary>ORed with AGENT_CONTROL_LEFT_* if the keyboard is being used</summary>
69 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX,
70 /// <summary>ORed with AGENT_CONTROL_UP_* if the keyboard is being used</summary>
71 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX,
72 /// <summary>Fly</summary>
73 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX,
74 /// <summary></summary>
75 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX,
76 /// <summary>Finish our current animation</summary>
77 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX,
78 /// <summary>Stand up from the ground or a prim seat</summary>
79 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX,
80 /// <summary>Sit on the ground at our current location</summary>
81 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX,
82 /// <summary>Whether mouselook is currently enabled</summary>
83 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX,
84 /// <summary>Legacy, used if a key was pressed for less than a certain amount of time</summary>
85 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX,
86 /// <summary>Legacy, used if a key was pressed for less than a certain amount of time</summary>
87 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX,
88 /// <summary>Legacy, used if a key was pressed for less than a certain amount of time</summary>
89 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX,
90 /// <summary>Legacy, used if a key was pressed for less than a certain amount of time</summary>
91 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX,
92 /// <summary>Legacy, used if a key was pressed for less than a certain amount of time</summary>
93 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX,
94 /// <summary>Legacy, used if a key was pressed for less than a certain amount of time</summary>
95 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX,
96 /// <summary></summary>
97 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX,
98 /// <summary></summary>
99 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX,
100 /// <summary>Set when the avatar is idled or set to away. Note that the away animation is
101 /// activated separately from setting this flag</summary>
102 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX,
103 /// <summary></summary>
104 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX,
105 /// <summary></summary>
106 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX,
107 /// <summary></summary>
108 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX,
109 /// <summary></summary>
110 AGENT_CONTROL_ML_LBUTTON_UP = 0x1 << CONTROL_ML_LBUTTON_UP_INDEX
111 }
112  
113 #endregion Enums
114  
115 #region AgentUpdate Constants
116  
117 private const int CONTROL_AT_POS_INDEX = 0;
118 private const int CONTROL_AT_NEG_INDEX = 1;
119 private const int CONTROL_LEFT_POS_INDEX = 2;
120 private const int CONTROL_LEFT_NEG_INDEX = 3;
121 private const int CONTROL_UP_POS_INDEX = 4;
122 private const int CONTROL_UP_NEG_INDEX = 5;
123 private const int CONTROL_PITCH_POS_INDEX = 6;
124 private const int CONTROL_PITCH_NEG_INDEX = 7;
125 private const int CONTROL_YAW_POS_INDEX = 8;
126 private const int CONTROL_YAW_NEG_INDEX = 9;
127 private const int CONTROL_FAST_AT_INDEX = 10;
128 private const int CONTROL_FAST_LEFT_INDEX = 11;
129 private const int CONTROL_FAST_UP_INDEX = 12;
130 private const int CONTROL_FLY_INDEX = 13;
131 private const int CONTROL_STOP_INDEX = 14;
132 private const int CONTROL_FINISH_ANIM_INDEX = 15;
133 private const int CONTROL_STAND_UP_INDEX = 16;
134 private const int CONTROL_SIT_ON_GROUND_INDEX = 17;
135 private const int CONTROL_MOUSELOOK_INDEX = 18;
136 private const int CONTROL_NUDGE_AT_POS_INDEX = 19;
137 private const int CONTROL_NUDGE_AT_NEG_INDEX = 20;
138 private const int CONTROL_NUDGE_LEFT_POS_INDEX = 21;
139 private const int CONTROL_NUDGE_LEFT_NEG_INDEX = 22;
140 private const int CONTROL_NUDGE_UP_POS_INDEX = 23;
141 private const int CONTROL_NUDGE_UP_NEG_INDEX = 24;
142 private const int CONTROL_TURN_LEFT_INDEX = 25;
143 private const int CONTROL_TURN_RIGHT_INDEX = 26;
144 private const int CONTROL_AWAY_INDEX = 27;
145 private const int CONTROL_LBUTTON_DOWN_INDEX = 28;
146 private const int CONTROL_LBUTTON_UP_INDEX = 29;
147 private const int CONTROL_ML_LBUTTON_DOWN_INDEX = 30;
148 private const int CONTROL_ML_LBUTTON_UP_INDEX = 31;
149 private const int TOTAL_CONTROLS = 32;
150  
151 #endregion AgentUpdate Constants
152  
153 /// <summary>
154 /// Agent movement and camera control
155 ///
156 /// Agent movement is controlled by setting specific <seealso cref="T:AgentManager.ControlFlags"/>
157 /// After the control flags are set, An AgentUpdate is required to update the simulator of the specified flags
158 /// This is most easily accomplished by setting one or more of the AgentMovement properties
159 ///
160 /// Movement of an avatar is always based on a compass direction, for example AtPos will move the
161 /// agent from West to East or forward on the X Axis, AtNeg will of course move agent from
162 /// East to West or backward on the X Axis, LeftPos will be South to North or forward on the Y Axis
163 /// The Z axis is Up, finer grained control of movements can be done using the Nudge properties
164 /// </summary>
165 public partial class AgentMovement
166 {
167 #region Properties
168  
169 /// <summary>Move agent positive along the X axis</summary>
170 public bool AtPos
171 {
172 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS); }
173 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS, value); }
174 }
175 /// <summary>Move agent negative along the X axis</summary>
176 public bool AtNeg
177 {
178 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG); }
179 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG, value); }
180 }
181 /// <summary>Move agent positive along the Y axis</summary>
182 public bool LeftPos
183 {
184 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS); }
185 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS, value); }
186 }
187 /// <summary>Move agent negative along the Y axis</summary>
188 public bool LeftNeg
189 {
190 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG); }
191 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG, value); }
192 }
193 /// <summary>Move agent positive along the Z axis</summary>
194 public bool UpPos
195 {
196 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_POS); }
197 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, value); }
198 }
199 /// <summary>Move agent negative along the Z axis</summary>
200 public bool UpNeg
201 {
202 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG); }
203 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, value); }
204 }
205 /// <summary></summary>
206 public bool PitchPos
207 {
208 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_POS); }
209 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_POS, value); }
210 }
211 /// <summary></summary>
212 public bool PitchNeg
213 {
214 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_NEG); }
215 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_NEG, value); }
216 }
217 /// <summary></summary>
218 public bool YawPos
219 {
220 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS); }
221 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS, value); }
222 }
223 /// <summary></summary>
224 public bool YawNeg
225 {
226 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG); }
227 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG, value); }
228 }
229 /// <summary></summary>
230 public bool FastAt
231 {
232 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT); }
233 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT, value); }
234 }
235 /// <summary></summary>
236 public bool FastLeft
237 {
238 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_LEFT); }
239 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_LEFT, value); }
240 }
241 /// <summary></summary>
242 public bool FastUp
243 {
244 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_UP); }
245 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_UP, value); }
246 }
247 /// <summary>Causes simulator to make agent fly</summary>
248 public bool Fly
249 {
250 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FLY); }
251 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FLY, value); }
252 }
253 /// <summary>Stop movement</summary>
254 public bool Stop
255 {
256 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STOP); }
257 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STOP, value); }
258 }
259 /// <summary>Finish animation</summary>
260 public bool FinishAnim
261 {
262 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM); }
263 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM, value); }
264 }
265 /// <summary>Stand up from a sit</summary>
266 public bool StandUp
267 {
268 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP); }
269 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP, value); }
270 }
271 /// <summary>Tells simulator to sit agent on ground</summary>
272 public bool SitOnGround
273 {
274 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND); }
275 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND, value); }
276 }
277 /// <summary>Place agent into mouselook mode</summary>
278 public bool Mouselook
279 {
280 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK); }
281 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK, value); }
282 }
283 /// <summary>Nudge agent positive along the X axis</summary>
284 public bool NudgeAtPos
285 {
286 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS); }
287 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, value); }
288 }
289 /// <summary>Nudge agent negative along the X axis</summary>
290 public bool NudgeAtNeg
291 {
292 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG); }
293 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, value); }
294 }
295 /// <summary>Nudge agent positive along the Y axis</summary>
296 public bool NudgeLeftPos
297 {
298 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS); }
299 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS, value); }
300 }
301 /// <summary>Nudge agent negative along the Y axis</summary>
302 public bool NudgeLeftNeg
303 {
304 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG); }
305 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG, value); }
306 }
307 /// <summary>Nudge agent positive along the Z axis</summary>
308 public bool NudgeUpPos
309 {
310 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS); }
311 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS, value); }
312 }
313 /// <summary>Nudge agent negative along the Z axis</summary>
314 public bool NudgeUpNeg
315 {
316 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG); }
317 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG, value); }
318 }
319 /// <summary></summary>
320 public bool TurnLeft
321 {
322 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT); }
323 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT, value); }
324 }
325 /// <summary></summary>
326 public bool TurnRight
327 {
328 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT); }
329 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT, value); }
330 }
331 /// <summary>Tell simulator to mark agent as away</summary>
332 public bool Away
333 {
334 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AWAY); }
335 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AWAY, value); }
336 }
337 /// <summary></summary>
338 public bool LButtonDown
339 {
340 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN); }
341 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN, value); }
342 }
343 /// <summary></summary>
344 public bool LButtonUp
345 {
346 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP); }
347 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP, value); }
348 }
349 /// <summary></summary>
350 public bool MLButtonDown
351 {
352 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN); }
353 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN, value); }
354 }
355 /// <summary></summary>
356 public bool MLButtonUp
357 {
358 get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP); }
359 set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP, value); }
360 }
361 /// <summary>
362 /// Returns "always run" value, or changes it by sending a SetAlwaysRunPacket
363 /// </summary>
364 public bool AlwaysRun
365 {
366 get
367 {
368 return alwaysRun;
369 }
370 set
371 {
372 alwaysRun = value;
373 SetAlwaysRunPacket run = new SetAlwaysRunPacket();
374 run.AgentData.AgentID = Client.Self.AgentID;
375 run.AgentData.SessionID = Client.Self.SessionID;
376 run.AgentData.AlwaysRun = alwaysRun;
377 Client.Network.SendPacket(run);
378 }
379 }
380 /// <summary>The current value of the agent control flags</summary>
381 public uint AgentControls
382 {
383 get { return agentControls; }
384 }
385  
386 /// <summary>Gets or sets the interval in milliseconds at which
387 /// AgentUpdate packets are sent to the current simulator. Setting
388 /// this to a non-zero value will also enable the packet sending if
389 /// it was previously off, and setting it to zero will disable</summary>
390 public int UpdateInterval
391 {
392 get
393 {
394 return updateInterval;
395 }
396 set
397 {
398 if (value > 0)
399 {
400 if (updateTimer != null)
401 {
402 updateTimer.Change(value, value);
403 }
404 updateInterval = value;
405 }
406 else
407 {
408 if (updateTimer != null)
409 {
410 updateTimer.Change(Timeout.Infinite, Timeout.Infinite);
411 }
412 updateInterval = 0;
413 }
414 }
415 }
416 /// <summary>Gets or sets whether AgentUpdate packets are sent to
417 /// the current simulator</summary>
418 public bool UpdateEnabled
419 {
420 get { return (updateInterval != 0); }
421 }
422  
423 /// <summary>Reset movement controls every time we send an update</summary>
424 public bool AutoResetControls
425 {
426 get { return autoResetControls; }
427 set { autoResetControls = value; }
428 }
429  
430 #endregion Properties
431  
432 /// <summary>Agent camera controls</summary>
433 public AgentCamera Camera;
434 /// <summary>Currently only used for hiding your group title</summary>
435 public AgentFlags Flags = AgentFlags.None;
436 /// <summary>Action state of the avatar, which can currently be
437 /// typing and editing</summary>
438 public AgentState State = AgentState.None;
439 /// <summary></summary>
440 public Quaternion BodyRotation = Quaternion.Identity;
441 /// <summary></summary>
442 public Quaternion HeadRotation = Quaternion.Identity;
443  
444 #region Change tracking
445 /// <summary></summary>
446 private Quaternion LastBodyRotation;
447 /// <summary></summary>
448 private Quaternion LastHeadRotation;
449 /// <summary></summary>
450 private Vector3 LastCameraCenter;
451 /// <summary></summary>
452 private Vector3 LastCameraXAxis;
453 /// <summary></summary>
454 private Vector3 LastCameraYAxis;
455 /// <summary></summary>
456 private Vector3 LastCameraZAxis;
457 /// <summary></summary>
458 private float LastFar;
459 #endregion Change tracking
460  
461 private bool alwaysRun;
462 private GridClient Client;
463 private uint agentControls;
464 private int duplicateCount;
465 private AgentState lastState;
466 /// <summary>Timer for sending AgentUpdate packets</summary>
467 private Timer updateTimer;
468 private int updateInterval;
469 private bool autoResetControls;
470  
471 /// <summary>Default constructor</summary>
472 public AgentMovement(GridClient client)
473 {
474 Client = client;
475 Camera = new AgentCamera();
476 Client.Network.LoginProgress += Network_OnConnected;
477 Client.Network.Disconnected += Network_OnDisconnected;
478 updateInterval = Settings.DEFAULT_AGENT_UPDATE_INTERVAL;
479 }
480  
481 private void CleanupTimer()
482 {
483 if (updateTimer != null)
484 {
485 updateTimer.Dispose();
486 updateTimer = null;
487 }
488 }
489  
490 private void Network_OnDisconnected(object sender, DisconnectedEventArgs e)
491 {
492 CleanupTimer();
493 }
494  
495 private void Network_OnConnected(object sender, LoginProgressEventArgs e)
496 {
497 if (e.Status == LoginStatus.Success)
498 {
499 CleanupTimer();
500 updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed), null, updateInterval, updateInterval);
501 }
502 }
503  
504 /// <summary>
505 /// Send an AgentUpdate with the camera set at the current agent
506 /// position and pointing towards the heading specified
507 /// </summary>
508 /// <param name="heading">Camera rotation in radians</param>
509 /// <param name="reliable">Whether to send the AgentUpdate reliable
510 /// or not</param>
511 public void UpdateFromHeading(double heading, bool reliable)
512 {
513 Camera.Position = Client.Self.SimPosition;
514 Camera.LookDirection(heading);
515  
516 BodyRotation.Z = (float)Math.Sin(heading / 2.0d);
517 BodyRotation.W = (float)Math.Cos(heading / 2.0d);
518 HeadRotation = BodyRotation;
519  
520 SendUpdate(reliable);
521 }
522  
523 /// <summary>
524 /// Rotates the avatar body and camera toward a target position.
525 /// This will also anchor the camera position on the avatar
526 /// </summary>
527 /// <param name="target">Region coordinates to turn toward</param>
528 public bool TurnToward(Vector3 target)
529 {
530 return TurnToward(target, true);
531 }
532  
533 /// <summary>
534 /// Rotates the avatar body and camera toward a target position.
535 /// This will also anchor the camera position on the avatar
536 /// </summary>
537 /// <param name="target">Region coordinates to turn toward</param>
538 /// <param name="sendUpdate">whether to send update or not</param>
539 public bool TurnToward(Vector3 target, bool sendUpdate)
540 {
541 if (Client.Settings.SEND_AGENT_UPDATES)
542 {
543 Quaternion parentRot = Quaternion.Identity;
544  
545 if (Client.Self.SittingOn > 0)
546 {
547 if (!Client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(Client.Self.SittingOn))
548 {
549 Logger.Log("Attempted TurnToward but parent prim is not in dictionary", Helpers.LogLevel.Warning, Client);
550 return false;
551 }
552 else parentRot = Client.Network.CurrentSim.ObjectsPrimitives[Client.Self.SittingOn].Rotation;
553 }
554  
555 Quaternion between = Vector3.RotationBetween(Vector3.UnitX, Vector3.Normalize(target - Client.Self.SimPosition));
556 Quaternion rot = between * (Quaternion.Identity / parentRot);
557  
558 BodyRotation = rot;
559 HeadRotation = rot;
560 Camera.LookAt(Client.Self.SimPosition, target);
561  
562 if (sendUpdate) SendUpdate();
563  
564 return true;
565 }
566 else
567 {
568 Logger.Log("Attempted TurnToward but agent updates are disabled", Helpers.LogLevel.Warning, Client);
569 return false;
570 }
571 }
572  
573 /// <summary>
574 /// Send new AgentUpdate packet to update our current camera
575 /// position and rotation
576 /// </summary>
577 public void SendUpdate()
578 {
579 SendUpdate(false, Client.Network.CurrentSim);
580 }
581  
582 /// <summary>
583 /// Send new AgentUpdate packet to update our current camera
584 /// position and rotation
585 /// </summary>
586 /// <param name="reliable">Whether to require server acknowledgement
587 /// of this packet</param>
588 public void SendUpdate(bool reliable)
589 {
590 SendUpdate(reliable, Client.Network.CurrentSim);
591 }
592  
593 /// <summary>
594 /// Send new AgentUpdate packet to update our current camera
595 /// position and rotation
596 /// </summary>
597 /// <param name="reliable">Whether to require server acknowledgement
598 /// of this packet</param>
599 /// <param name="simulator">Simulator to send the update to</param>
600 public void SendUpdate(bool reliable, Simulator simulator)
601 {
602 // Since version 1.40.4 of the Linden simulator, sending this update
603 // causes corruption of the agent position in the simulator
604 if (simulator != null && (!simulator.AgentMovementComplete))
605 return;
606  
607 Vector3 origin = Camera.Position;
608 Vector3 xAxis = Camera.LeftAxis;
609 Vector3 yAxis = Camera.AtAxis;
610 Vector3 zAxis = Camera.UpAxis;
611  
612 // Attempted to sort these in a rough order of how often they might change
613 if (agentControls == 0 &&
614 yAxis == LastCameraYAxis &&
615 origin == LastCameraCenter &&
616 State == lastState &&
617 HeadRotation == LastHeadRotation &&
618 BodyRotation == LastBodyRotation &&
619 xAxis == LastCameraXAxis &&
620 Camera.Far == LastFar &&
621 zAxis == LastCameraZAxis)
622 {
623 ++duplicateCount;
624 }
625 else
626 {
627 duplicateCount = 0;
628 }
629  
630 if (Client.Settings.DISABLE_AGENT_UPDATE_DUPLICATE_CHECK || duplicateCount < 10)
631 {
632 // Store the current state to do duplicate checking
633 LastHeadRotation = HeadRotation;
634 LastBodyRotation = BodyRotation;
635 LastCameraYAxis = yAxis;
636 LastCameraCenter = origin;
637 LastCameraXAxis = xAxis;
638 LastCameraZAxis = zAxis;
639 LastFar = Camera.Far;
640 lastState = State;
641  
642 // Build the AgentUpdate packet and send it
643 AgentUpdatePacket update = new AgentUpdatePacket();
644 update.Header.Reliable = reliable;
645  
646 update.AgentData.AgentID = Client.Self.AgentID;
647 update.AgentData.SessionID = Client.Self.SessionID;
648 update.AgentData.HeadRotation = HeadRotation;
649 update.AgentData.BodyRotation = BodyRotation;
650 update.AgentData.CameraAtAxis = xAxis;
651 update.AgentData.CameraCenter = origin;
652 update.AgentData.CameraLeftAxis = yAxis;
653 update.AgentData.CameraUpAxis = zAxis;
654 update.AgentData.Far = Camera.Far;
655 update.AgentData.State = (byte)State;
656 update.AgentData.ControlFlags = agentControls;
657 update.AgentData.Flags = (byte)Flags;
658  
659 Client.Network.SendPacket(update, simulator);
660  
661 if (autoResetControls) {
662 ResetControlFlags();
663 }
664 }
665 }
666  
667 /// <summary>
668 /// Builds an AgentUpdate packet entirely from parameters. This
669 /// will not touch the state of Self.Movement or
670 /// Self.Movement.Camera in any way
671 /// </summary>
672 /// <param name="controlFlags"></param>
673 /// <param name="position"></param>
674 /// <param name="forwardAxis"></param>
675 /// <param name="leftAxis"></param>
676 /// <param name="upAxis"></param>
677 /// <param name="bodyRotation"></param>
678 /// <param name="headRotation"></param>
679 /// <param name="farClip"></param>
680 /// <param name="reliable"></param>
681 /// <param name="flags"></param>
682 /// <param name="state"></param>
683 public void SendManualUpdate(AgentManager.ControlFlags controlFlags, Vector3 position, Vector3 forwardAxis,
684 Vector3 leftAxis, Vector3 upAxis, Quaternion bodyRotation, Quaternion headRotation, float farClip,
685 AgentFlags flags, AgentState state, bool reliable)
686 {
687 // Since version 1.40.4 of the Linden simulator, sending this update
688 // causes corruption of the agent position in the simulator
689 if (Client.Network.CurrentSim != null && (!Client.Network.CurrentSim.HandshakeComplete))
690 return;
691  
692 AgentUpdatePacket update = new AgentUpdatePacket();
693  
694 update.AgentData.AgentID = Client.Self.AgentID;
695 update.AgentData.SessionID = Client.Self.SessionID;
696 update.AgentData.BodyRotation = bodyRotation;
697 update.AgentData.HeadRotation = headRotation;
698 update.AgentData.CameraCenter = position;
699 update.AgentData.CameraAtAxis = forwardAxis;
700 update.AgentData.CameraLeftAxis = leftAxis;
701 update.AgentData.CameraUpAxis = upAxis;
702 update.AgentData.Far = farClip;
703 update.AgentData.ControlFlags = (uint)controlFlags;
704 update.AgentData.Flags = (byte)flags;
705 update.AgentData.State = (byte)state;
706  
707 update.Header.Reliable = reliable;
708  
709 Client.Network.SendPacket(update);
710 }
711  
712 private bool GetControlFlag(ControlFlags flag)
713 {
714 return (agentControls & (uint)flag) != 0;
715 }
716  
717 private void SetControlFlag(ControlFlags flag, bool value)
718 {
719 if (value) agentControls |= (uint)flag;
720 else agentControls &= ~((uint)flag);
721 }
722  
723 public void ResetControlFlags()
724 {
725 // Reset all of the flags except for persistent settings like
726 // away, fly, mouselook, and crouching
727 agentControls &=
728 (uint)(ControlFlags.AGENT_CONTROL_AWAY |
729 ControlFlags.AGENT_CONTROL_FLY |
730 ControlFlags.AGENT_CONTROL_MOUSELOOK |
731 ControlFlags.AGENT_CONTROL_UP_NEG);
732 }
733  
734  
735 /// <summary>
736 /// Sends update of Field of Vision vertical angle to the simulator
737 /// </summary>
738 /// <param name="angle">Angle in radians</param>
739 public void SetFOVVerticalAngle(float angle)
740 {
741 OpenMetaverse.Packets.AgentFOVPacket msg = new OpenMetaverse.Packets.AgentFOVPacket();
742 msg.AgentData.AgentID = Client.Self.AgentID;
743 msg.AgentData.SessionID = Client.Self.SessionID;
744 msg.AgentData.CircuitCode = Client.Network.CircuitCode;
745 msg.FOVBlock.GenCounter = 0;
746 msg.FOVBlock.VerticalAngle = angle;
747 Client.Network.SendPacket(msg);
748 }
749  
750 private void UpdateTimer_Elapsed(object obj)
751 {
752 if (Client.Network.Connected && Client.Settings.SEND_AGENT_UPDATES)
753 {
754 //Send an AgentUpdate packet
755 SendUpdate(false, Client.Network.CurrentSim);
756 }
757 }
758 }
759 }
760 }