OSDN Git Service

Silence too verbose debug
[radegast/radegast.git] / Radegast / Core / StateManager.cs
index 8416c9e..4387a57 100644 (file)
@@ -1,6 +1,6 @@
 // 
 // Radegast Metaverse Client
-// Copyright (c) 2009, Radegast Development Team
+// Copyright (c) 2009-2014, Radegast Development Team
 // All rights reserved.
 // 
 // Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,10 @@ using System;
 using System.Collections.Generic;
 using System.Timers;
 using System.Threading;
+
 using OpenMetaverse;
+
+using Radegast.Automation;
 using Radegast.Netcom;
 
 namespace Radegast
@@ -42,16 +45,24 @@ namespace Radegast
         public string ID { get; set; }
         public string Name { get; set; }
         public Quaternion Heading { get; set; }
+
         public KnownHeading(string id, string name, Quaternion heading)
         {
             this.ID = id;
             this.Name = name;
             this.Heading = heading;
         }
+
+        public override string ToString()
+        {
+            return Name;
+        }
     }
 
     public class StateManager : IDisposable
     {
+        public Parcel Parcel { get; set; }
+
         private RadegastInstance instance;
         private GridClient client { get { return instance.Client; } }
         private RadegastNetcom netcom { get { return instance.Netcom; } }
@@ -66,6 +77,8 @@ namespace Radegast
         private bool following = false;
         private string followName = string.Empty;
         private float followDistance = 3.0f;
+        private UUID followID;
+        private bool displayEndWalk = false;
 
         private UUID awayAnimationID = new UUID("fd037134-85d4-f241-72c6-4f42164fedee");
         private UUID busyAnimationID = new UUID("efcf670c2d188128973a034ebc806b67");
@@ -73,6 +86,8 @@ namespace Radegast
         internal static Random rnd = new Random();
         private System.Threading.Timer lookAtTimer;
 
+        public float FOVVerticalAngle = Utils.TWO_PI - 0.05f;
+
         /// <summary>
         /// Passes walk state
         /// </summary>
@@ -84,8 +99,13 @@ namespace Radegast
         /// </summary>
         public event WalkStateCanged OnWalkStateCanged;
 
-        List<KnownHeading> m_Headings;
-        public List<KnownHeading> KnownHeadings
+        /// <summary>
+        /// Fires when avatar stands
+        /// </summary>
+        public event EventHandler<SitEventArgs> SitStateChanged;
+
+        static List<KnownHeading> m_Headings;
+        public static List<KnownHeading> KnownHeadings
         {
             get
             {
@@ -113,10 +133,70 @@ namespace Radegast
             }
         }
 
+        public static Vector3 RotToEuler(Quaternion r)
+        {
+            Quaternion t = new Quaternion(r.X * r.X, r.Y * r.Y, r.Z * r.Z, r.W * r.W);
+
+            float m = (t.X + t.Y + t.Z + t.W);
+            if (Math.Abs(m) < 0.001) return Vector3.Zero;
+            float n = 2 * (r.Y * r.W + r.X * r.Z);
+            float p = m * m - n * n;
+
+            if (p > 0)
+                return new Vector3(
+                    (float)Math.Atan2(2.0 * (r.X * r.W - r.Y * r.Z), (-t.X - t.Y + t.Z + t.W)),
+                    (float)Math.Atan2(n, Math.Sqrt(p)),
+                    (float)Math.Atan2(2.0 * (r.Z * r.W - r.X * r.Y), t.X - t.Y - t.Z + t.W)
+                    );
+            else if (n > 0)
+                return new Vector3(
+                    0f,
+                    (float)(Math.PI / 2d),
+                    (float)Math.Atan2((r.Z * r.W + r.X * r.Y), 0.5 - t.X - t.Y)
+                    );
+            else
+                return new Vector3(
+                    0f,
+                    -(float)(Math.PI / 2d),
+                    (float)Math.Atan2((r.Z * r.W + r.X * r.Y), 0.5 - t.X - t.Z)
+                    );
+        }
+
+        public static KnownHeading ClosestKnownHeading(int degrees)
+        {
+            KnownHeading ret = KnownHeadings[0];
+            int facing = (int)(57.2957795d * RotToEuler(KnownHeadings[0].Heading).Z);
+            if (facing < 0) facing += 360;
+            int minDistance = Math.Abs(degrees - facing);
+
+            for (int i = 1; i < KnownHeadings.Count; i++)
+            {
+                facing = (int)(57.2957795d * RotToEuler(KnownHeadings[i].Heading).Z);
+                if (facing < 0) facing += 360;
+
+                int distance = Math.Abs(degrees - facing);
+                if (distance < minDistance)
+                {
+                    ret = KnownHeadings[i];
+                    minDistance = distance;
+                }
+            }
+
+            return ret;
+        }
+
+        public Dictionary<UUID, string> KnownAnimations;
+        public bool CameraTracksOwnAvatar = true;
+        public Vector3 DefaultCameraOffset = new Vector3(-5, 0, 0);
+
         public StateManager(RadegastInstance instance)
         {
             this.instance = instance;
             this.instance.ClientChanged += new EventHandler<ClientChangedEventArgs>(instance_ClientChanged);
+            KnownAnimations = Animations.ToDictionary();
+            autosit = new AutoSit(this.instance);
+            pseudohome = new PseudoHome(this.instance);
+            lslHelper = new LSLHelper(this.instance);
 
             beamTimer = new System.Timers.Timer();
             beamTimer.Enabled = false;
@@ -132,24 +212,24 @@ namespace Radegast
 
         private void RegisterClientEvents(GridClient client)
         {
+            client.Objects.AvatarUpdate += new EventHandler<AvatarUpdateEventArgs>(Objects_AvatarUpdate);
             client.Objects.TerseObjectUpdate += new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);
+            client.Objects.AvatarSitChanged += new EventHandler<AvatarSitChangedEventArgs>(Objects_AvatarSitChanged);
             client.Self.AlertMessage += new EventHandler<AlertMessageEventArgs>(Self_AlertMessage);
             client.Self.TeleportProgress += new EventHandler<TeleportEventArgs>(Self_TeleportProgress);
             client.Network.EventQueueRunning += new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
+            client.Network.SimChanged += new EventHandler<SimChangedEventArgs>(Network_SimChanged);
         }
 
         private void UnregisterClientEvents(GridClient client)
         {
+            client.Objects.AvatarUpdate -= new EventHandler<AvatarUpdateEventArgs>(Objects_AvatarUpdate);
             client.Objects.TerseObjectUpdate -= new EventHandler<TerseObjectUpdateEventArgs>(Objects_TerseObjectUpdate);
+            client.Objects.AvatarSitChanged -= new EventHandler<AvatarSitChangedEventArgs>(Objects_AvatarSitChanged);
             client.Self.AlertMessage -= new EventHandler<AlertMessageEventArgs>(Self_AlertMessage);
             client.Self.TeleportProgress -= new EventHandler<TeleportEventArgs>(Self_TeleportProgress);
             client.Network.EventQueueRunning -= new EventHandler<EventQueueRunningEventArgs>(Network_EventQueueRunning);
-        }
-
-        void instance_ClientChanged(object sender, ClientChangedEventArgs e)
-        {
-            UnregisterClientEvents(e.OldClient);
-            RegisterClientEvents(client);
+            client.Network.SimChanged -= new EventHandler<SimChangedEventArgs>(Network_SimChanged);
         }
 
         public void Dispose()
@@ -172,8 +252,230 @@ namespace Radegast
                 walkTimer.Dispose();
                 walkTimer = null;
             }
+
+            if (autosit != null)
+            {
+                autosit.Dispose();
+                autosit = null;
+            }
+
+            if (lslHelper == null)
+            {
+                lslHelper.Dispose();
+                lslHelper = null;
+            }
+        }
+
+        void instance_ClientChanged(object sender, ClientChangedEventArgs e)
+        {
+            UnregisterClientEvents(e.OldClient);
+            RegisterClientEvents(client);
+        }
+
+        void Objects_AvatarSitChanged(object sender, AvatarSitChangedEventArgs e)
+        {
+            if (e.Avatar.LocalID != client.Self.LocalID) return;
+
+            sitting = e.SittingOn != 0;
+
+            if (client.Self.SittingOn != 0 && !client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(client.Self.SittingOn))
+            {
+                client.Objects.RequestObject(client.Network.CurrentSim, client.Self.SittingOn);
+            }
+
+            if (SitStateChanged != null)
+            {
+                SitStateChanged(this, new SitEventArgs(this.sitting));
+            }
+        }
+
+        /// <summary>
+        /// Locates avatar in the current sim, or adjacents sims
+        /// </summary>
+        /// <param name="person">Avatar UUID</param>
+        /// <param name="position">Position within sim</param>
+        /// <returns>True if managed to find the avatar</returns>
+        public bool TryFindAvatar(UUID person, out Vector3 position)
+        {
+            Simulator sim;
+            if (!TryFindAvatar(person, out sim, out position)) return false;
+            // same sim?
+            if (sim == client.Network.CurrentSim) return true;
+            position = ToLocalPosition(sim.Handle, position);
+            return true;
+        }
+
+        public Vector3 ToLocalPosition(ulong handle, Vector3 position)
+        {
+            Vector3d diff = ToVector3D(handle, position) - client.Self.GlobalPosition;
+            position = new Vector3((float) diff.X, (float) diff.Y, (float) diff.Z) - position;
+            return position;
+        }
+
+        public static Vector3d ToVector3D(ulong handle, Vector3 pos)
+        {
+            uint globalX, globalY;
+            Utils.LongToUInts(handle, out globalX, out globalY);
+
+            return new Vector3d(
+                (double)globalX + (double)pos.X,
+                (double)globalY + (double)pos.Y,
+                (double)pos.Z);
+        }
+
+        /// <summary>
+        /// Locates avatar in the current sim, or adjacents sims
+        /// </summary>
+        /// <param name="person">Avatar UUID</param>
+        /// <param name="sim">Simulator avatar is in</param>
+        /// <param name="position">Position within sim</param>
+        /// <returns>True if managed to find the avatar</returns>
+        public bool TryFindAvatar(UUID person, out Simulator sim, out Vector3 position)
+        {
+            return TryFindPrim(person, out sim, out position, true);
+        }
+        public bool TryFindPrim(UUID person, out Simulator sim, out Vector3 position, bool onlyAvatars)
+        {
+            Simulator[] Simulators = null;
+            lock (client.Network.Simulators)
+            {
+                Simulators = client.Network.Simulators.ToArray();
+            }
+            sim = null;
+            position = Vector3.Zero;
+
+            Primitive avi = null;
+
+            // First try the object tracker
+            foreach (var s in Simulators)
+            {
+                avi = s.ObjectsAvatars.Find((Avatar av) => { return av.ID == person; });
+                if (avi != null)
+                {
+                    sim = s;
+                    break;
+                }
+            }
+            if (avi == null && !onlyAvatars)
+            {
+                foreach (var s in Simulators)
+                {
+                    avi = s.ObjectsPrimitives.Find((Primitive av) => { return av.ID == person; });
+                    if (avi != null)
+                    {
+                        sim = s;
+                        break;
+                    }
+                }
+            }
+            if (avi != null)
+            {
+                if (avi.ParentID == 0)
+                {
+                    position = avi.Position;
+                }
+                else
+                {
+                    Primitive seat;
+                    if (sim.ObjectsPrimitives.TryGetValue(avi.ParentID, out seat))
+                    {
+                        position = seat.Position + avi.Position * seat.Rotation;
+                    }
+                }
+            }
+            else
+            {
+                foreach (var s in Simulators)
+                {
+                    if (s.AvatarPositions.ContainsKey(person))
+                    {
+                        position = s.AvatarPositions[person];
+                        sim = s;
+                        break;
+                    }
+                }
+            }
+
+            if (position.Z > 0.1f)
+                return true;
+            else
+                return false;
+        }
+
+        public bool TryLocatePrim(Primitive avi, out Simulator sim, out Vector3 position)
+        {
+            Simulator[] Simulators = null;
+            lock (client.Network.Simulators)
+            {
+                Simulators = client.Network.Simulators.ToArray();
+            }
+
+            sim = client.Network.CurrentSim;
+            position = Vector3.Zero;
+            {
+                foreach (var s in Simulators)
+                {
+                    if (s.Handle == avi.RegionHandle)
+                    {
+                        sim = s;
+                        break;
+                    }
+                }
+            }
+            if (avi != null)
+            {
+                if (avi.ParentID == 0)
+                {
+                    position = avi.Position;
+                }
+                else
+                {
+                    Primitive seat;
+                    if (sim.ObjectsPrimitives.TryGetValue(avi.ParentID, out seat))
+                    {
+                        position = seat.Position + avi.Position*seat.Rotation;
+                    }
+                }
+            }
+            if (position.Z > 0.1f)
+                return true;
+            else
+                return false;
+        }
+
+        /// <summary>
+        /// Move to target position either by walking or by teleporting
+        /// </summary>
+        /// <param name="target">Sim local position of the target</param>
+        /// <param name="useTP">Move using teleport</param>
+        public void MoveTo(Vector3 target, bool useTP)
+        {
+            MoveTo(client.Network.CurrentSim, target, useTP);
+        }
+
+        /// <summary>
+        /// Move to target position either by walking or by teleporting
+        /// </summary>
+        /// <param name="sim">Simulator in which the target is</param>
+        /// <param name="target">Sim local position of the target</param>
+        /// <param name="useTP">Move using teleport</param>
+        public void MoveTo(Simulator sim, Vector3 target, bool useTP)
+        {
+            SetSitting(false, UUID.Zero);
+
+            if (useTP)
+            {
+                client.Self.RequestTeleport(sim.Handle, target);
+            }
+            else
+            {
+                displayEndWalk = true;
+                client.Self.Movement.TurnToward(target);
+                WalkTo(GlobalPosition(sim, target));
+            }
         }
 
+
         public void SetRandomHeading()
         {
             client.Self.Movement.UpdateFromHeading(Utils.TWO_PI * rnd.NextDouble(), true);
@@ -188,6 +490,17 @@ namespace Radegast
             }
         }
 
+        void Network_SimChanged(object sender, SimChangedEventArgs e)
+        {
+            WorkPool.QueueUserWorkItem(sync =>
+            {
+                Thread.Sleep(15 * 1000);
+                autosit.TrySit();
+                pseudohome.ETGoHome();
+            });
+            client.Self.Movement.SetFOVVerticalAngle(FOVVerticalAngle);
+        }
+
         private UUID teleportEffect = UUID.Random();
 
         void Self_TeleportProgress(object sender, TeleportEventArgs e)
@@ -225,54 +538,180 @@ namespace Radegast
 
         void netcom_ClientConnected(object sender, EventArgs e)
         {
-            client.Self.Movement.Camera.Far = 256f;
-            effectSource = client.Self.AgentID;
+            if (!instance.GlobalSettings.ContainsKey("draw_distance"))
+            {
+                instance.GlobalSettings["draw_distance"] = 48;
+            }
+
+            client.Self.Movement.Camera.Far = instance.GlobalSettings["draw_distance"];
 
             if (lookAtTimer == null)
+            {
                 lookAtTimer = new System.Threading.Timer(new TimerCallback(lookAtTimerTick), null, Timeout.Infinite, Timeout.Infinite);
+            }
+        }
+
+        void Objects_AvatarUpdate(object sender, AvatarUpdateEventArgs e)
+        {
+            if (e.Avatar.LocalID == client.Self.LocalID)
+            {
+                SetDefaultCamera();
+            }
         }
 
         void Objects_TerseObjectUpdate(object sender, TerseObjectUpdateEventArgs e)
         {
             if (!e.Update.Avatar) return;
+            
+            if (e.Prim.LocalID == client.Self.LocalID)
+            {
+                SetDefaultCamera();
+            }
+
             if (!following) return;
 
             Avatar av;
             client.Network.CurrentSim.ObjectsAvatars.TryGetValue(e.Update.LocalID, out av);
             if (av == null) return;
 
-            if (av.Name == followName)
+            if (av.ID == followID)
+            {
+                Vector3 pos = AvatarPosition(client.Network.CurrentSim, av);
+
+                FollowUpdate(pos);
+            }
+        }
+
+        void FollowUpdate(Vector3 pos)
+        {
+            if (Vector3.Distance(pos, client.Self.SimPosition) > followDistance)
+            {
+                Vector3 target = pos + Vector3.Normalize(client.Self.SimPosition - pos) * (followDistance - 1f);
+                client.Self.AutoPilotCancel();
+                Vector3d glb = GlobalPosition(client.Network.CurrentSim, target);
+                client.Self.AutoPilot(glb.X, glb.Y, glb.Z);
+            }
+            else
             {
-                Vector3 pos;
+                client.Self.AutoPilotCancel();
+                client.Self.Movement.TurnToward(pos);
+            }
+        }
 
-                if (av.ParentID == 0)
+        public void SetDefaultCamera()
+        {
+            if (CameraTracksOwnAvatar)
+            {
+                if (client.Self.SittingOn != 0 && !client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(client.Self.SittingOn))
                 {
-                    pos = av.Position;
+                    // We are sitting but don't have the information about the object we are sitting on
+                    // Sim seems to ignore RequestMutlipleObjects message
+                    // client.Objects.RequestObject(client.Network.CurrentSim, client.Self.SittingOn);
                 }
                 else
                 {
-                    Primitive prim;
-                    client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(av.ParentID, out prim);
+                    Vector3 pos = client.Self.SimPosition + DefaultCameraOffset * client.Self.Movement.BodyRotation;
+                    //Logger.Log("Setting camera position to " + pos.ToString(), Helpers.LogLevel.Debug);
+                    client.Self.Movement.Camera.LookAt(
+                        pos,
+                        client.Self.SimPosition
+                    );
+                }
+            }
+        }
 
-                    if (prim == null)
-                        pos = client.Self.SimPosition;
-                    else
-                        pos = prim.Position + av.Position;
+        public Quaternion AvatarRotation(Simulator sim, UUID avID)
+        {
+            Quaternion rot = Quaternion.Identity;
+            Avatar av = sim.ObjectsAvatars.Find((Avatar a) => { return a.ID == avID; });
+
+            if (av == null)
+                return rot;
+
+            if (av.ParentID == 0)
+            {
+                rot = av.Rotation;
+            }
+            else
+            {
+                Primitive prim;
+                if (sim.ObjectsPrimitives.TryGetValue(av.ParentID, out prim))
+                {
+                    rot = prim.Rotation + av.Rotation;
                 }
+            }
+
+            return rot;
+        }
+
+
+        public Vector3 AvatarPosition(Simulator sim, UUID avID)
+        {
+            Vector3 pos = Vector3.Zero;
+            Avatar av = sim.ObjectsAvatars.Find((Avatar a) => { return a.ID == avID; });
+            if (av != null)
+            {
+                return AvatarPosition(sim, av);
+            }
+            else
+            {
+                Vector3 coarse;
+                if (sim.AvatarPositions.TryGetValue(avID, out coarse))
+                {
+                    if (coarse.Z > 0.01)
+                        return coarse;
+                }
+            }
+            return pos;
+        }
+
+        public Vector3 AvatarPosition(Simulator sim, Avatar av)
+        {
+            Vector3 pos = Vector3.Zero;
 
-                if (Vector3.Distance(pos, client.Self.SimPosition) > followDistance)
+            if (av.ParentID == 0)
+            {
+                pos = av.Position;
+            }
+            else
+            {
+                Primitive prim;
+                if (sim.ObjectsPrimitives.TryGetValue(av.ParentID, out prim))
                 {
-                    int followRegionX = (int)(e.Simulator.Handle >> 32);
-                    int followRegionY = (int)(e.Simulator.Handle & 0xFFFFFFFF);
-                    ulong x = (ulong)(pos.X + followRegionX);
-                    ulong y = (ulong)(pos.Y + followRegionY);
+                    pos = prim.Position + av.Position;
+                }
+            }
+
+            return pos;
+        }
 
-                    client.Self.AutoPilotCancel();
-                    client.Self.AutoPilot(x, y, pos.Z);
+        public void Follow(string name, UUID id)
+        {
+            followName = name;
+            followID = id;
+            following = followID != UUID.Zero;
+
+            if (following)
+            {
+                walking = false;
+
+                Vector3 target = AvatarPosition(client.Network.CurrentSim, id);
+                if (Vector3.Zero != target)
+                {
+                    client.Self.Movement.TurnToward(target);
+                    FollowUpdate(target);
                 }
+
             }
         }
 
+        public void StopFollowing()
+        {
+            following = false;
+            followName = string.Empty;
+            followID = UUID.Zero;
+        }
+
         #region Look at effect
         private int lastLookAtEffect = 0;
         private UUID lookAtEffect = UUID.Random();
@@ -282,7 +721,7 @@ namespace Radegast
         /// </summary>
         public void LookInFront()
         {
-            if (!client.Network.Connected) return;
+            if (!client.Network.Connected || instance.GlobalSettings["disable_look_at"]) return;
 
             client.Self.LookAtEffect(client.Self.AgentID, client.Self.AgentID,
                 new Vector3d(new Vector3(3, 0, 0) * Quaternion.Identity),
@@ -296,7 +735,11 @@ namespace Radegast
 
         void netcom_ChatReceived(object sender, ChatEventArgs e)
         {
-            if (e.SourceID != client.Self.AgentID && (e.SourceType == ChatSourceType.Agent || e.Type == ChatType.StartTyping))
+            //somehow it can be too early (when Radegast is loaded from running bot)
+            if (instance.GlobalSettings==null) return;
+            if (!instance.GlobalSettings["disable_look_at"]
+                && e.SourceID != client.Self.AgentID
+                && (e.SourceType == ChatSourceType.Agent || e.Type == ChatType.StartTyping))
             {
                 // change focus max every 4 seconds
                 if (Environment.TickCount - lastLookAtEffect > 4000)
@@ -313,17 +756,6 @@ namespace Radegast
         }
         #endregion Look at effect
 
-        public void Follow(string name)
-        {
-            followName = name;
-            following = !string.IsNullOrEmpty(followName);
-
-            if (following)
-            {
-                walking = false;
-            }
-        }
-
         #region Walking (move to)
         private bool walking = false;
         private System.Threading.Timer walkTimer;
@@ -336,6 +768,19 @@ namespace Radegast
         {
             WalkTo(GlobalPosition(prim));
         }
+        public double WaitUntilPosition(Vector3d pos, TimeSpan maxWait, double howClose)
+        {
+             
+            DateTime until = DateTime.Now + maxWait;
+            while (until > DateTime.Now)
+            {
+                double dist = Vector3d.Distance(client.Self.GlobalPosition, pos);
+                if (howClose >= dist) return dist;
+                Thread.Sleep(250);
+            }
+            return Vector3d.Distance(client.Self.GlobalPosition, pos);
+            
+        }
 
         public void WalkTo(Vector3d globalPos)
         {
@@ -382,7 +827,7 @@ namespace Radegast
                     EndWalking();
                     return;
                 }
-                walkTimer.Change(walkChekInterval, Timeout.Infinite);
+                if (walkTimer != null) walkTimer.Change(walkChekInterval, Timeout.Infinite);
             }
         }
 
@@ -415,6 +860,22 @@ namespace Radegast
                 walkTimer.Dispose();
                 walkTimer = null;
                 client.Self.AutoPilotCancel();
+                
+                if (displayEndWalk)
+                {
+                    displayEndWalk = false;
+                    string msg = "Finished walking";
+
+                    if (walkToTarget != Vector3d.Zero)
+                    {
+                        System.Threading.Thread.Sleep(1000);
+                        msg += string.Format(" {0:0} meters from destination", Vector3d.Distance(client.Self.GlobalPosition, walkToTarget));
+                        walkToTarget = Vector3d.Zero;
+                    }
+
+                    instance.TabConsole.DisplayNotificationInChat(msg);
+                }
+
                 FireWalkStateCanged();
             }
         }
@@ -422,6 +883,8 @@ namespace Radegast
 
         public void SetTyping(bool typing)
         {
+            if (!client.Network.Connected) return;
+
             Dictionary<UUID, bool> typingAnim = new Dictionary<UUID, bool>();
             typingAnim.Add(typingAnimationID, typing);
 
@@ -441,6 +904,7 @@ namespace Radegast
             awayAnim.Add(awayAnimationID, away);
 
             client.Self.Animate(awayAnim, true);
+            if (UseMoveControl) client.Self.Movement.Away = away;
             this.away = away;
         }
 
@@ -474,11 +938,48 @@ namespace Radegast
             }
             else
             {
-                client.Self.Stand();
+                if (!instance.RLV.RestictionActive("unsit"))
+                {
+                    client.Self.Stand();
+                }
+                else
+                {
+                    instance.TabConsole.DisplayNotificationInChat("Unsit prevented by RLV");
+                    this.sitting = true;
+                    return;
+                }
+            }
+
+            if (SitStateChanged != null)
+            {
+                SitStateChanged(this, new SitEventArgs(this.sitting));
+            }
+
+            if (!this.sitting)
+            {
+                StopAllAnimations();
             }
         }
 
-        public Vector3d GlobalPosition(Simulator sim, Vector3 pos)
+        public void StopAllAnimations()
+        {
+            Dictionary<UUID, bool> stop = new Dictionary<UUID, bool>();
+
+            client.Self.SignaledAnimations.ForEach((UUID anim) =>
+            {
+                if (!KnownAnimations.ContainsKey(anim))
+                {
+                    stop.Add(anim, false);
+                }
+            });
+
+            if (stop.Count > 0)
+            {
+                client.Self.Animate(stop, true);
+            }
+        }
+
+        static public Vector3d GlobalPosition(Simulator sim, Vector3 pos)
         {
             uint globalX, globalY;
             Utils.LongToUInts(sim.Handle, out globalX, out globalY);
@@ -503,14 +1004,13 @@ namespace Radegast
         private int numBeans;
         private Color4[] beamColors = new Color4[3] { new Color4(0, 255, 0, 255), new Color4(255, 0, 0, 255), new Color4(0, 0, 255, 255) };
         private Primitive targetPrim;
-        private UUID effectSource;
 
         public void UnSetPointing()
         {
             beamTimer.Enabled = false;
             if (pointID != UUID.Zero)
             {
-                client.Self.PointAtEffect(effectSource, UUID.Zero, Vector3d.Zero, PointAtType.None, pointID);
+                client.Self.PointAtEffect(client.Self.AgentID, UUID.Zero, Vector3d.Zero, PointAtType.None, pointID);
                 pointID = UUID.Zero;
             }
 
@@ -555,7 +1055,7 @@ namespace Radegast
                         cross.Normalize();
                         scatter = GlobalPosition(targetPrim) + cross * (i * 0.2d) * (i % 2 == 0 ? 1 : -1);
                     }
-                    client.Self.BeamEffect(effectSource, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[i]);
+                    client.Self.BeamEffect(client.Self.AgentID, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[i]);
                 }
 
                 for (int j = 1; j < numBeans; j++)
@@ -566,7 +1066,7 @@ namespace Radegast
                     cross.Normalize();
                     scatter = GlobalPosition(targetPrim) + cross * (j * 0.2d) * (j % 2 == 0 ? 1 : -1);
 
-                    client.Self.BeamEffect(effectSource, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[j + i - 1]);
+                    client.Self.BeamEffect(client.Self.AgentID, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[j + i - 1]);
                 }
             }
             catch (Exception) { };
@@ -584,7 +1084,7 @@ namespace Radegast
             targetPrim = prim;
             this.numBeans = numBeans;
 
-            client.Self.PointAtEffect(effectSource, prim.ID, Vector3d.Zero, PointAtType.Select, pointID);
+            client.Self.PointAtEffect(client.Self.AgentID, prim.ID, Vector3d.Zero, PointAtType.Select, pointID);
 
             for (int i = 0; i < numBeans; i++)
             {
@@ -622,12 +1122,6 @@ namespace Radegast
             set { busyAnimationID = value; }
         }
 
-        public UUID EffectSource
-        {
-            get { return effectSource; }
-            set { effectSource = value; }
-        }
-
         public bool IsTyping
         {
             get { return typing; }
@@ -635,7 +1129,11 @@ namespace Radegast
 
         public bool IsAway
         {
-            get { return away; }
+            get
+            {
+                if (UseMoveControl) return client.Self.Movement.Away;
+                return away;
+            }
         }
 
         public bool IsBusy
@@ -645,12 +1143,20 @@ namespace Radegast
 
         public bool IsFlying
         {
-            get { return flying; }
+            get { return client.Self.Movement.Fly; }
         }
 
         public bool IsSitting
         {
-            get { return sitting; }
+            get
+            {
+                if (client.Self.Movement.SitOnGround || client.Self.SittingOn != 0) return true;
+                if (sitting) {
+                    Logger.Log("out of sync sitting", Helpers.LogLevel.Debug);
+                    sitting = false;
+                }
+                return false;
+            }
         }
 
         public bool IsPointing
@@ -679,5 +1185,39 @@ namespace Radegast
         {
             get { return walking; }
         }
+
+        private AutoSit autosit;
+        public AutoSit AutoSit
+        {
+            get { return autosit; }
+        }
+
+        private LSLHelper lslHelper;
+        public LSLHelper LSLHelper
+        {
+            get { return lslHelper; }
+        }
+
+        private PseudoHome pseudohome;
+
+        /// <summary>
+        /// Experimental Option that sometimes the Client has more authority than state mananger
+        /// </summary>
+        public static bool UseMoveControl;
+
+        public PseudoHome PseudoHome
+        {
+            get { return pseudohome; }
+        }
+    }
+
+    public class SitEventArgs : EventArgs
+    {
+        public bool Sitting;
+
+        public SitEventArgs(bool sitting)
+        {
+            this.Sitting = sitting;
+        }
     }
 }