2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2013, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 using System.Collections.Generic;
34 using System.Threading;
38 using Radegast.Automation;
39 using Radegast.Netcom;
43 public class KnownHeading
45 public string ID { get; set; }
46 public string Name { get; set; }
47 public Quaternion Heading { get; set; }
49 public KnownHeading(string id, string name, Quaternion heading)
53 this.Heading = heading;
56 public override string ToString()
62 public class StateManager : IDisposable
64 public Parcel Parcel { get; set; }
66 private RadegastInstance instance;
67 private GridClient client { get { return instance.Client; } }
68 private RadegastNetcom netcom { get { return instance.Netcom; } }
70 private bool typing = false;
71 private bool away = false;
72 private bool busy = false;
73 private bool flying = false;
74 private bool alwaysrun = false;
75 private bool sitting = false;
77 private bool following = false;
78 private string followName = string.Empty;
79 private float followDistance = 3.0f;
80 private UUID followID;
81 private bool displayEndWalk = false;
83 private UUID awayAnimationID = new UUID("fd037134-85d4-f241-72c6-4f42164fedee");
84 private UUID busyAnimationID = new UUID("efcf670c2d188128973a034ebc806b67");
85 private UUID typingAnimationID = new UUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
86 internal static Random rnd = new Random();
87 private System.Threading.Timer lookAtTimer;
89 public float FOVVerticalAngle = Utils.TWO_PI - 0.05f;
94 /// <param name="walking">True if we are walking towards a targer</param>
95 public delegate void WalkStateCanged(bool walking);
98 /// Fires when we start or stop walking towards a target
100 public event WalkStateCanged OnWalkStateCanged;
103 /// Fires when avatar stands
105 public event EventHandler<SitEventArgs> SitStateChanged;
107 static List<KnownHeading> m_Headings;
108 public static List<KnownHeading> KnownHeadings
112 if (m_Headings == null)
114 m_Headings = new List<KnownHeading>(16);
115 m_Headings.Add(new KnownHeading("E", "East", new Quaternion(0.00000f, 0.00000f, 0.00000f, 1.00000f)));
116 m_Headings.Add(new KnownHeading("ENE", "East by Northeast", new Quaternion(0.00000f, 0.00000f, 0.19509f, 0.98079f)));
117 m_Headings.Add(new KnownHeading("NE", "Northeast", new Quaternion(0.00000f, 0.00000f, 0.38268f, 0.92388f)));
118 m_Headings.Add(new KnownHeading("NNE", "North by Northeast", new Quaternion(0.00000f, 0.00000f, 0.55557f, 0.83147f)));
119 m_Headings.Add(new KnownHeading("N", "North", new Quaternion(0.00000f, 0.00000f, 0.70711f, 0.70711f)));
120 m_Headings.Add(new KnownHeading("NNW", "North by Northwest", new Quaternion(0.00000f, 0.00000f, 0.83147f, 0.55557f)));
121 m_Headings.Add(new KnownHeading("NW", "Nortwest", new Quaternion(0.00000f, 0.00000f, 0.92388f, 0.38268f)));
122 m_Headings.Add(new KnownHeading("WNW", "West by Northwest", new Quaternion(0.00000f, 0.00000f, 0.98079f, 0.19509f)));
123 m_Headings.Add(new KnownHeading("W", "West", new Quaternion(0.00000f, 0.00000f, 1.00000f, -0.00000f)));
124 m_Headings.Add(new KnownHeading("WSW", "West by Southwest", new Quaternion(0.00000f, 0.00000f, 0.98078f, -0.19509f)));
125 m_Headings.Add(new KnownHeading("SW", "Southwest", new Quaternion(0.00000f, 0.00000f, 0.92388f, -0.38268f)));
126 m_Headings.Add(new KnownHeading("SSW", "South by Southwest", new Quaternion(0.00000f, 0.00000f, 0.83147f, -0.55557f)));
127 m_Headings.Add(new KnownHeading("S", "South", new Quaternion(0.00000f, 0.00000f, 0.70711f, -0.70711f)));
128 m_Headings.Add(new KnownHeading("SSE", "South by Southeast", new Quaternion(0.00000f, 0.00000f, 0.55557f, -0.83147f)));
129 m_Headings.Add(new KnownHeading("SE", "Southeast", new Quaternion(0.00000f, 0.00000f, 0.38268f, -0.92388f)));
130 m_Headings.Add(new KnownHeading("ESE", "East by Southeast", new Quaternion(0.00000f, 0.00000f, 0.19509f, -0.98078f)));
136 public static Vector3 RotToEuler(Quaternion r)
138 Quaternion t = new Quaternion(r.X * r.X, r.Y * r.Y, r.Z * r.Z, r.W * r.W);
140 float m = (t.X + t.Y + t.Z + t.W);
141 if (Math.Abs(m) < 0.001) return Vector3.Zero;
142 float n = 2 * (r.Y * r.W + r.X * r.Z);
143 float p = m * m - n * n;
147 (float)Math.Atan2(2.0 * (r.X * r.W - r.Y * r.Z), (-t.X - t.Y + t.Z + t.W)),
148 (float)Math.Atan2(n, Math.Sqrt(p)),
149 (float)Math.Atan2(2.0 * (r.Z * r.W - r.X * r.Y), t.X - t.Y - t.Z + t.W)
154 (float)(Math.PI / 2d),
155 (float)Math.Atan2((r.Z * r.W + r.X * r.Y), 0.5 - t.X - t.Y)
160 -(float)(Math.PI / 2d),
161 (float)Math.Atan2((r.Z * r.W + r.X * r.Y), 0.5 - t.X - t.Z)
165 public static KnownHeading ClosestKnownHeading(int degrees)
167 KnownHeading ret = KnownHeadings[0];
168 int facing = (int)(57.2957795d * RotToEuler(KnownHeadings[0].Heading).Z);
169 if (facing < 0) facing += 360;
170 int minDistance = Math.Abs(degrees - facing);
172 for (int i = 1; i < KnownHeadings.Count; i++)
174 facing = (int)(57.2957795d * RotToEuler(KnownHeadings[i].Heading).Z);
175 if (facing < 0) facing += 360;
177 int distance = Math.Abs(degrees - facing);
178 if (distance < minDistance)
180 ret = KnownHeadings[i];
181 minDistance = distance;
188 public Dictionary<UUID, string> KnownAnimations;
189 public bool CameraTracksOwnAvatar = true;
190 public Vector3 DefaultCameraOffset = new Vector3(-5, 0, 0);
192 public StateManager(RadegastInstance instance)
194 this.instance = instance;
195 this.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
196 KnownAnimations = Animations.ToDictionary();
197 autosit = new AutoSit(this.instance);
198 pseudohome = new PseudoHome(this.instance);
199 lslHelper = new LSLHelper(this.instance);
201 beamTimer = new System.Timers.Timer();
202 beamTimer.Enabled = false;
203 beamTimer.Elapsed += new ElapsedEventHandler(beamTimer_Elapsed);
206 netcom.ClientConnected += new EventHandler<EventArgs>(netcom_ClientConnected);
207 netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
208 netcom.ChatReceived += new EventHandler<ChatEventArgs>(netcom_ChatReceived);
209 RegisterClientEvents(client);
213 private void RegisterClientEvents(GridClient client)
215 client.Objects.AvatarUpdate += new EventHandler<AvatarUpdateEventArgs>(Objects_AvatarUpdate);
216 client.Objects.TerseObjectUpdate += new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);
217 client.Objects.AvatarSitChanged += new EventHandler<AvatarSitChangedEventArgs>(Objects_AvatarSitChanged);
218 client.Self.AlertMessage += new EventHandler<AlertMessageEventArgs>(Self_AlertMessage);
219 client.Self.TeleportProgress += new EventHandler<TeleportEventArgs>(Self_TeleportProgress);
220 client.Network.EventQueueRunning += new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
221 client.Network.SimChanged += new EventHandler<SimChangedEventArgs>(Network_SimChanged);
224 private void UnregisterClientEvents(GridClient client)
226 client.Objects.AvatarUpdate -= new EventHandler<AvatarUpdateEventArgs>(Objects_AvatarUpdate);
227 client.Objects.TerseObjectUpdate -= new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);
228 client.Objects.AvatarSitChanged -= new EventHandler<AvatarSitChangedEventArgs>(Objects_AvatarSitChanged);
229 client.Self.AlertMessage -= new EventHandler<AlertMessageEventArgs>(Self_AlertMessage);
230 client.Self.TeleportProgress -= new EventHandler<TeleportEventArgs>(Self_TeleportProgress);
231 client.Network.EventQueueRunning -= new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
232 client.Network.SimChanged -= new EventHandler<SimChangedEventArgs>(Network_SimChanged);
235 public void Dispose()
237 netcom.ClientConnected -= new EventHandler<EventArgs>(netcom_ClientConnected);
238 netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
239 netcom.ChatReceived -= new EventHandler<ChatEventArgs>(netcom_ChatReceived);
240 UnregisterClientEvents(client);
244 if (lookAtTimer != null)
246 lookAtTimer.Dispose();
250 if (walkTimer != null)
262 if (lslHelper == null)
269 void instance_ClientChanged(object sender, ClientChangedEventArgs e)
271 UnregisterClientEvents(e.OldClient);
272 RegisterClientEvents(client);
275 void Objects_AvatarSitChanged(object sender, AvatarSitChangedEventArgs e)
277 if (e.Avatar.LocalID != client.Self.LocalID) return;
279 sitting = e.SittingOn != 0;
281 if (client.Self.SittingOn != 0 && !client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(client.Self.SittingOn))
283 client.Objects.RequestObject(client.Network.CurrentSim, client.Self.SittingOn);
286 if (SitStateChanged != null)
288 SitStateChanged(this, new SitEventArgs(this.sitting));
293 /// Locates avatar in the current sim, or adjacents sims
295 /// <param name="person">Avatar UUID</param>
296 /// <param name="position">Position within sim</param>
297 /// <returns>True if managed to find the avatar</returns>
298 public bool TryFindAvatar(UUID person, out Vector3 position)
301 if (!TryFindAvatar(person, out sim, out position)) return false;
303 if (sim == client.Network.CurrentSim) return true;
304 position = ToLocalPosition(sim.Handle, position);
308 public Vector3 ToLocalPosition(ulong handle, Vector3 position)
310 Vector3d diff = ToVector3D(handle, position) - client.Self.GlobalPosition;
311 position = new Vector3((float) diff.X, (float) diff.Y, (float) diff.Z) - position;
315 public static Vector3d ToVector3D(ulong handle, Vector3 pos)
317 uint globalX, globalY;
318 Utils.LongToUInts(handle, out globalX, out globalY);
321 (double)globalX + (double)pos.X,
322 (double)globalY + (double)pos.Y,
327 /// Locates avatar in the current sim, or adjacents sims
329 /// <param name="person">Avatar UUID</param>
330 /// <param name="sim">Simulator avatar is in</param>
331 /// <param name="position">Position within sim</param>
332 /// <returns>True if managed to find the avatar</returns>
333 public bool TryFindAvatar(UUID person, out Simulator sim, out Vector3 position)
335 return TryFindPrim(person, out sim, out position, true);
337 public bool TryFindPrim(UUID person, out Simulator sim, out Vector3 position, bool onlyAvatars)
339 Simulator[] Simulators = null;
340 lock (client.Network.Simulators)
342 Simulators = client.Network.Simulators.ToArray();
345 position = Vector3.Zero;
347 Primitive avi = null;
349 // First try the object tracker
350 foreach (var s in Simulators)
352 avi = s.ObjectsAvatars.Find((Avatar av) => { return av.ID == person; });
359 if (avi == null && !onlyAvatars)
361 foreach (var s in Simulators)
363 avi = s.ObjectsPrimitives.Find((Primitive av) => { return av.ID == person; });
373 if (avi.ParentID == 0)
375 position = avi.Position;
380 if (sim.ObjectsPrimitives.TryGetValue(avi.ParentID, out seat))
382 position = seat.Position + avi.Position * seat.Rotation;
388 foreach (var s in Simulators)
390 if (s.AvatarPositions.ContainsKey(person))
392 position = s.AvatarPositions[person];
399 if (position.Z > 0.1f)
405 public bool TryLocatePrim(Primitive avi, out Simulator sim, out Vector3 position)
407 Simulator[] Simulators = null;
408 lock (client.Network.Simulators)
410 Simulators = client.Network.Simulators.ToArray();
413 sim = client.Network.CurrentSim;
414 position = Vector3.Zero;
416 foreach (var s in Simulators)
418 if (s.Handle == avi.RegionHandle)
427 if (avi.ParentID == 0)
429 position = avi.Position;
434 if (sim.ObjectsPrimitives.TryGetValue(avi.ParentID, out seat))
436 position = seat.Position + avi.Position*seat.Rotation;
440 if (position.Z > 0.1f)
447 /// Move to target position either by walking or by teleporting
449 /// <param name="target">Sim local position of the target</param>
450 /// <param name="useTP">Move using teleport</param>
451 public void MoveTo(Vector3 target, bool useTP)
453 MoveTo(client.Network.CurrentSim, target, useTP);
457 /// Move to target position either by walking or by teleporting
459 /// <param name="sim">Simulator in which the target is</param>
460 /// <param name="target">Sim local position of the target</param>
461 /// <param name="useTP">Move using teleport</param>
462 public void MoveTo(Simulator sim, Vector3 target, bool useTP)
464 SetSitting(false, UUID.Zero);
468 client.Self.RequestTeleport(sim.Handle, target);
472 displayEndWalk = true;
473 client.Self.Movement.TurnToward(target);
474 WalkTo(GlobalPosition(sim, target));
479 public void SetRandomHeading()
481 client.Self.Movement.UpdateFromHeading(Utils.TWO_PI * rnd.NextDouble(), true);
485 void Network_EventQueueRunning(object sender, EventQueueRunningEventArgs e)
487 if (e.Simulator == client.Network.CurrentSim)
493 void Network_SimChanged(object sender, SimChangedEventArgs e)
495 WorkPool.QueueUserWorkItem(sync =>
497 Thread.Sleep(15 * 1000);
499 pseudohome.ETGoHome();
501 client.Self.Movement.SetFOVVerticalAngle(FOVVerticalAngle);
504 private UUID teleportEffect = UUID.Random();
506 void Self_TeleportProgress(object sender, TeleportEventArgs e)
508 if (!client.Network.Connected) return;
510 if (e.Status == TeleportStatus.Progress)
512 client.Self.SphereEffect(client.Self.GlobalPosition, Color4.White, 4f, teleportEffect);
515 if (e.Status == TeleportStatus.Finished)
517 client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0f, teleportEffect);
521 if (e.Status == TeleportStatus.Failed)
523 client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0f, teleportEffect);
527 void netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)
529 typing = away = busy = walking = false;
531 if (lookAtTimer != null)
533 lookAtTimer.Dispose();
539 void netcom_ClientConnected(object sender, EventArgs e)
541 if (!instance.GlobalSettings.ContainsKey("draw_distance"))
543 instance.GlobalSettings["draw_distance"] = 48;
546 client.Self.Movement.Camera.Far = instance.GlobalSettings["draw_distance"];
548 if (lookAtTimer == null)
550 lookAtTimer = new System.Threading.Timer(new TimerCallback(lookAtTimerTick), null, Timeout.Infinite, Timeout.Infinite);
554 void Objects_AvatarUpdate(object sender, AvatarUpdateEventArgs e)
556 if (e.Avatar.LocalID == client.Self.LocalID)
562 void Objects_TerseObjectUpdate(object sender, TerseObjectUpdateEventArgs e)
564 if (!e.Update.Avatar) return;
566 if (e.Prim.LocalID == client.Self.LocalID)
571 if (!following) return;
574 client.Network.CurrentSim.ObjectsAvatars.TryGetValue(e.Update.LocalID, out av);
575 if (av == null) return;
577 if (av.ID == followID)
579 Vector3 pos = AvatarPosition(client.Network.CurrentSim, av);
585 void FollowUpdate(Vector3 pos)
587 if (Vector3.Distance(pos, client.Self.SimPosition) > followDistance)
589 Vector3 target = pos + Vector3.Normalize(client.Self.SimPosition - pos) * (followDistance - 1f);
590 client.Self.AutoPilotCancel();
591 Vector3d glb = GlobalPosition(client.Network.CurrentSim, target);
592 client.Self.AutoPilot(glb.X, glb.Y, glb.Z);
596 client.Self.AutoPilotCancel();
597 client.Self.Movement.TurnToward(pos);
601 public void SetDefaultCamera()
603 if (CameraTracksOwnAvatar)
605 if (client.Self.SittingOn != 0 && !client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(client.Self.SittingOn))
607 // We are sitting but don't have the information about the object we are sitting on
608 // Sim seems to ignore RequestMutlipleObjects message
609 // client.Objects.RequestObject(client.Network.CurrentSim, client.Self.SittingOn);
613 Vector3 pos = client.Self.SimPosition + DefaultCameraOffset * client.Self.Movement.BodyRotation;
614 Logger.Log("Setting camera position to " + pos.ToString(), Helpers.LogLevel.Debug);
615 client.Self.Movement.Camera.LookAt(
617 client.Self.SimPosition
623 public Quaternion AvatarRotation(Simulator sim, UUID avID)
625 Quaternion rot = Quaternion.Identity;
626 Avatar av = sim.ObjectsAvatars.Find((Avatar a) => { return a.ID == avID; });
631 if (av.ParentID == 0)
638 if (sim.ObjectsPrimitives.TryGetValue(av.ParentID, out prim))
640 rot = prim.Rotation + av.Rotation;
648 public Vector3 AvatarPosition(Simulator sim, UUID avID)
650 Vector3 pos = Vector3.Zero;
651 Avatar av = sim.ObjectsAvatars.Find((Avatar a) => { return a.ID == avID; });
654 return AvatarPosition(sim, av);
659 if (sim.AvatarPositions.TryGetValue(avID, out coarse))
668 public Vector3 AvatarPosition(Simulator sim, Avatar av)
670 Vector3 pos = Vector3.Zero;
672 if (av.ParentID == 0)
679 if (sim.ObjectsPrimitives.TryGetValue(av.ParentID, out prim))
681 pos = prim.Position + av.Position;
688 public void Follow(string name, UUID id)
692 following = followID != UUID.Zero;
698 Vector3 target = AvatarPosition(client.Network.CurrentSim, id);
699 if (Vector3.Zero != target)
701 client.Self.Movement.TurnToward(target);
702 FollowUpdate(target);
708 public void StopFollowing()
711 followName = string.Empty;
712 followID = UUID.Zero;
715 #region Look at effect
716 private int lastLookAtEffect = 0;
717 private UUID lookAtEffect = UUID.Random();
720 /// Set eye focus 3m in front of us
722 public void LookInFront()
724 if (!client.Network.Connected || instance.GlobalSettings["disable_look_at"]) return;
726 client.Self.LookAtEffect(client.Self.AgentID, client.Self.AgentID,
727 new Vector3d(new Vector3(3, 0, 0) * Quaternion.Identity),
728 LookAtType.Idle, lookAtEffect);
731 void lookAtTimerTick(object state)
736 void netcom_ChatReceived(object sender, ChatEventArgs e)
738 //somehow it can be too early (when Radegast is loaded from running bot)
739 if (instance.GlobalSettings==null) return;
740 if (!instance.GlobalSettings["disable_look_at"]
741 && e.SourceID != client.Self.AgentID
742 && (e.SourceType == ChatSourceType.Agent || e.Type == ChatType.StartTyping))
744 // change focus max every 4 seconds
745 if (Environment.TickCount - lastLookAtEffect > 4000)
747 lastLookAtEffect = Environment.TickCount;
748 client.Self.LookAtEffect(client.Self.AgentID, e.SourceID, Vector3d.Zero, LookAtType.Respond, lookAtEffect);
749 // keep looking at the speaker for 10 seconds
750 if (lookAtTimer != null)
752 lookAtTimer.Change(10000, Timeout.Infinite);
757 #endregion Look at effect
759 #region Walking (move to)
760 private bool walking = false;
761 private System.Threading.Timer walkTimer;
762 private int walkChekInterval = 500;
763 private Vector3d walkToTarget;
764 int lastDistance = 0;
765 int lastDistanceChanged = 0;
767 public void WalkTo(Primitive prim)
769 WalkTo(GlobalPosition(prim));
771 public double WaitUntilPosition(Vector3d pos, TimeSpan maxWait, double howClose)
774 DateTime until = DateTime.Now + maxWait;
775 while (until > DateTime.Now)
777 double dist = Vector3d.Distance(client.Self.GlobalPosition, pos);
778 if (howClose >= dist) return dist;
781 return Vector3d.Distance(client.Self.GlobalPosition, pos);
785 public void WalkTo(Vector3d globalPos)
787 walkToTarget = globalPos;
792 followName = string.Empty;
795 if (walkTimer == null)
797 walkTimer = new System.Threading.Timer(new TimerCallback(walkTimerElapsed), null, walkChekInterval, Timeout.Infinite);
800 lastDistanceChanged = System.Environment.TickCount;
801 client.Self.AutoPilotCancel();
803 client.Self.AutoPilot(walkToTarget.X, walkToTarget.Y, walkToTarget.Z);
804 FireWalkStateCanged();
807 void walkTimerElapsed(object sender)
810 double distance = Vector3d.Distance(client.Self.GlobalPosition, walkToTarget);
819 if (lastDistance != (int)distance)
821 lastDistanceChanged = System.Environment.TickCount;
822 lastDistance = (int)distance;
824 else if ((System.Environment.TickCount - lastDistanceChanged) > 10000)
826 // Our distance to the target has not changed in 10s, give up
830 if (walkTimer != null) walkTimer.Change(walkChekInterval, Timeout.Infinite);
834 void Self_AlertMessage(object sender, AlertMessageEventArgs e)
836 if (e.Message.Contains("Autopilot cancel"))
845 void FireWalkStateCanged()
847 if (OnWalkStateCanged != null)
849 try { OnWalkStateCanged(walking); }
850 catch (Exception) { }
854 public void EndWalking()
859 Logger.Log("Finished walking.", Helpers.LogLevel.Debug, client);
862 client.Self.AutoPilotCancel();
866 displayEndWalk = false;
867 string msg = "Finished walking";
869 if (walkToTarget != Vector3d.Zero)
871 System.Threading.Thread.Sleep(1000);
872 msg += string.Format(" {0:0} meters from destination", Vector3d.Distance(client.Self.GlobalPosition, walkToTarget));
873 walkToTarget = Vector3d.Zero;
876 instance.TabConsole.DisplayNotificationInChat(msg);
879 FireWalkStateCanged();
884 public void SetTyping(bool typing)
886 if (!client.Network.Connected) return;
888 Dictionary<UUID, bool> typingAnim = new Dictionary<UUID, bool>();
889 typingAnim.Add(typingAnimationID, typing);
891 client.Self.Animate(typingAnim, false);
894 client.Self.Chat(string.Empty, 0, ChatType.StartTyping);
896 client.Self.Chat(string.Empty, 0, ChatType.StopTyping);
898 this.typing = typing;
901 public void SetAway(bool away)
903 Dictionary<UUID, bool> awayAnim = new Dictionary<UUID, bool>();
904 awayAnim.Add(awayAnimationID, away);
906 client.Self.Animate(awayAnim, true);
907 if (UseMoveControl) client.Self.Movement.Away = away;
911 public void SetBusy(bool busy)
913 Dictionary<UUID, bool> busyAnim = new Dictionary<UUID, bool>();
914 busyAnim.Add(busyAnimationID, busy);
916 client.Self.Animate(busyAnim, true);
920 public void SetFlying(bool flying)
922 this.flying = client.Self.Movement.Fly = flying;
925 public void SetAlwaysRun(bool alwaysrun)
927 this.alwaysrun = client.Self.Movement.AlwaysRun = alwaysrun;
930 public void SetSitting(bool sitting, UUID target)
932 this.sitting = sitting;
936 client.Self.RequestSit(target, Vector3.Zero);
941 if (!instance.RLV.RestictionActive("unsit"))
947 instance.TabConsole.DisplayNotificationInChat("Unsit prevented by RLV");
953 if (SitStateChanged != null)
955 SitStateChanged(this, new SitEventArgs(this.sitting));
964 public void StopAllAnimations()
966 Dictionary<UUID, bool> stop = new Dictionary<UUID, bool>();
968 client.Self.SignaledAnimations.ForEach((UUID anim) =>
970 if (!KnownAnimations.ContainsKey(anim))
972 stop.Add(anim, false);
978 client.Self.Animate(stop, true);
982 static public Vector3d GlobalPosition(Simulator sim, Vector3 pos)
984 uint globalX, globalY;
985 Utils.LongToUInts(sim.Handle, out globalX, out globalY);
988 (double)globalX + (double)pos.X,
989 (double)globalY + (double)pos.Y,
993 public Vector3d GlobalPosition(Primitive prim)
995 return GlobalPosition(client.Network.CurrentSim, prim.Position);
998 private System.Timers.Timer beamTimer;
999 private List<Vector3d> beamTarget;
1000 private Random beamRandom = new Random();
1001 private UUID pointID;
1002 private UUID sphereID;
1003 private List<UUID> beamID;
1004 private int numBeans;
1005 private Color4[] beamColors = new Color4[3] { new Color4(0, 255, 0, 255), new Color4(255, 0, 0, 255), new Color4(0, 0, 255, 255) };
1006 private Primitive targetPrim;
1008 public void UnSetPointing()
1010 beamTimer.Enabled = false;
1011 if (pointID != UUID.Zero)
1013 client.Self.PointAtEffect(client.Self.AgentID, UUID.Zero, Vector3d.Zero, PointAtType.None, pointID);
1014 pointID = UUID.Zero;
1019 foreach (UUID id in beamID)
1021 client.Self.BeamEffect(UUID.Zero, UUID.Zero, Vector3d.Zero, new Color4(255, 255, 255, 255), 0, id);
1026 if (sphereID != UUID.Zero)
1028 client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0, sphereID);
1029 sphereID = UUID.Zero;
1034 void beamTimer_Elapsed(object sender, EventArgs e)
1036 if (beamID == null) return;
1040 client.Self.SphereEffect(GlobalPosition(targetPrim), beamColors[beamRandom.Next(0, 3)], 0.85f, sphereID);
1042 for (i = 0; i < numBeans; i++)
1044 UUID newBeam = UUID.Random();
1049 scatter = GlobalPosition(targetPrim);
1053 Vector3d direction = client.Self.GlobalPosition - GlobalPosition(targetPrim);
1054 Vector3d cross = direction % new Vector3d(0, 0, 1);
1056 scatter = GlobalPosition(targetPrim) + cross * (i * 0.2d) * (i % 2 == 0 ? 1 : -1);
1058 client.Self.BeamEffect(client.Self.AgentID, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[i]);
1061 for (int j = 1; j < numBeans; j++)
1063 UUID newBeam = UUID.Random();
1065 Vector3d cross = new Vector3d(0, 0, 1);
1067 scatter = GlobalPosition(targetPrim) + cross * (j * 0.2d) * (j % 2 == 0 ? 1 : -1);
1069 client.Self.BeamEffect(client.Self.AgentID, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[j + i - 1]);
1072 catch (Exception) { };
1076 public void SetPointing(Primitive prim, int numBeans)
1079 client.Self.Movement.TurnToward(prim.Position);
1080 pointID = UUID.Random();
1081 sphereID = UUID.Random();
1082 beamID = new List<UUID>();
1083 beamTarget = new List<Vector3d>();
1085 this.numBeans = numBeans;
1087 client.Self.PointAtEffect(client.Self.AgentID, prim.ID, Vector3d.Zero, PointAtType.Select, pointID);
1089 for (int i = 0; i < numBeans; i++)
1091 UUID newBeam = UUID.Random();
1092 beamID.Add(newBeam);
1093 beamTarget.Add(Vector3d.Zero);
1096 for (int i = 1; i < numBeans; i++)
1098 UUID newBeam = UUID.Random();
1099 beamID.Add(newBeam);
1100 beamTarget.Add(Vector3d.Zero);
1103 beamTimer.Interval = 1000;
1104 beamTimer.Enabled = true;
1107 public UUID TypingAnimationID
1109 get { return typingAnimationID; }
1110 set { typingAnimationID = value; }
1113 public UUID AwayAnimationID
1115 get { return awayAnimationID; }
1116 set { awayAnimationID = value; }
1119 public UUID BusyAnimationID
1121 get { return busyAnimationID; }
1122 set { busyAnimationID = value; }
1125 public bool IsTyping
1127 get { return typing; }
1134 if (UseMoveControl) return client.Self.Movement.Away;
1141 get { return busy; }
1144 public bool IsFlying
1146 get { return client.Self.Movement.Fly; }
1149 public bool IsSitting
1153 if (client.Self.Movement.SitOnGround || client.Self.SittingOn != 0) return true;
1155 Logger.Log("out of sync sitting", Helpers.LogLevel.Debug);
1162 public bool IsPointing
1164 get { return pointID != UUID.Zero; }
1167 public bool IsFollowing
1169 get { return following; }
1172 public string FollowName
1174 get { return followName; }
1175 set { followName = value; }
1178 public float FollowDistance
1180 get { return followDistance; }
1181 set { followDistance = value; }
1184 public bool IsWalking
1186 get { return walking; }
1189 private AutoSit autosit;
1190 public AutoSit AutoSit
1192 get { return autosit; }
1195 private LSLHelper lslHelper;
1196 public LSLHelper LSLHelper
1198 get { return lslHelper; }
1201 private PseudoHome pseudohome;
1204 /// Experimental Option that sometimes the Client has more authority than state mananger
1206 public static bool UseMoveControl;
1208 public PseudoHome PseudoHome
1210 get { return pseudohome; }
1214 public class SitEventArgs : EventArgs
1216 public bool Sitting;
1218 public SitEventArgs(bool sitting)
1220 this.Sitting = sitting;