OSDN Git Service

Silence too verbose debug
[radegast/radegast.git] / Radegast / Core / StateManager.cs
index 588d4fb..4387a57 100644 (file)
@@ -1,6 +1,6 @@
 // 
 // Radegast Metaverse Client
-// Copyright (c) 2009-2012, 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,6 +45,7 @@ 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;
@@ -74,6 +78,7 @@ namespace Radegast
         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");
@@ -81,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>
@@ -179,12 +186,17 @@ namespace Radegast
         }
 
         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;
@@ -200,20 +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);
+            client.Network.SimChanged -= new EventHandler<SimChangedEventArgs>(Network_SimChanged);
         }
 
         public void Dispose()
@@ -236,6 +252,18 @@ 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)
@@ -248,7 +276,13 @@ namespace Radegast
         {
             if (e.Avatar.LocalID != client.Self.LocalID) return;
 
-            this.sitting = e.SittingOn != 0;
+            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));
@@ -259,27 +293,81 @@ namespace Radegast
         /// 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;
 
-            Avatar avi = null;
+            Primitive avi = null;
 
-            // First try the objecct tracker
-            for (int i = 0; i < client.Network.Simulators.Count; i++)
+            // First try the object tracker
+            foreach (var s in Simulators)
             {
-                avi = client.Network.Simulators[i].ObjectsAvatars.Find((Avatar av) => { return av.ID == person; });
+                avi = s.ObjectsAvatars.Find((Avatar av) => { return av.ID == person; });
                 if (avi != null)
                 {
-                    sim = client.Network.Simulators[i];
+                    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)
@@ -291,18 +379,18 @@ namespace Radegast
                     Primitive seat;
                     if (sim.ObjectsPrimitives.TryGetValue(avi.ParentID, out seat))
                     {
-                        position = seat.Position + avi.Position;
+                        position = seat.Position + avi.Position * seat.Rotation;
                     }
                 }
             }
             else
             {
-                for (int i = 0; i < client.Network.Simulators.Count; i++)
+                foreach (var s in Simulators)
                 {
-                    if (client.Network.Simulators[i].AvatarPositions.ContainsKey(person))
+                    if (s.AvatarPositions.ContainsKey(person))
                     {
-                        sim = client.Network.Simulators[i];
-                        position = sim.AvatarPositions[person];
+                        position = s.AvatarPositions[person];
+                        sim = s;
                         break;
                     }
                 }
@@ -314,6 +402,80 @@ namespace Radegast
                 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);
@@ -328,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)
@@ -373,19 +546,35 @@ namespace Radegast
             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);
 
@@ -409,6 +598,28 @@ namespace Radegast
             }
         }
 
+        public void SetDefaultCamera()
+        {
+            if (CameraTracksOwnAvatar)
+            {
+                if (client.Self.SittingOn != 0 && !client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(client.Self.SittingOn))
+                {
+                    // 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
+                {
+                    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
+                    );
+                }
+            }
+        }
+
         public Quaternion AvatarRotation(Simulator sim, UUID avID)
         {
             Quaternion rot = Quaternion.Identity;
@@ -510,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),
@@ -524,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)
@@ -553,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)
         {
@@ -599,7 +827,7 @@ namespace Radegast
                     EndWalking();
                     return;
                 }
-                walkTimer.Change(walkChekInterval, Timeout.Infinite);
+                if (walkTimer != null) walkTimer.Change(walkChekInterval, Timeout.Infinite);
             }
         }
 
@@ -632,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();
             }
         }
@@ -660,6 +904,7 @@ namespace Radegast
             awayAnim.Add(awayAnimationID, away);
 
             client.Self.Animate(awayAnim, true);
+            if (UseMoveControl) client.Self.Movement.Away = away;
             this.away = away;
         }
 
@@ -693,7 +938,16 @@ 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)
@@ -725,7 +979,7 @@ namespace Radegast
             }
         }
 
-        public Vector3d GlobalPosition(Simulator sim, Vector3 pos)
+        static public Vector3d GlobalPosition(Simulator sim, Vector3 pos)
         {
             uint globalX, globalY;
             Utils.LongToUInts(sim.Handle, out globalX, out globalY);
@@ -875,7 +1129,11 @@ namespace Radegast
 
         public bool IsAway
         {
-            get { return away; }
+            get
+            {
+                if (UseMoveControl) return client.Self.Movement.Away;
+                return away;
+            }
         }
 
         public bool IsBusy
@@ -885,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
@@ -919,6 +1185,30 @@ 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