//
// Radegast Metaverse Client
-// Copyright (c) 2009-2010, Radegast Development Team
+// Copyright (c) 2009-2014, Radegast Development Team
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
using System.Collections.Generic;
using System.Timers;
using System.Threading;
+
using OpenMetaverse;
+
+using Radegast.Automation;
using Radegast.Netcom;
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;
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");
internal static Random rnd = new Random();
private System.Threading.Timer lookAtTimer;
+ public float FOVVerticalAngle = Utils.TWO_PI - 0.05f;
+
/// <summary>
/// Passes walk state
/// </summary>
}
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;
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()
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)
{
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));
/// 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;
-
- // First try the objecct tracker
- for (int i = 0; i < client.Network.Simulators.Count; i++)
+ Primitive avi = null;
+
+ // 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)
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;
}
}
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);
}
}
+ 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)
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);
}
}
+ 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;
/// </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),
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)
{
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)
{
EndWalking();
return;
}
- walkTimer.Change(walkChekInterval, Timeout.Infinite);
+ if (walkTimer != null) walkTimer.Change(walkChekInterval, Timeout.Infinite);
}
}
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();
}
}
awayAnim.Add(awayAnimationID, away);
client.Self.Animate(awayAnim, true);
+ if (UseMoveControl) client.Self.Movement.Away = away;
this.away = away;
}
}
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)
public void StopAllAnimations()
{
- Dictionary<UUID, bool> stop = new Dictionary<UUID,bool>();
-
+ Dictionary<UUID, bool> stop = new Dictionary<UUID, bool>();
+
client.Self.SignaledAnimations.ForEach((UUID anim) =>
{
if (!KnownAnimations.ContainsKey(anim))
}
}
- 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);
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;
}
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++)
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) { };
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++)
{
set { busyAnimationID = value; }
}
- public UUID EffectSource
- {
- get { return effectSource; }
- set { effectSource = value; }
- }
-
public bool IsTyping
{
get { return typing; }
public bool IsAway
{
- get { return away; }
+ get
+ {
+ if (UseMoveControl) return client.Self.Movement.Away;
+ return away;
+ }
}
public bool IsBusy
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
{
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