2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2012, 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;
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; }
48 public KnownHeading(string id, string name, Quaternion heading)
52 this.Heading = heading;
55 public override string ToString()
61 public class StateManager : IDisposable
63 public Parcel Parcel { get; set; }
65 private RadegastInstance instance;
66 private GridClient client { get { return instance.Client; } }
67 private RadegastNetcom netcom { get { return instance.Netcom; } }
69 private bool typing = false;
70 private bool away = false;
71 private bool busy = false;
72 private bool flying = false;
73 private bool alwaysrun = false;
74 private bool sitting = false;
76 private bool following = false;
77 private string followName = string.Empty;
78 private float followDistance = 3.0f;
79 private UUID followID;
80 private bool displayEndWalk = false;
82 private UUID awayAnimationID = new UUID("fd037134-85d4-f241-72c6-4f42164fedee");
83 private UUID busyAnimationID = new UUID("efcf670c2d188128973a034ebc806b67");
84 private UUID typingAnimationID = new UUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
85 internal static Random rnd = new Random();
86 private System.Threading.Timer lookAtTimer;
91 /// <param name="walking">True if we are walking towards a targer</param>
92 public delegate void WalkStateCanged(bool walking);
95 /// Fires when we start or stop walking towards a target
97 public event WalkStateCanged OnWalkStateCanged;
100 /// Fires when avatar stands
102 public event EventHandler<SitEventArgs> SitStateChanged;
104 static List<KnownHeading> m_Headings;
105 public static List<KnownHeading> KnownHeadings
109 if (m_Headings == null)
111 m_Headings = new List<KnownHeading>(16);
112 m_Headings.Add(new KnownHeading("E", "East", new Quaternion(0.00000f, 0.00000f, 0.00000f, 1.00000f)));
113 m_Headings.Add(new KnownHeading("ENE", "East by Northeast", new Quaternion(0.00000f, 0.00000f, 0.19509f, 0.98079f)));
114 m_Headings.Add(new KnownHeading("NE", "Northeast", new Quaternion(0.00000f, 0.00000f, 0.38268f, 0.92388f)));
115 m_Headings.Add(new KnownHeading("NNE", "North by Northeast", new Quaternion(0.00000f, 0.00000f, 0.55557f, 0.83147f)));
116 m_Headings.Add(new KnownHeading("N", "North", new Quaternion(0.00000f, 0.00000f, 0.70711f, 0.70711f)));
117 m_Headings.Add(new KnownHeading("NNW", "North by Northwest", new Quaternion(0.00000f, 0.00000f, 0.83147f, 0.55557f)));
118 m_Headings.Add(new KnownHeading("NW", "Nortwest", new Quaternion(0.00000f, 0.00000f, 0.92388f, 0.38268f)));
119 m_Headings.Add(new KnownHeading("WNW", "West by Northwest", new Quaternion(0.00000f, 0.00000f, 0.98079f, 0.19509f)));
120 m_Headings.Add(new KnownHeading("W", "West", new Quaternion(0.00000f, 0.00000f, 1.00000f, -0.00000f)));
121 m_Headings.Add(new KnownHeading("WSW", "West by Southwest", new Quaternion(0.00000f, 0.00000f, 0.98078f, -0.19509f)));
122 m_Headings.Add(new KnownHeading("SW", "Southwest", new Quaternion(0.00000f, 0.00000f, 0.92388f, -0.38268f)));
123 m_Headings.Add(new KnownHeading("SSW", "South by Southwest", new Quaternion(0.00000f, 0.00000f, 0.83147f, -0.55557f)));
124 m_Headings.Add(new KnownHeading("S", "South", new Quaternion(0.00000f, 0.00000f, 0.70711f, -0.70711f)));
125 m_Headings.Add(new KnownHeading("SSE", "South by Southeast", new Quaternion(0.00000f, 0.00000f, 0.55557f, -0.83147f)));
126 m_Headings.Add(new KnownHeading("SE", "Southeast", new Quaternion(0.00000f, 0.00000f, 0.38268f, -0.92388f)));
127 m_Headings.Add(new KnownHeading("ESE", "East by Southeast", new Quaternion(0.00000f, 0.00000f, 0.19509f, -0.98078f)));
133 public static Vector3 RotToEuler(Quaternion r)
135 Quaternion t = new Quaternion(r.X * r.X, r.Y * r.Y, r.Z * r.Z, r.W * r.W);
137 float m = (t.X + t.Y + t.Z + t.W);
138 if (Math.Abs(m) < 0.001) return Vector3.Zero;
139 float n = 2 * (r.Y * r.W + r.X * r.Z);
140 float p = m * m - n * n;
144 (float)Math.Atan2(2.0 * (r.X * r.W - r.Y * r.Z), (-t.X - t.Y + t.Z + t.W)),
145 (float)Math.Atan2(n, Math.Sqrt(p)),
146 (float)Math.Atan2(2.0 * (r.Z * r.W - r.X * r.Y), t.X - t.Y - t.Z + t.W)
151 (float)(Math.PI / 2d),
152 (float)Math.Atan2((r.Z * r.W + r.X * r.Y), 0.5 - t.X - t.Y)
157 -(float)(Math.PI / 2d),
158 (float)Math.Atan2((r.Z * r.W + r.X * r.Y), 0.5 - t.X - t.Z)
162 public static KnownHeading ClosestKnownHeading(int degrees)
164 KnownHeading ret = KnownHeadings[0];
165 int facing = (int)(57.2957795d * RotToEuler(KnownHeadings[0].Heading).Z);
166 if (facing < 0) facing += 360;
167 int minDistance = Math.Abs(degrees - facing);
169 for (int i = 1; i < KnownHeadings.Count; i++)
171 facing = (int)(57.2957795d * RotToEuler(KnownHeadings[i].Heading).Z);
172 if (facing < 0) facing += 360;
174 int distance = Math.Abs(degrees - facing);
175 if (distance < minDistance)
177 ret = KnownHeadings[i];
178 minDistance = distance;
185 public Dictionary<UUID, string> KnownAnimations;
187 public StateManager(RadegastInstance instance)
189 this.instance = instance;
190 this.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
191 KnownAnimations = Animations.ToDictionary();
192 autosit = new AutoSit(this.instance);
193 pseudohome = new PseudoHome(this.instance);
195 beamTimer = new System.Timers.Timer();
196 beamTimer.Enabled = false;
197 beamTimer.Elapsed += new ElapsedEventHandler(beamTimer_Elapsed);
200 netcom.ClientConnected += new EventHandler<EventArgs>(netcom_ClientConnected);
201 netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
202 netcom.ChatReceived += new EventHandler<ChatEventArgs>(netcom_ChatReceived);
203 RegisterClientEvents(client);
207 private void RegisterClientEvents(GridClient client)
209 client.Objects.TerseObjectUpdate += new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);
210 client.Objects.AvatarSitChanged += new EventHandler<AvatarSitChangedEventArgs>(Objects_AvatarSitChanged);
211 client.Self.AlertMessage += new EventHandler<AlertMessageEventArgs>(Self_AlertMessage);
212 client.Self.TeleportProgress += new EventHandler<TeleportEventArgs>(Self_TeleportProgress);
213 client.Network.EventQueueRunning += new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
214 client.Network.SimChanged += new EventHandler<SimChangedEventArgs>(Network_SimChanged);
217 private void UnregisterClientEvents(GridClient client)
219 client.Objects.TerseObjectUpdate -= new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);
220 client.Objects.AvatarSitChanged -= new EventHandler<AvatarSitChangedEventArgs>(Objects_AvatarSitChanged);
221 client.Self.AlertMessage -= new EventHandler<AlertMessageEventArgs>(Self_AlertMessage);
222 client.Self.TeleportProgress -= new EventHandler<TeleportEventArgs>(Self_TeleportProgress);
223 client.Network.EventQueueRunning -= new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
224 client.Network.SimChanged -= new EventHandler<SimChangedEventArgs>(Network_SimChanged);
227 public void Dispose()
229 netcom.ClientConnected -= new EventHandler<EventArgs>(netcom_ClientConnected);
230 netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
231 netcom.ChatReceived -= new EventHandler<ChatEventArgs>(netcom_ChatReceived);
232 UnregisterClientEvents(client);
236 if (lookAtTimer != null)
238 lookAtTimer.Dispose();
242 if (walkTimer != null)
249 void instance_ClientChanged(object sender, ClientChangedEventArgs e)
251 UnregisterClientEvents(e.OldClient);
252 RegisterClientEvents(client);
255 void Objects_AvatarSitChanged(object sender, AvatarSitChangedEventArgs e)
257 if (e.Avatar.LocalID != client.Self.LocalID) return;
259 this.sitting = e.SittingOn != 0;
260 if (SitStateChanged != null)
262 SitStateChanged(this, new SitEventArgs(this.sitting));
267 /// Locates avatar in the current sim, or adjacents sims
269 /// <param name="person">Avatar UUID</param>
270 /// <param name="position">Position within sim</param>
271 /// <returns>True if managed to find the avatar</returns>
272 public bool TryFindAvatar(UUID person, out Vector3 position)
275 if (!TryFindAvatar(person, out sim, out position)) return false;
277 if (sim == client.Network.CurrentSim) return true;
278 position = ToLocalPosition(sim.Handle, position);
282 public Vector3 ToLocalPosition(ulong handle, Vector3 position)
284 Vector3d diff = ToVector3D(handle, position) - client.Self.GlobalPosition;
285 position = new Vector3((float) diff.X, (float) diff.Y, (float) diff.Z) - position;
289 public static Vector3d ToVector3D(ulong handle, Vector3 pos)
291 uint globalX, globalY;
292 Utils.LongToUInts(handle, out globalX, out globalY);
295 (double)globalX + (double)pos.X,
296 (double)globalY + (double)pos.Y,
301 /// Locates avatar in the current sim, or adjacents sims
303 /// <param name="person">Avatar UUID</param>
304 /// <param name="sim">Simulator avatar is in</param>
305 /// <param name="position">Position within sim</param>
306 /// <returns>True if managed to find the avatar</returns>
307 public bool TryFindAvatar(UUID person, out Simulator sim, out Vector3 position)
309 return TryFindPrim(person, out sim, out position, true);
311 public bool TryFindPrim(UUID person, out Simulator sim, out Vector3 position, bool onlyAvatars)
313 Simulator[] Simulators = null;
314 lock (client.Network.Simulators)
316 Simulators = client.Network.Simulators.ToArray();
319 position = Vector3.Zero;
321 Primitive avi = null;
323 // First try the object tracker
324 foreach (var s in Simulators)
326 avi = s.ObjectsAvatars.Find((Avatar av) => { return av.ID == person; });
333 if (avi == null && !onlyAvatars)
335 foreach (var s in Simulators)
337 avi = s.ObjectsPrimitives.Find((Primitive av) => { return av.ID == person; });
347 if (avi.ParentID == 0)
349 position = avi.Position;
354 if (sim.ObjectsPrimitives.TryGetValue(avi.ParentID, out seat))
356 position = seat.Position + avi.Position * seat.Rotation;
362 foreach (var s in Simulators)
364 if (s.AvatarPositions.ContainsKey(person))
366 position = s.AvatarPositions[person];
373 if (position.Z > 0.1f)
379 public bool TryLocatePrim(Primitive avi, out Simulator sim, out Vector3 position)
381 Simulator[] Simulators = null;
382 lock (client.Network.Simulators)
384 Simulators = client.Network.Simulators.ToArray();
387 sim = client.Network.CurrentSim;
388 position = Vector3.Zero;
390 foreach (var s in Simulators)
392 if (s.Handle == avi.RegionHandle)
401 if (avi.ParentID == 0)
403 position = avi.Position;
408 if (sim.ObjectsPrimitives.TryGetValue(avi.ParentID, out seat))
410 position = seat.Position + avi.Position*seat.Rotation;
414 if (position.Z > 0.1f)
421 /// Move to target position either by walking or by teleporting
423 /// <param name="target">Sim local position of the target</param>
424 /// <param name="useTP">Move using teleport</param>
425 public void MoveTo(Vector3 target, bool useTP)
427 MoveTo(client.Network.CurrentSim, target, useTP);
431 /// Move to target position either by walking or by teleporting
433 /// <param name="sim">Simulator in which the target is</param>
434 /// <param name="target">Sim local position of the target</param>
435 /// <param name="useTP">Move using teleport</param>
436 public void MoveTo(Simulator sim, Vector3 target, bool useTP)
438 SetSitting(false, UUID.Zero);
442 client.Self.RequestTeleport(sim.Handle, target);
446 displayEndWalk = true;
447 client.Self.Movement.TurnToward(target);
448 WalkTo(GlobalPosition(sim, target));
453 public void SetRandomHeading()
455 client.Self.Movement.UpdateFromHeading(Utils.TWO_PI * rnd.NextDouble(), true);
459 void Network_EventQueueRunning(object sender, EventQueueRunningEventArgs e)
461 if (e.Simulator == client.Network.CurrentSim)
467 void Network_SimChanged(object sender, SimChangedEventArgs e)
470 pseudohome.ETGoHome();
473 private UUID teleportEffect = UUID.Random();
475 void Self_TeleportProgress(object sender, TeleportEventArgs e)
477 if (!client.Network.Connected) return;
479 if (e.Status == TeleportStatus.Progress)
481 client.Self.SphereEffect(client.Self.GlobalPosition, Color4.White, 4f, teleportEffect);
484 if (e.Status == TeleportStatus.Finished)
486 client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0f, teleportEffect);
490 if (e.Status == TeleportStatus.Failed)
492 client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0f, teleportEffect);
496 void netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)
498 typing = away = busy = walking = false;
500 if (lookAtTimer != null)
502 lookAtTimer.Dispose();
508 void netcom_ClientConnected(object sender, EventArgs e)
510 if (!instance.GlobalSettings.ContainsKey("draw_distance"))
512 instance.GlobalSettings["draw_distance"] = 48;
515 client.Self.Movement.Camera.Far = instance.GlobalSettings["draw_distance"];
517 if (lookAtTimer == null)
519 lookAtTimer = new System.Threading.Timer(new TimerCallback(lookAtTimerTick), null, Timeout.Infinite, Timeout.Infinite);
523 void Objects_TerseObjectUpdate(object sender, TerseObjectUpdateEventArgs e)
525 if (!e.Update.Avatar) return;
526 if (!following) return;
529 client.Network.CurrentSim.ObjectsAvatars.TryGetValue(e.Update.LocalID, out av);
530 if (av == null) return;
532 if (av.ID == followID)
534 Vector3 pos = AvatarPosition(client.Network.CurrentSim, av);
540 void FollowUpdate(Vector3 pos)
542 if (Vector3.Distance(pos, client.Self.SimPosition) > followDistance)
544 Vector3 target = pos + Vector3.Normalize(client.Self.SimPosition - pos) * (followDistance - 1f);
545 client.Self.AutoPilotCancel();
546 Vector3d glb = GlobalPosition(client.Network.CurrentSim, target);
547 client.Self.AutoPilot(glb.X, glb.Y, glb.Z);
551 client.Self.AutoPilotCancel();
552 client.Self.Movement.TurnToward(pos);
556 public Quaternion AvatarRotation(Simulator sim, UUID avID)
558 Quaternion rot = Quaternion.Identity;
559 Avatar av = sim.ObjectsAvatars.Find((Avatar a) => { return a.ID == avID; });
564 if (av.ParentID == 0)
571 if (sim.ObjectsPrimitives.TryGetValue(av.ParentID, out prim))
573 rot = prim.Rotation + av.Rotation;
581 public Vector3 AvatarPosition(Simulator sim, UUID avID)
583 Vector3 pos = Vector3.Zero;
584 Avatar av = sim.ObjectsAvatars.Find((Avatar a) => { return a.ID == avID; });
587 return AvatarPosition(sim, av);
592 if (sim.AvatarPositions.TryGetValue(avID, out coarse))
601 public Vector3 AvatarPosition(Simulator sim, Avatar av)
603 Vector3 pos = Vector3.Zero;
605 if (av.ParentID == 0)
612 if (sim.ObjectsPrimitives.TryGetValue(av.ParentID, out prim))
614 pos = prim.Position + av.Position;
621 public void Follow(string name, UUID id)
625 following = followID != UUID.Zero;
631 Vector3 target = AvatarPosition(client.Network.CurrentSim, id);
632 if (Vector3.Zero != target)
634 client.Self.Movement.TurnToward(target);
635 FollowUpdate(target);
641 public void StopFollowing()
644 followName = string.Empty;
645 followID = UUID.Zero;
648 #region Look at effect
649 private int lastLookAtEffect = 0;
650 private UUID lookAtEffect = UUID.Random();
653 /// Set eye focus 3m in front of us
655 public void LookInFront()
657 if (!client.Network.Connected || instance.GlobalSettings["disable_look_at"]) return;
659 client.Self.LookAtEffect(client.Self.AgentID, client.Self.AgentID,
660 new Vector3d(new Vector3(3, 0, 0) * Quaternion.Identity),
661 LookAtType.Idle, lookAtEffect);
664 void lookAtTimerTick(object state)
669 void netcom_ChatReceived(object sender, ChatEventArgs e)
671 //somehow it can be too early (when Radegast is loaded from running bot)
672 if (instance.GlobalSettings==null) return;
673 if (!instance.GlobalSettings["disable_look_at"]
674 && e.SourceID != client.Self.AgentID
675 && (e.SourceType == ChatSourceType.Agent || e.Type == ChatType.StartTyping))
677 // change focus max every 4 seconds
678 if (Environment.TickCount - lastLookAtEffect > 4000)
680 lastLookAtEffect = Environment.TickCount;
681 client.Self.LookAtEffect(client.Self.AgentID, e.SourceID, Vector3d.Zero, LookAtType.Respond, lookAtEffect);
682 // keep looking at the speaker for 10 seconds
683 if (lookAtTimer != null)
685 lookAtTimer.Change(10000, Timeout.Infinite);
690 #endregion Look at effect
692 #region Walking (move to)
693 private bool walking = false;
694 private System.Threading.Timer walkTimer;
695 private int walkChekInterval = 500;
696 private Vector3d walkToTarget;
697 int lastDistance = 0;
698 int lastDistanceChanged = 0;
700 public void WalkTo(Primitive prim)
702 WalkTo(GlobalPosition(prim));
704 public double WaitUntilPosition(Vector3d pos, TimeSpan maxWait, double howClose)
707 DateTime until = DateTime.Now + maxWait;
708 while (until > DateTime.Now)
710 double dist = Vector3d.Distance(client.Self.GlobalPosition, pos);
711 if (howClose >= dist) return dist;
714 return Vector3d.Distance(client.Self.GlobalPosition, pos);
718 public void WalkTo(Vector3d globalPos)
720 walkToTarget = globalPos;
725 followName = string.Empty;
728 if (walkTimer == null)
730 walkTimer = new System.Threading.Timer(new TimerCallback(walkTimerElapsed), null, walkChekInterval, Timeout.Infinite);
733 lastDistanceChanged = System.Environment.TickCount;
734 client.Self.AutoPilotCancel();
736 client.Self.AutoPilot(walkToTarget.X, walkToTarget.Y, walkToTarget.Z);
737 FireWalkStateCanged();
740 void walkTimerElapsed(object sender)
743 double distance = Vector3d.Distance(client.Self.GlobalPosition, walkToTarget);
752 if (lastDistance != (int)distance)
754 lastDistanceChanged = System.Environment.TickCount;
755 lastDistance = (int)distance;
757 else if ((System.Environment.TickCount - lastDistanceChanged) > 10000)
759 // Our distance to the target has not changed in 10s, give up
763 if (walkTimer != null) walkTimer.Change(walkChekInterval, Timeout.Infinite);
767 void Self_AlertMessage(object sender, AlertMessageEventArgs e)
769 if (e.Message.Contains("Autopilot cancel"))
778 void FireWalkStateCanged()
780 if (OnWalkStateCanged != null)
782 try { OnWalkStateCanged(walking); }
783 catch (Exception) { }
787 public void EndWalking()
792 Logger.Log("Finished walking.", Helpers.LogLevel.Debug, client);
795 client.Self.AutoPilotCancel();
799 displayEndWalk = false;
800 string msg = "Finished walking";
802 if (walkToTarget != Vector3d.Zero)
804 System.Threading.Thread.Sleep(1000);
805 msg += string.Format(" {0:0} meters from destination", Vector3d.Distance(client.Self.GlobalPosition, walkToTarget));
806 walkToTarget = Vector3d.Zero;
809 instance.TabConsole.DisplayNotificationInChat(msg);
812 FireWalkStateCanged();
817 public void SetTyping(bool typing)
819 if (!client.Network.Connected) return;
821 Dictionary<UUID, bool> typingAnim = new Dictionary<UUID, bool>();
822 typingAnim.Add(typingAnimationID, typing);
824 client.Self.Animate(typingAnim, false);
827 client.Self.Chat(string.Empty, 0, ChatType.StartTyping);
829 client.Self.Chat(string.Empty, 0, ChatType.StopTyping);
831 this.typing = typing;
834 public void SetAway(bool away)
836 Dictionary<UUID, bool> awayAnim = new Dictionary<UUID, bool>();
837 awayAnim.Add(awayAnimationID, away);
839 client.Self.Animate(awayAnim, true);
840 if (UseMoveControl) client.Self.Movement.Away = away;
844 public void SetBusy(bool busy)
846 Dictionary<UUID, bool> busyAnim = new Dictionary<UUID, bool>();
847 busyAnim.Add(busyAnimationID, busy);
849 client.Self.Animate(busyAnim, true);
853 public void SetFlying(bool flying)
855 this.flying = client.Self.Movement.Fly = flying;
858 public void SetAlwaysRun(bool alwaysrun)
860 this.alwaysrun = client.Self.Movement.AlwaysRun = alwaysrun;
863 public void SetSitting(bool sitting, UUID target)
865 this.sitting = sitting;
869 client.Self.RequestSit(target, Vector3.Zero);
874 if (!instance.RLV.RestictionActive("unsit"))
880 instance.TabConsole.DisplayNotificationInChat("Unsit prevented by RLV");
886 if (SitStateChanged != null)
888 SitStateChanged(this, new SitEventArgs(this.sitting));
897 public void StopAllAnimations()
899 Dictionary<UUID, bool> stop = new Dictionary<UUID, bool>();
901 client.Self.SignaledAnimations.ForEach((UUID anim) =>
903 if (!KnownAnimations.ContainsKey(anim))
905 stop.Add(anim, false);
911 client.Self.Animate(stop, true);
915 static public Vector3d GlobalPosition(Simulator sim, Vector3 pos)
917 uint globalX, globalY;
918 Utils.LongToUInts(sim.Handle, out globalX, out globalY);
921 (double)globalX + (double)pos.X,
922 (double)globalY + (double)pos.Y,
926 public Vector3d GlobalPosition(Primitive prim)
928 return GlobalPosition(client.Network.CurrentSim, prim.Position);
931 private System.Timers.Timer beamTimer;
932 private List<Vector3d> beamTarget;
933 private Random beamRandom = new Random();
934 private UUID pointID;
935 private UUID sphereID;
936 private List<UUID> beamID;
937 private int numBeans;
938 private Color4[] beamColors = new Color4[3] { new Color4(0, 255, 0, 255), new Color4(255, 0, 0, 255), new Color4(0, 0, 255, 255) };
939 private Primitive targetPrim;
941 public void UnSetPointing()
943 beamTimer.Enabled = false;
944 if (pointID != UUID.Zero)
946 client.Self.PointAtEffect(client.Self.AgentID, UUID.Zero, Vector3d.Zero, PointAtType.None, pointID);
952 foreach (UUID id in beamID)
954 client.Self.BeamEffect(UUID.Zero, UUID.Zero, Vector3d.Zero, new Color4(255, 255, 255, 255), 0, id);
959 if (sphereID != UUID.Zero)
961 client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0, sphereID);
962 sphereID = UUID.Zero;
967 void beamTimer_Elapsed(object sender, EventArgs e)
969 if (beamID == null) return;
973 client.Self.SphereEffect(GlobalPosition(targetPrim), beamColors[beamRandom.Next(0, 3)], 0.85f, sphereID);
975 for (i = 0; i < numBeans; i++)
977 UUID newBeam = UUID.Random();
982 scatter = GlobalPosition(targetPrim);
986 Vector3d direction = client.Self.GlobalPosition - GlobalPosition(targetPrim);
987 Vector3d cross = direction % new Vector3d(0, 0, 1);
989 scatter = GlobalPosition(targetPrim) + cross * (i * 0.2d) * (i % 2 == 0 ? 1 : -1);
991 client.Self.BeamEffect(client.Self.AgentID, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[i]);
994 for (int j = 1; j < numBeans; j++)
996 UUID newBeam = UUID.Random();
998 Vector3d cross = new Vector3d(0, 0, 1);
1000 scatter = GlobalPosition(targetPrim) + cross * (j * 0.2d) * (j % 2 == 0 ? 1 : -1);
1002 client.Self.BeamEffect(client.Self.AgentID, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[j + i - 1]);
1005 catch (Exception) { };
1009 public void SetPointing(Primitive prim, int numBeans)
1012 client.Self.Movement.TurnToward(prim.Position);
1013 pointID = UUID.Random();
1014 sphereID = UUID.Random();
1015 beamID = new List<UUID>();
1016 beamTarget = new List<Vector3d>();
1018 this.numBeans = numBeans;
1020 client.Self.PointAtEffect(client.Self.AgentID, prim.ID, Vector3d.Zero, PointAtType.Select, pointID);
1022 for (int i = 0; i < numBeans; i++)
1024 UUID newBeam = UUID.Random();
1025 beamID.Add(newBeam);
1026 beamTarget.Add(Vector3d.Zero);
1029 for (int i = 1; i < numBeans; i++)
1031 UUID newBeam = UUID.Random();
1032 beamID.Add(newBeam);
1033 beamTarget.Add(Vector3d.Zero);
1036 beamTimer.Interval = 1000;
1037 beamTimer.Enabled = true;
1040 public UUID TypingAnimationID
1042 get { return typingAnimationID; }
1043 set { typingAnimationID = value; }
1046 public UUID AwayAnimationID
1048 get { return awayAnimationID; }
1049 set { awayAnimationID = value; }
1052 public UUID BusyAnimationID
1054 get { return busyAnimationID; }
1055 set { busyAnimationID = value; }
1058 public bool IsTyping
1060 get { return typing; }
1067 if (UseMoveControl) return client.Self.Movement.Away;
1074 get { return busy; }
1077 public bool IsFlying
1079 get { return client.Self.Movement.Fly; }
1082 public bool IsSitting
1086 if (client.Self.Movement.SitOnGround || client.Self.SittingOn != 0) return true;
1088 Logger.Log("out of sync sitting", Helpers.LogLevel.Debug);
1095 public bool IsPointing
1097 get { return pointID != UUID.Zero; }
1100 public bool IsFollowing
1102 get { return following; }
1105 public string FollowName
1107 get { return followName; }
1108 set { followName = value; }
1111 public float FollowDistance
1113 get { return followDistance; }
1114 set { followDistance = value; }
1117 public bool IsWalking
1119 get { return walking; }
1122 private AutoSit autosit;
1123 public AutoSit AutoSit
1125 get { return autosit; }
1128 private PseudoHome pseudohome;
1131 /// Experimental Option that sometimes the Client has more authority than state mananger
1133 public static bool UseMoveControl;
1135 public PseudoHome PseudoHome
1137 get { return pseudohome; }
1141 public class SitEventArgs : EventArgs
1143 public bool Sitting;
1145 public SitEventArgs(bool sitting)
1147 this.Sitting = sitting;