Files
RaindropViewer/Assets/Raindrop/Core/StateManager.cs
T

1225 lines
41 KiB
C#

//
// Radegast Metaverse Client
// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the application "Radegast", nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Id$
//
using System;
using System.Collections.Generic;
using System.Timers;
using System.Threading;
using OpenMetaverse;
//using Radegast.Automation;
using Raindrop.Netcom;
namespace Raindrop
{
public class KnownHeading
{
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 RaindropInstance instance;
private GridClient client { get { return instance.Client; } }
private RaindropNetcom netcom { get { return instance.Netcom; } }
private bool typing = false;
private bool away = false;
private bool busy = false;
private bool flying = false;
private bool alwaysrun = false;
private bool sitting = false;
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");
private UUID typingAnimationID = new UUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
internal static Random rnd = new Random();
private System.Threading.Timer lookAtTimer;
public float FOVVerticalAngle = OpenMetaverse.Utils.TWO_PI - 0.05f;
/// <summary>
/// Passes walk state
/// </summary>
/// <param name="walking">True if we are walking towards a targer</param>
public delegate void WalkStateCanged(bool walking);
/// <summary>
/// Fires when we start or stop walking towards a target
/// </summary>
public event WalkStateCanged OnWalkStateCanged;
/// <summary>
/// Fires when avatar stands
/// </summary>
public event EventHandler<SitEventArgs> SitStateChanged;
static List<KnownHeading> m_Headings;
public static List<KnownHeading> KnownHeadings
{
get
{
if (m_Headings == null)
{
m_Headings = new List<KnownHeading>(16);
m_Headings.Add(new KnownHeading("E", "East", new Quaternion(0.00000f, 0.00000f, 0.00000f, 1.00000f)));
m_Headings.Add(new KnownHeading("ENE", "East by Northeast", new Quaternion(0.00000f, 0.00000f, 0.19509f, 0.98079f)));
m_Headings.Add(new KnownHeading("NE", "Northeast", new Quaternion(0.00000f, 0.00000f, 0.38268f, 0.92388f)));
m_Headings.Add(new KnownHeading("NNE", "North by Northeast", new Quaternion(0.00000f, 0.00000f, 0.55557f, 0.83147f)));
m_Headings.Add(new KnownHeading("N", "North", new Quaternion(0.00000f, 0.00000f, 0.70711f, 0.70711f)));
m_Headings.Add(new KnownHeading("NNW", "North by Northwest", new Quaternion(0.00000f, 0.00000f, 0.83147f, 0.55557f)));
m_Headings.Add(new KnownHeading("NW", "Nortwest", new Quaternion(0.00000f, 0.00000f, 0.92388f, 0.38268f)));
m_Headings.Add(new KnownHeading("WNW", "West by Northwest", new Quaternion(0.00000f, 0.00000f, 0.98079f, 0.19509f)));
m_Headings.Add(new KnownHeading("W", "West", new Quaternion(0.00000f, 0.00000f, 1.00000f, -0.00000f)));
m_Headings.Add(new KnownHeading("WSW", "West by Southwest", new Quaternion(0.00000f, 0.00000f, 0.98078f, -0.19509f)));
m_Headings.Add(new KnownHeading("SW", "Southwest", new Quaternion(0.00000f, 0.00000f, 0.92388f, -0.38268f)));
m_Headings.Add(new KnownHeading("SSW", "South by Southwest", new Quaternion(0.00000f, 0.00000f, 0.83147f, -0.55557f)));
m_Headings.Add(new KnownHeading("S", "South", new Quaternion(0.00000f, 0.00000f, 0.70711f, -0.70711f)));
m_Headings.Add(new KnownHeading("SSE", "South by Southeast", new Quaternion(0.00000f, 0.00000f, 0.55557f, -0.83147f)));
m_Headings.Add(new KnownHeading("SE", "Southeast", new Quaternion(0.00000f, 0.00000f, 0.38268f, -0.92388f)));
m_Headings.Add(new KnownHeading("ESE", "East by Southeast", new Quaternion(0.00000f, 0.00000f, 0.19509f, -0.98078f)));
}
return m_Headings;
}
}
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(RaindropInstance 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;
beamTimer.Elapsed += new ElapsedEventHandler(beamTimer_Elapsed);
// Callbacks
netcom.ClientConnected += new EventHandler<EventArgs>(netcom_ClientConnected);
netcom.ClientDisconnected += new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
netcom.ChatReceived += new EventHandler<ChatEventArgs>(netcom_ChatReceived);
RegisterClientEvents(client);
}
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()
{
netcom.ClientConnected -= new EventHandler<EventArgs>(netcom_ClientConnected);
netcom.ClientDisconnected -= new EventHandler<DisconnectedEventArgs>(netcom_ClientDisconnected);
netcom.ChatReceived -= new EventHandler<ChatEventArgs>(netcom_ChatReceived);
UnregisterClientEvents(client);
beamTimer.Dispose();
beamTimer = null;
if (lookAtTimer != null)
{
lookAtTimer.Dispose();
lookAtTimer = null;
}
if (walkTimer != null)
{
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;
OpenMetaverse.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(OpenMetaverse.Utils.TWO_PI * rnd.NextDouble(), true);
LookInFront();
}
void Network_EventQueueRunning(object sender, EventQueueRunningEventArgs e)
{
if (e.Simulator == client.Network.CurrentSim)
{
SetRandomHeading();
}
}
void Network_SimChanged(object sender, SimChangedEventArgs e)
{
//ThreadPool.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)
{
if (!client.Network.Connected) return;
if (e.Status == TeleportStatus.Progress)
{
instance.MediaManager.PlayUISound(UISounds.Teleport);
client.Self.SphereEffect(client.Self.GlobalPosition, Color4.White, 4f, teleportEffect);
}
if (e.Status == TeleportStatus.Finished)
{
client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0f, teleportEffect);
SetRandomHeading();
}
if (e.Status == TeleportStatus.Failed)
{
instance.MediaManager.PlayUISound(UISounds.Error);
client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0f, teleportEffect);
}
}
void netcom_ClientDisconnected(object sender, DisconnectedEventArgs e)
{
typing = away = busy = walking = false;
if (lookAtTimer != null)
{
lookAtTimer.Dispose();
lookAtTimer = null;
}
}
void netcom_ClientConnected(object sender, EventArgs e)
{
if (true /*!instance.GlobalSettings.ContainsKey("draw_distance")*/) //todo
{
instance.GlobalSettings["draw_distance"] = 20;
}
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.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
{
client.Self.AutoPilotCancel();
client.Self.Movement.TurnToward(pos);
}
}
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;
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 (av.ParentID == 0)
{
pos = av.Position;
}
else
{
Primitive prim;
if (sim.ObjectsPrimitives.TryGetValue(av.ParentID, out prim))
{
pos = prim.Position + av.Position;
}
}
return pos;
}
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();
/// <summary>
/// Set eye focus 3m in front of us
/// </summary>
public void LookInFront()
{
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),
LookAtType.Idle, lookAtEffect);
}
void lookAtTimerTick(object state)
{
LookInFront();
}
void netcom_ChatReceived(object sender, ChatEventArgs e)
{
//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)
{
lastLookAtEffect = Environment.TickCount;
client.Self.LookAtEffect(client.Self.AgentID, e.SourceID, Vector3d.Zero, LookAtType.Respond, lookAtEffect);
// keep looking at the speaker for 10 seconds
if (lookAtTimer != null)
{
lookAtTimer.Change(10000, Timeout.Infinite);
}
}
}
}
#endregion Look at effect
#region Walking (move to)
private bool walking = false;
private System.Threading.Timer walkTimer;
private int walkChekInterval = 500;
private Vector3d walkToTarget;
int lastDistance = 0;
int lastDistanceChanged = 0;
public void WalkTo(Primitive prim)
{
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)
{
walkToTarget = globalPos;
if (following)
{
following = false;
followName = string.Empty;
}
if (walkTimer == null)
{
walkTimer = new System.Threading.Timer(new TimerCallback(walkTimerElapsed), null, walkChekInterval, Timeout.Infinite);
}
lastDistanceChanged = System.Environment.TickCount;
client.Self.AutoPilotCancel();
walking = true;
client.Self.AutoPilot(walkToTarget.X, walkToTarget.Y, walkToTarget.Z);
FireWalkStateCanged();
}
void walkTimerElapsed(object sender)
{
double distance = Vector3d.Distance(client.Self.GlobalPosition, walkToTarget);
if (distance < 2d)
{
// We're there
EndWalking();
}
else
{
if (lastDistance != (int)distance)
{
lastDistanceChanged = System.Environment.TickCount;
lastDistance = (int)distance;
}
else if ((System.Environment.TickCount - lastDistanceChanged) > 10000)
{
// Our distance to the target has not changed in 10s, give up
EndWalking();
return;
}
if (walkTimer != null) walkTimer.Change(walkChekInterval, Timeout.Infinite);
}
}
void Self_AlertMessage(object sender, AlertMessageEventArgs e)
{
if (e.Message.Contains("Autopilot cancel"))
{
if (walking)
{
EndWalking();
}
}
}
void FireWalkStateCanged()
{
if (OnWalkStateCanged != null)
{
try { OnWalkStateCanged(walking); }
catch (Exception) { }
}
}
public void EndWalking()
{
if (walking)
{
walking = false;
Logger.Log("Finished walking.", Helpers.LogLevel.Debug, client);
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();
}
}
#endregion
public void SetTyping(bool typing)
{
if (!client.Network.Connected) return;
Dictionary<UUID, bool> typingAnim = new Dictionary<UUID, bool>();
typingAnim.Add(typingAnimationID, typing);
client.Self.Animate(typingAnim, false);
if (typing)
client.Self.Chat(string.Empty, 0, ChatType.StartTyping);
else
client.Self.Chat(string.Empty, 0, ChatType.StopTyping);
this.typing = typing;
}
public void SetAway(bool away)
{
Dictionary<UUID, bool> awayAnim = new Dictionary<UUID, bool>();
awayAnim.Add(awayAnimationID, away);
client.Self.Animate(awayAnim, true);
if (UseMoveControl) client.Self.Movement.Away = away;
this.away = away;
}
public void SetBusy(bool busy)
{
Dictionary<UUID, bool> busyAnim = new Dictionary<UUID, bool>();
busyAnim.Add(busyAnimationID, busy);
client.Self.Animate(busyAnim, true);
this.busy = busy;
}
public void SetFlying(bool flying)
{
this.flying = client.Self.Movement.Fly = flying;
}
public void SetAlwaysRun(bool alwaysrun)
{
this.alwaysrun = client.Self.Movement.AlwaysRun = alwaysrun;
}
public void SetSitting(bool sitting, UUID target)
{
this.sitting = sitting;
if (sitting)
{
client.Self.RequestSit(target, Vector3.Zero);
client.Self.Sit();
}
else
{
//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 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;
OpenMetaverse.Utils.LongToUInts(sim.Handle, out globalX, out globalY);
return new Vector3d(
(double)globalX + (double)pos.X,
(double)globalY + (double)pos.Y,
(double)pos.Z);
}
public Vector3d GlobalPosition(Primitive prim)
{
return GlobalPosition(client.Network.CurrentSim, prim.Position);
}
private System.Timers.Timer beamTimer;
private List<Vector3d> beamTarget;
private Random beamRandom = new Random();
private UUID pointID;
private UUID sphereID;
private List<UUID> beamID;
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;
public void UnSetPointing()
{
beamTimer.Enabled = false;
if (pointID != UUID.Zero)
{
client.Self.PointAtEffect(client.Self.AgentID, UUID.Zero, Vector3d.Zero, PointAtType.None, pointID);
pointID = UUID.Zero;
}
if (beamID != null)
{
foreach (UUID id in beamID)
{
client.Self.BeamEffect(UUID.Zero, UUID.Zero, Vector3d.Zero, new Color4(255, 255, 255, 255), 0, id);
}
beamID = null;
}
if (sphereID != UUID.Zero)
{
client.Self.SphereEffect(Vector3d.Zero, Color4.White, 0, sphereID);
sphereID = UUID.Zero;
}
}
void beamTimer_Elapsed(object sender, EventArgs e)
{
if (beamID == null) return;
try
{
client.Self.SphereEffect(GlobalPosition(targetPrim), beamColors[beamRandom.Next(0, 3)], 0.85f, sphereID);
int i = 0;
for (i = 0; i < numBeans; i++)
{
UUID newBeam = UUID.Random();
Vector3d scatter;
if (i == 0)
{
scatter = GlobalPosition(targetPrim);
}
else
{
Vector3d direction = client.Self.GlobalPosition - GlobalPosition(targetPrim);
Vector3d cross = direction % new Vector3d(0, 0, 1);
cross.Normalize();
scatter = GlobalPosition(targetPrim) + cross * (i * 0.2d) * (i % 2 == 0 ? 1 : -1);
}
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++)
{
UUID newBeam = UUID.Random();
Vector3d scatter;
Vector3d cross = new Vector3d(0, 0, 1);
cross.Normalize();
scatter = GlobalPosition(targetPrim) + cross * (j * 0.2d) * (j % 2 == 0 ? 1 : -1);
client.Self.BeamEffect(client.Self.AgentID, UUID.Zero, scatter, beamColors[beamRandom.Next(0, 3)], 1.0f, beamID[j + i - 1]);
}
}
catch (Exception) { };
}
public void SetPointing(Primitive prim, int numBeans)
{
UnSetPointing();
client.Self.Movement.TurnToward(prim.Position);
pointID = UUID.Random();
sphereID = UUID.Random();
beamID = new List<UUID>();
beamTarget = new List<Vector3d>();
targetPrim = prim;
this.numBeans = numBeans;
client.Self.PointAtEffect(client.Self.AgentID, prim.ID, Vector3d.Zero, PointAtType.Select, pointID);
for (int i = 0; i < numBeans; i++)
{
UUID newBeam = UUID.Random();
beamID.Add(newBeam);
beamTarget.Add(Vector3d.Zero);
}
for (int i = 1; i < numBeans; i++)
{
UUID newBeam = UUID.Random();
beamID.Add(newBeam);
beamTarget.Add(Vector3d.Zero);
}
beamTimer.Interval = 1000;
beamTimer.Enabled = true;
}
public UUID TypingAnimationID
{
get { return typingAnimationID; }
set { typingAnimationID = value; }
}
public UUID AwayAnimationID
{
get { return awayAnimationID; }
set { awayAnimationID = value; }
}
public UUID BusyAnimationID
{
get { return busyAnimationID; }
set { busyAnimationID = value; }
}
public bool IsTyping
{
get { return typing; }
}
public bool IsAway
{
get
{
if (UseMoveControl) return client.Self.Movement.Away;
return away;
}
}
public bool IsBusy
{
get { return busy; }
}
public bool IsFlying
{
get { return client.Self.Movement.Fly; }
}
public bool IsSitting
{
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
{
get { return pointID != UUID.Zero; }
}
public bool IsFollowing
{
get { return following; }
}
public string FollowName
{
get { return followName; }
set { followName = value; }
}
public float FollowDistance
{
get { return followDistance; }
set { followDistance = value; }
}
public bool IsWalking
{
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;
}
}
}