diff --git a/LibreMetaverse/AgentManagerMovement.cs b/LibreMetaverse/AgentManagerMovement.cs
index 08bc45cb..b67128b0 100644
--- a/LibreMetaverse/AgentManagerMovement.cs
+++ b/LibreMetaverse/AgentManagerMovement.cs
@@ -1,744 +1,744 @@
-/*
- * Copyright (c) 2006-2016, openmetaverse.co
- * 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.
- * - Neither the name of the openmetaverse.co 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 OWNER 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.
- */
-
-using System;
-using System.Threading;
-using OpenMetaverse.Packets;
-
-namespace OpenMetaverse
-{
- public partial class AgentManager
- {
- #region Enums
-
- ///
- /// Used to specify movement actions for your agent
- ///
- [Flags]
- public enum ControlFlags
- {
- /// Empty flag
- NONE = 0,
- /// Move Forward (SL Keybinding: W/Up Arrow)
- AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX,
- /// Move Backward (SL Keybinding: S/Down Arrow)
- AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX,
- /// Move Left (SL Keybinding: Shift-(A/Left Arrow))
- AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX,
- /// Move Right (SL Keybinding: Shift-(D/Right Arrow))
- AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX,
- /// Not Flying: Jump/Flying: Move Up (SL Keybinding: E)
- AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX,
- /// Not Flying: Croutch/Flying: Move Down (SL Keybinding: C)
- AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX,
- /// Unused
- AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX,
- /// Unused
- AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX,
- /// Unused
- AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX,
- /// Unused
- AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX,
- /// ORed with AGENT_CONTROL_AT_* if the keyboard is being used
- AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX,
- /// ORed with AGENT_CONTROL_LEFT_* if the keyboard is being used
- AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX,
- /// ORed with AGENT_CONTROL_UP_* if the keyboard is being used
- AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX,
- /// Fly
- AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX,
- ///
- AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX,
- /// Finish our current animation
- AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX,
- /// Stand up from the ground or a prim seat
- AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX,
- /// Sit on the ground at our current location
- AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX,
- /// Whether mouselook is currently enabled
- AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX,
- /// Legacy, used if a key was pressed for less than a certain amount of time
- AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX,
- /// Legacy, used if a key was pressed for less than a certain amount of time
- AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX,
- /// Legacy, used if a key was pressed for less than a certain amount of time
- AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX,
- /// Legacy, used if a key was pressed for less than a certain amount of time
- AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX,
- /// Legacy, used if a key was pressed for less than a certain amount of time
- AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX,
- /// Legacy, used if a key was pressed for less than a certain amount of time
- AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX,
- ///
- AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX,
- ///
- AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX,
- /// Set when the avatar is idled or set to away. Note that the away animation is
- /// activated separately from setting this flag
- AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX,
- ///
- AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX,
- ///
- AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX,
- ///
- AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX,
- ///
- AGENT_CONTROL_ML_LBUTTON_UP = 0x1 << CONTROL_ML_LBUTTON_UP_INDEX
- }
-
- #endregion Enums
-
- #region AgentUpdate Constants
-
- private const int CONTROL_AT_POS_INDEX = 0;
- private const int CONTROL_AT_NEG_INDEX = 1;
- private const int CONTROL_LEFT_POS_INDEX = 2;
- private const int CONTROL_LEFT_NEG_INDEX = 3;
- private const int CONTROL_UP_POS_INDEX = 4;
- private const int CONTROL_UP_NEG_INDEX = 5;
- private const int CONTROL_PITCH_POS_INDEX = 6;
- private const int CONTROL_PITCH_NEG_INDEX = 7;
- private const int CONTROL_YAW_POS_INDEX = 8;
- private const int CONTROL_YAW_NEG_INDEX = 9;
- private const int CONTROL_FAST_AT_INDEX = 10;
- private const int CONTROL_FAST_LEFT_INDEX = 11;
- private const int CONTROL_FAST_UP_INDEX = 12;
- private const int CONTROL_FLY_INDEX = 13;
- private const int CONTROL_STOP_INDEX = 14;
- private const int CONTROL_FINISH_ANIM_INDEX = 15;
- private const int CONTROL_STAND_UP_INDEX = 16;
- private const int CONTROL_SIT_ON_GROUND_INDEX = 17;
- private const int CONTROL_MOUSELOOK_INDEX = 18;
- private const int CONTROL_NUDGE_AT_POS_INDEX = 19;
- private const int CONTROL_NUDGE_AT_NEG_INDEX = 20;
- private const int CONTROL_NUDGE_LEFT_POS_INDEX = 21;
- private const int CONTROL_NUDGE_LEFT_NEG_INDEX = 22;
- private const int CONTROL_NUDGE_UP_POS_INDEX = 23;
- private const int CONTROL_NUDGE_UP_NEG_INDEX = 24;
- private const int CONTROL_TURN_LEFT_INDEX = 25;
- private const int CONTROL_TURN_RIGHT_INDEX = 26;
- private const int CONTROL_AWAY_INDEX = 27;
- private const int CONTROL_LBUTTON_DOWN_INDEX = 28;
- private const int CONTROL_LBUTTON_UP_INDEX = 29;
- private const int CONTROL_ML_LBUTTON_DOWN_INDEX = 30;
- private const int CONTROL_ML_LBUTTON_UP_INDEX = 31;
- private const int TOTAL_CONTROLS = 32;
-
- #endregion AgentUpdate Constants
-
- ///
- /// Agent movement and camera control
- ///
- /// Agent movement is controlled by setting specific
- /// After the control flags are set, An AgentUpdate is required to update the simulator of the specified flags
- /// This is most easily accomplished by setting one or more of the AgentMovement properties
- ///
- /// Movement of an avatar is always based on a compass direction, for example AtPos will move the
- /// agent from West to East or forward on the X Axis, AtNeg will of course move agent from
- /// East to West or backward on the X Axis, LeftPos will be South to North or forward on the Y Axis
- /// The Z axis is Up, finer grained control of movements can be done using the Nudge properties
- ///
- public partial class AgentMovement
- {
- #region Properties
-
- /// Move agent positive along the X axis
- public bool AtPos
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS, value); }
- }
- /// Move agent negative along the X axis
- public bool AtNeg
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG, value); }
- }
- /// Move agent positive along the Y axis
- public bool LeftPos
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS, value); }
- }
- /// Move agent negative along the Y axis
- public bool LeftNeg
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG, value); }
- }
- /// Move agent positive along the Z axis
- public bool UpPos
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_POS); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, value); }
- }
- /// Move agent negative along the Z axis
- public bool UpNeg
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, value); }
- }
- ///
- public bool PitchPos
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_POS); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_POS, value); }
- }
- ///
- public bool PitchNeg
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_NEG); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_NEG, value); }
- }
- ///
- public bool YawPos
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS, value); }
- }
- ///
- public bool YawNeg
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG, value); }
- }
- ///
- public bool FastAt
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT, value); }
- }
- ///
- public bool FastLeft
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_LEFT); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_LEFT, value); }
- }
- ///
- public bool FastUp
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_UP); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_UP, value); }
- }
- /// Causes simulator to make agent fly
- public bool Fly
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FLY); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FLY, value); }
- }
- /// Stop movement
- public bool Stop
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STOP); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STOP, value); }
- }
- /// Finish animation
- public bool FinishAnim
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM, value); }
- }
- /// Stand up from a sit
- public bool StandUp
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP, value); }
- }
- /// Tells simulator to sit agent on ground
- public bool SitOnGround
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND, value); }
- }
- /// Place agent into mouselook mode
- public bool Mouselook
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK, value); }
- }
- /// Nudge agent positive along the X axis
- public bool NudgeAtPos
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, value); }
- }
- /// Nudge agent negative along the X axis
- public bool NudgeAtNeg
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, value); }
- }
- /// Nudge agent positive along the Y axis
- public bool NudgeLeftPos
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS, value); }
- }
- /// Nudge agent negative along the Y axis
- public bool NudgeLeftNeg
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG, value); }
- }
- /// Nudge agent positive along the Z axis
- public bool NudgeUpPos
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS, value); }
- }
- /// Nudge agent negative along the Z axis
- public bool NudgeUpNeg
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG, value); }
- }
- ///
- public bool TurnLeft
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT, value); }
- }
- ///
- public bool TurnRight
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT, value); }
- }
- /// Tell simulator to mark agent as away
- public bool Away
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AWAY); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AWAY, value); }
- }
- ///
- public bool LButtonDown
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN, value); }
- }
- ///
- public bool LButtonUp
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP, value); }
- }
- ///
- public bool MLButtonDown
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN, value); }
- }
- ///
- public bool MLButtonUp
- {
- get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP); }
- set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP, value); }
- }
- ///
- /// Returns "always run" value, or changes it by sending a SetAlwaysRunPacket
- ///
- public bool AlwaysRun
- {
- get
- {
- return alwaysRun;
- }
- set
- {
- alwaysRun = value;
- SetAlwaysRunPacket run = new SetAlwaysRunPacket();
- run.AgentData.AgentID = Client.Self.AgentID;
- run.AgentData.SessionID = Client.Self.SessionID;
- run.AgentData.AlwaysRun = alwaysRun;
- Client.Network.SendPacket(run);
- }
- }
- /// The current value of the agent control flags
- public uint AgentControls { get; private set; }
-
- /// Gets or sets the interval in milliseconds at which
- /// AgentUpdate packets are sent to the current simulator. Setting
- /// this to a non-zero value will also enable the packet sending if
- /// it was previously off, and setting it to zero will disable
- public int UpdateInterval
- {
- get
- {
- return updateInterval;
- }
- set
- {
- if (value > 0)
- {
- updateTimer?.Change(value, value);
- updateInterval = value;
- }
- else
- {
- updateTimer?.Change(Timeout.Infinite, Timeout.Infinite);
- updateInterval = 0;
- }
- }
- }
- /// Gets or sets whether AgentUpdate packets are sent to
- /// the current simulator
- public bool UpdateEnabled
- {
- get { return (updateInterval != 0); }
- }
-
- /// Reset movement controls every time we send an update
- public bool AutoResetControls { get; set; }
-
- #endregion Properties
-
- /// Agent camera controls
- public AgentCamera Camera;
- /// Currently only used for hiding your group title
- public AgentFlags Flags = AgentFlags.None;
- /// Action state of the avatar, which can currently be
- /// typing and editing
- public AgentState State = AgentState.None;
- ///
- public Quaternion BodyRotation = Quaternion.Identity;
- ///
- public Quaternion HeadRotation = Quaternion.Identity;
-
- #region Change tracking
- ///
- private Quaternion LastBodyRotation;
- ///
- private Quaternion LastHeadRotation;
- ///
- private Vector3 LastCameraCenter;
- ///
- private Vector3 LastCameraXAxis;
- ///
- private Vector3 LastCameraYAxis;
- ///
- private Vector3 LastCameraZAxis;
- ///
- private float LastFar;
- #endregion Change tracking
-
- private bool alwaysRun;
- private GridClient Client;
- private int duplicateCount;
- private AgentState lastState;
- /// Timer for sending AgentUpdate packets
- private Timer updateTimer;
- private int updateInterval;
-
- /// Default constructor
- public AgentMovement(GridClient client)
- {
- Client = client;
- Camera = new AgentCamera();
- Client.Network.LoginProgress += Network_OnConnected;
- Client.Network.Disconnected += Network_OnDisconnected;
- updateInterval = Settings.DEFAULT_AGENT_UPDATE_INTERVAL;
- }
-
- private void CleanupTimer()
- {
- if (updateTimer != null)
- {
- updateTimer.Dispose();
- updateTimer = null;
- }
- }
-
- private void Network_OnDisconnected(object sender, DisconnectedEventArgs e)
- {
- CleanupTimer();
- }
-
- private void Network_OnConnected(object sender, LoginProgressEventArgs e)
- {
- if (e.Status == LoginStatus.Success)
- {
- CleanupTimer();
- updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed), null, updateInterval, updateInterval);
- }
- }
-
- ///
- /// Send an AgentUpdate with the camera set at the current agent
- /// position and pointing towards the heading specified
- ///
- /// Camera rotation in radians
- /// Whether to send the AgentUpdate reliable
- /// or not
- public void UpdateFromHeading(double heading, bool reliable)
- {
- Camera.Position = Client.Self.SimPosition;
- Camera.LookDirection(heading);
-
- BodyRotation.Z = (float)Math.Sin(heading / 2.0d);
- BodyRotation.W = (float)Math.Cos(heading / 2.0d);
- HeadRotation = BodyRotation;
-
- SendUpdate(reliable);
- }
-
- ///
- /// Rotates the avatar body and camera toward a target position.
- /// This will also anchor the camera position on the avatar
- ///
- /// Region coordinates to turn toward
- public bool TurnToward(Vector3 target)
- {
- return TurnToward(target, true);
- }
-
- ///
- /// Rotates the avatar body and camera toward a target position.
- /// This will also anchor the camera position on the avatar
- ///
- /// Region coordinates to turn toward
- /// whether to send update or not
- public bool TurnToward(Vector3 target, bool sendUpdate)
- {
- if (Client.Settings.SEND_AGENT_UPDATES)
- {
- Quaternion parentRot = Quaternion.Identity;
-
- if (Client.Self.SittingOn > 0)
- {
- if (!Client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(Client.Self.SittingOn))
- {
- Logger.Log("Attempted TurnToward but parent prim is not in dictionary", Helpers.LogLevel.Warning, Client);
- return false;
- }
- else parentRot = Client.Network.CurrentSim.ObjectsPrimitives[Client.Self.SittingOn].Rotation;
- }
-
- Quaternion between = Vector3.RotationBetween(Vector3.UnitX, Vector3.Normalize(target - Client.Self.SimPosition));
- Quaternion rot = between * (Quaternion.Identity / parentRot);
-
- BodyRotation = rot;
- HeadRotation = rot;
- Camera.LookAt(Client.Self.SimPosition, target);
-
- if (sendUpdate) SendUpdate();
-
- return true;
- }
- else
- {
- Logger.Log("Attempted TurnToward but agent updates are disabled", Helpers.LogLevel.Warning, Client);
- return false;
- }
- }
-
- ///
- /// Send new AgentUpdate packet to update our current camera
- /// position and rotation
- ///
- public void SendUpdate()
- {
- SendUpdate(false, Client.Network.CurrentSim);
- }
-
- ///
- /// Send new AgentUpdate packet to update our current camera
- /// position and rotation
- ///
- /// Whether to require server acknowledgement
- /// of this packet
- public void SendUpdate(bool reliable)
- {
- SendUpdate(reliable, Client.Network.CurrentSim);
- }
-
- ///
- /// Send new AgentUpdate packet to update our current camera
- /// position and rotation
- ///
- /// Whether to require server acknowledgement
- /// of this packet
- /// Simulator to send the update to
- public void SendUpdate(bool reliable, Simulator simulator)
- {
- // Since version 1.40.4 of the Linden simulator, sending this update
- // causes corruption of the agent position in the simulator
- if (simulator != null && (!simulator.AgentMovementComplete))
- return;
-
- Vector3 origin = Camera.Position;
- Vector3 xAxis = Camera.LeftAxis;
- Vector3 yAxis = Camera.AtAxis;
- Vector3 zAxis = Camera.UpAxis;
-
- // Attempted to sort these in a rough order of how often they might change
- if (AgentControls == 0 &&
- yAxis == LastCameraYAxis &&
- origin == LastCameraCenter &&
- State == lastState &&
- HeadRotation == LastHeadRotation &&
- BodyRotation == LastBodyRotation &&
- xAxis == LastCameraXAxis &&
- Camera.Far == LastFar &&
- zAxis == LastCameraZAxis)
- {
- ++duplicateCount;
- }
- else
- {
- duplicateCount = 0;
- }
-
- if (Client.Settings.DISABLE_AGENT_UPDATE_DUPLICATE_CHECK || duplicateCount < 10)
- {
- // Store the current state to do duplicate checking
- LastHeadRotation = HeadRotation;
- LastBodyRotation = BodyRotation;
- LastCameraYAxis = yAxis;
- LastCameraCenter = origin;
- LastCameraXAxis = xAxis;
- LastCameraZAxis = zAxis;
- LastFar = Camera.Far;
- lastState = State;
-
- // Build the AgentUpdate packet and send it
- AgentUpdatePacket update = new AgentUpdatePacket();
- update.Header.Reliable = reliable;
-
- update.AgentData.AgentID = Client.Self.AgentID;
- update.AgentData.SessionID = Client.Self.SessionID;
- update.AgentData.HeadRotation = HeadRotation;
- update.AgentData.BodyRotation = BodyRotation;
- update.AgentData.CameraAtAxis = xAxis;
- update.AgentData.CameraCenter = origin;
- update.AgentData.CameraLeftAxis = yAxis;
- update.AgentData.CameraUpAxis = zAxis;
- update.AgentData.Far = Camera.Far;
- update.AgentData.State = (byte)State;
- update.AgentData.ControlFlags = AgentControls;
- update.AgentData.Flags = (byte)Flags;
-
- Client.Network.SendPacket(update, simulator);
-
- if (AutoResetControls) {
- ResetControlFlags();
- }
- }
- }
-
- ///
- /// Builds an AgentUpdate packet entirely from parameters. This
- /// will not touch the state of Self.Movement or
- /// Self.Movement.Camera in any way
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public void SendManualUpdate(AgentManager.ControlFlags controlFlags, Vector3 position, Vector3 forwardAxis,
- Vector3 leftAxis, Vector3 upAxis, Quaternion bodyRotation, Quaternion headRotation, float farClip,
- AgentFlags flags, AgentState state, bool reliable)
- {
- // Since version 1.40.4 of the Linden simulator, sending this update
- // causes corruption of the agent position in the simulator
- if (Client.Network.CurrentSim != null && (!Client.Network.CurrentSim.HandshakeComplete))
- return;
-
- AgentUpdatePacket update = new AgentUpdatePacket();
-
- update.AgentData.AgentID = Client.Self.AgentID;
- update.AgentData.SessionID = Client.Self.SessionID;
- update.AgentData.BodyRotation = bodyRotation;
- update.AgentData.HeadRotation = headRotation;
- update.AgentData.CameraCenter = position;
- update.AgentData.CameraAtAxis = forwardAxis;
- update.AgentData.CameraLeftAxis = leftAxis;
- update.AgentData.CameraUpAxis = upAxis;
- update.AgentData.Far = farClip;
- update.AgentData.ControlFlags = (uint)controlFlags;
- update.AgentData.Flags = (byte)flags;
- update.AgentData.State = (byte)state;
-
- update.Header.Reliable = reliable;
-
- Client.Network.SendPacket(update);
- }
-
- private bool GetControlFlag(ControlFlags flag)
- {
- return (AgentControls & (uint)flag) != 0;
- }
-
- private void SetControlFlag(ControlFlags flag, bool value)
- {
- if (value) AgentControls |= (uint)flag;
- else AgentControls &= ~((uint)flag);
- }
-
- public void ResetControlFlags()
- {
- // Reset all of the flags except for persistent settings like
- // away, fly, mouselook, and crouching
- AgentControls &=
- (uint)(ControlFlags.AGENT_CONTROL_AWAY |
- ControlFlags.AGENT_CONTROL_FLY |
- ControlFlags.AGENT_CONTROL_MOUSELOOK |
- ControlFlags.AGENT_CONTROL_UP_NEG);
- }
-
-
- ///
- /// Sends update of Field of Vision vertical angle to the simulator
- ///
- /// Angle in radians
- public void SetFOVVerticalAngle(float angle)
- {
- OpenMetaverse.Packets.AgentFOVPacket msg = new OpenMetaverse.Packets.AgentFOVPacket();
- msg.AgentData.AgentID = Client.Self.AgentID;
- msg.AgentData.SessionID = Client.Self.SessionID;
- msg.AgentData.CircuitCode = Client.Network.CircuitCode;
- msg.FOVBlock.GenCounter = 0;
- msg.FOVBlock.VerticalAngle = angle;
- Client.Network.SendPacket(msg);
- }
-
- private void UpdateTimer_Elapsed(object obj)
- {
- if (Client.Network.Connected && Client.Settings.SEND_AGENT_UPDATES)
- {
- //Send an AgentUpdate packet
- SendUpdate(false, Client.Network.CurrentSim);
- }
- }
- }
- }
-}
+/*
+ * Copyright (c) 2006-2016, openmetaverse.co
+ * 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.
+ * - Neither the name of the openmetaverse.co 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 OWNER 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.
+ */
+
+using System;
+using System.Threading;
+using OpenMetaverse.Packets;
+
+namespace OpenMetaverse
+{
+ public partial class AgentManager
+ {
+ #region Enums
+
+ ///
+ /// Used to specify movement actions for your agent
+ ///
+ [Flags]
+ public enum ControlFlags
+ {
+ /// Empty flag
+ NONE = 0,
+ /// Move Forward (SL Keybinding: W/Up Arrow)
+ AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX,
+ /// Move Backward (SL Keybinding: S/Down Arrow)
+ AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX,
+ /// Move Left (SL Keybinding: Shift-(A/Left Arrow))
+ AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX,
+ /// Move Right (SL Keybinding: Shift-(D/Right Arrow))
+ AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX,
+ /// Not Flying: Jump/Flying: Move Up (SL Keybinding: E)
+ AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX,
+ /// Not Flying: Croutch/Flying: Move Down (SL Keybinding: C)
+ AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX,
+ /// Unused
+ AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX,
+ /// Unused
+ AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX,
+ /// Unused
+ AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX,
+ /// Unused
+ AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX,
+ /// ORed with AGENT_CONTROL_AT_* if the keyboard is being used
+ AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX,
+ /// ORed with AGENT_CONTROL_LEFT_* if the keyboard is being used
+ AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX,
+ /// ORed with AGENT_CONTROL_UP_* if the keyboard is being used
+ AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX,
+ /// Fly
+ AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX,
+ ///
+ AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX,
+ /// Finish our current animation
+ AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX,
+ /// Stand up from the ground or a prim seat
+ AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX,
+ /// Sit on the ground at our current location
+ AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX,
+ /// Whether mouselook is currently enabled
+ AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX,
+ /// Legacy, used if a key was pressed for less than a certain amount of time
+ AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX,
+ /// Legacy, used if a key was pressed for less than a certain amount of time
+ AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX,
+ /// Legacy, used if a key was pressed for less than a certain amount of time
+ AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX,
+ /// Legacy, used if a key was pressed for less than a certain amount of time
+ AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX,
+ /// Legacy, used if a key was pressed for less than a certain amount of time
+ AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX,
+ /// Legacy, used if a key was pressed for less than a certain amount of time
+ AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX,
+ ///
+ AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX,
+ ///
+ AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX,
+ /// Set when the avatar is idled or set to away. Note that the away animation is
+ /// activated separately from setting this flag
+ AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX,
+ ///
+ AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX,
+ ///
+ AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX,
+ ///
+ AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX,
+ ///
+ AGENT_CONTROL_ML_LBUTTON_UP = 0x1 << CONTROL_ML_LBUTTON_UP_INDEX
+ }
+
+ #endregion Enums
+
+ #region AgentUpdate Constants
+
+ private const int CONTROL_AT_POS_INDEX = 0;
+ private const int CONTROL_AT_NEG_INDEX = 1;
+ private const int CONTROL_LEFT_POS_INDEX = 2;
+ private const int CONTROL_LEFT_NEG_INDEX = 3;
+ private const int CONTROL_UP_POS_INDEX = 4;
+ private const int CONTROL_UP_NEG_INDEX = 5;
+ private const int CONTROL_PITCH_POS_INDEX = 6;
+ private const int CONTROL_PITCH_NEG_INDEX = 7;
+ private const int CONTROL_YAW_POS_INDEX = 8;
+ private const int CONTROL_YAW_NEG_INDEX = 9;
+ private const int CONTROL_FAST_AT_INDEX = 10;
+ private const int CONTROL_FAST_LEFT_INDEX = 11;
+ private const int CONTROL_FAST_UP_INDEX = 12;
+ private const int CONTROL_FLY_INDEX = 13;
+ private const int CONTROL_STOP_INDEX = 14;
+ private const int CONTROL_FINISH_ANIM_INDEX = 15;
+ private const int CONTROL_STAND_UP_INDEX = 16;
+ private const int CONTROL_SIT_ON_GROUND_INDEX = 17;
+ private const int CONTROL_MOUSELOOK_INDEX = 18;
+ private const int CONTROL_NUDGE_AT_POS_INDEX = 19;
+ private const int CONTROL_NUDGE_AT_NEG_INDEX = 20;
+ private const int CONTROL_NUDGE_LEFT_POS_INDEX = 21;
+ private const int CONTROL_NUDGE_LEFT_NEG_INDEX = 22;
+ private const int CONTROL_NUDGE_UP_POS_INDEX = 23;
+ private const int CONTROL_NUDGE_UP_NEG_INDEX = 24;
+ private const int CONTROL_TURN_LEFT_INDEX = 25;
+ private const int CONTROL_TURN_RIGHT_INDEX = 26;
+ private const int CONTROL_AWAY_INDEX = 27;
+ private const int CONTROL_LBUTTON_DOWN_INDEX = 28;
+ private const int CONTROL_LBUTTON_UP_INDEX = 29;
+ private const int CONTROL_ML_LBUTTON_DOWN_INDEX = 30;
+ private const int CONTROL_ML_LBUTTON_UP_INDEX = 31;
+ private const int TOTAL_CONTROLS = 32;
+
+ #endregion AgentUpdate Constants
+
+ ///
+ /// Agent movement and camera control
+ ///
+ /// Agent movement is controlled by setting specific
+ /// After the control flags are set, An AgentUpdate is required to update the simulator of the specified flags
+ /// This is most easily accomplished by setting one or more of the AgentMovement properties
+ ///
+ /// Movement of an avatar is always based on a compass direction, for example AtPos will move the
+ /// agent from West to East or forward on the X Axis, AtNeg will of course move agent from
+ /// East to West or backward on the X Axis, LeftPos will be South to North or forward on the Y Axis
+ /// The Z axis is Up, finer grained control of movements can be done using the Nudge properties
+ ///
+ public partial class AgentMovement
+ {
+ #region Properties
+
+ /// Move agent positive along the X axis
+ public bool AtPos
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_POS, value); }
+ }
+ /// Move agent negative along the X axis
+ public bool AtNeg
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG, value); }
+ }
+ /// Move agent positive along the Y axis
+ public bool LeftPos
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS, value); }
+ }
+ /// Move agent negative along the Y axis
+ public bool LeftNeg
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG, value); }
+ }
+ /// Move agent positive along the Z axis
+ public bool UpPos
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_POS); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, value); }
+ }
+ /// Move agent negative along the Z axis
+ public bool UpNeg
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, value); }
+ }
+ ///
+ public bool PitchPos
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_POS); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_POS, value); }
+ }
+ ///
+ public bool PitchNeg
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_NEG); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_PITCH_NEG, value); }
+ }
+ ///
+ public bool YawPos
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS, value); }
+ }
+ ///
+ public bool YawNeg
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG, value); }
+ }
+ ///
+ public bool FastAt
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_AT, value); }
+ }
+ ///
+ public bool FastLeft
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_LEFT); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_LEFT, value); }
+ }
+ ///
+ public bool FastUp
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_UP); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FAST_UP, value); }
+ }
+ /// Causes simulator to make agent fly
+ public bool Fly
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FLY); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FLY, value); }
+ }
+ /// Stop movement
+ public bool Stop
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STOP); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STOP, value); }
+ }
+ /// Finish animation
+ public bool FinishAnim
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_FINISH_ANIM, value); }
+ }
+ /// Stand up from a sit
+ public bool StandUp
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP, value); }
+ }
+ /// Tells simulator to sit agent on ground
+ public bool SitOnGround
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND, value); }
+ }
+ /// Place agent into mouselook mode
+ public bool Mouselook
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK, value); }
+ }
+ /// Nudge agent positive along the X axis
+ public bool NudgeAtPos
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, value); }
+ }
+ /// Nudge agent negative along the X axis
+ public bool NudgeAtNeg
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, value); }
+ }
+ /// Nudge agent positive along the Y axis
+ public bool NudgeLeftPos
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS, value); }
+ }
+ /// Nudge agent negative along the Y axis
+ public bool NudgeLeftNeg
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG, value); }
+ }
+ /// Nudge agent positive along the Z axis
+ public bool NudgeUpPos
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS, value); }
+ }
+ /// Nudge agent negative along the Z axis
+ public bool NudgeUpNeg
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG, value); }
+ }
+ ///
+ public bool TurnLeft
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT, value); }
+ }
+ ///
+ public bool TurnRight
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT, value); }
+ }
+ /// Tell simulator to mark agent as away
+ public bool Away
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AWAY); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_AWAY, value); }
+ }
+ ///
+ public bool LButtonDown
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN, value); }
+ }
+ ///
+ public bool LButtonUp
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP, value); }
+ }
+ ///
+ public bool MLButtonDown
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN, value); }
+ }
+ ///
+ public bool MLButtonUp
+ {
+ get { return GetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP); }
+ set { SetControlFlag(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP, value); }
+ }
+ ///
+ /// Returns "always run" value, or changes it by sending a SetAlwaysRunPacket
+ ///
+ public bool AlwaysRun
+ {
+ get
+ {
+ return alwaysRun;
+ }
+ set
+ {
+ alwaysRun = value;
+ SetAlwaysRunPacket run = new SetAlwaysRunPacket();
+ run.AgentData.AgentID = Client.Self.AgentID;
+ run.AgentData.SessionID = Client.Self.SessionID;
+ run.AgentData.AlwaysRun = alwaysRun;
+ Client.Network.SendPacket(run);
+ }
+ }
+ /// The current value of the agent control flags
+ public uint AgentControls { get; private set; }
+
+ /// Gets or sets the interval in milliseconds at which
+ /// AgentUpdate packets are sent to the current simulator. Setting
+ /// this to a non-zero value will also enable the packet sending if
+ /// it was previously off, and setting it to zero will disable
+ public int UpdateInterval
+ {
+ get
+ {
+ return updateInterval;
+ }
+ set
+ {
+ if (value > 0)
+ {
+ updateTimer?.Change(value, value);
+ updateInterval = value;
+ }
+ else
+ {
+ updateTimer?.Change(Timeout.Infinite, Timeout.Infinite);
+ updateInterval = 0;
+ }
+ }
+ }
+ /// Gets or sets whether AgentUpdate packets are sent to
+ /// the current simulator
+ public bool UpdateEnabled
+ {
+ get { return (updateInterval != 0); }
+ }
+
+ /// Reset movement controls every time we send an update
+ public bool AutoResetControls { get; set; }
+
+ #endregion Properties
+
+ /// Agent camera controls
+ public AgentCamera Camera;
+ /// Currently only used for hiding your group title
+ public AgentFlags Flags = AgentFlags.None;
+ /// Action state of the avatar, which can currently be
+ /// typing and editing
+ public AgentState State = AgentState.None;
+ ///
+ public Quaternion BodyRotation = Quaternion.Identity;
+ ///
+ public Quaternion HeadRotation = Quaternion.Identity;
+
+ #region Change tracking
+ ///
+ private Quaternion LastBodyRotation;
+ ///
+ private Quaternion LastHeadRotation;
+ ///
+ private Vector3 LastCameraCenter;
+ ///
+ private Vector3 LastCameraXAxis;
+ ///
+ private Vector3 LastCameraYAxis;
+ ///
+ private Vector3 LastCameraZAxis;
+ ///
+ private float LastFar;
+ #endregion Change tracking
+
+ private bool alwaysRun;
+ private GridClient Client;
+ private int duplicateCount;
+ private AgentState lastState;
+ /// Timer for sending AgentUpdate packets
+ private Timer updateTimer;
+ private int updateInterval;
+
+ /// Default constructor
+ public AgentMovement(GridClient client)
+ {
+ Client = client;
+ Camera = new AgentCamera();
+ Client.Network.LoginProgress += Network_OnConnected;
+ Client.Network.Disconnected += Network_OnDisconnected;
+ updateInterval = Settings.DEFAULT_AGENT_UPDATE_INTERVAL;
+ }
+
+ private void CleanupTimer()
+ {
+ if (updateTimer != null)
+ {
+ updateTimer.Dispose();
+ updateTimer = null;
+ }
+ }
+
+ private void Network_OnDisconnected(object sender, DisconnectedEventArgs e)
+ {
+ CleanupTimer();
+ }
+
+ private void Network_OnConnected(object sender, LoginProgressEventArgs e)
+ {
+ if (e.Status == LoginStatus.Success)
+ {
+ CleanupTimer();
+ updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed), null, updateInterval, updateInterval);
+ }
+ }
+
+ ///
+ /// Send an AgentUpdate with the camera set at the current agent
+ /// position and pointing towards the heading specified
+ ///
+ /// Camera rotation in radians
+ /// Whether to send the AgentUpdate reliable
+ /// or not
+ public void UpdateFromHeading(double heading, bool reliable)
+ {
+ Camera.Position = Client.Self.SimPosition;
+ Camera.LookDirection(heading);
+
+ BodyRotation.Z = (float)Math.Sin(heading / 2.0d);
+ BodyRotation.W = (float)Math.Cos(heading / 2.0d);
+ HeadRotation = BodyRotation;
+
+ SendUpdate(reliable);
+ }
+
+ ///
+ /// Rotates the avatar body and camera toward a target position.
+ /// This will also anchor the camera position on the avatar
+ ///
+ /// Region coordinates to turn toward
+ public bool TurnToward(Vector3 target)
+ {
+ return TurnToward(target, true);
+ }
+
+ ///
+ /// Rotates the avatar body and camera toward a target position.
+ /// This will also anchor the camera position on the avatar
+ ///
+ /// Region coordinates to turn toward
+ /// whether to send update or not
+ public bool TurnToward(Vector3 target, bool sendUpdate)
+ {
+ if (Client.Settings.SEND_AGENT_UPDATES)
+ {
+ Quaternion parentRot = Quaternion.Identity;
+
+ if (Client.Self.SittingOn > 0)
+ {
+ if (!Client.Network.CurrentSim.ObjectsPrimitives.ContainsKey(Client.Self.SittingOn))
+ {
+ Logger.Log("Attempted TurnToward but parent prim is not in dictionary", Helpers.LogLevel.Warning, Client);
+ return false;
+ }
+ else parentRot = Client.Network.CurrentSim.ObjectsPrimitives[Client.Self.SittingOn].Rotation;
+ }
+
+ Quaternion between = Vector3.RotationBetween(Vector3.UnitX, Vector3.Normalize(target - Client.Self.SimPosition));
+ Quaternion rot = between * (Quaternion.Identity / parentRot);
+
+ BodyRotation = rot;
+ HeadRotation = rot;
+ Camera.LookAt(Client.Self.SimPosition, target);
+
+ if (sendUpdate) SendUpdate();
+
+ return true;
+ }
+ else
+ {
+ Logger.Log("Attempted TurnToward but agent updates are disabled", Helpers.LogLevel.Warning, Client);
+ return false;
+ }
+ }
+
+ ///
+ /// Send new AgentUpdate packet to update our current camera
+ /// position and rotation
+ ///
+ public void SendUpdate()
+ {
+ SendUpdate(false, Client.Network.CurrentSim);
+ }
+
+ ///
+ /// Send new AgentUpdate packet to update our current camera
+ /// position and rotation
+ ///
+ /// Whether to require server acknowledgement
+ /// of this packet
+ public void SendUpdate(bool reliable)
+ {
+ SendUpdate(reliable, Client.Network.CurrentSim);
+ }
+
+ ///
+ /// Send new AgentUpdate packet to update our current camera
+ /// position and rotation
+ ///
+ /// Whether to require server acknowledgement
+ /// of this packet
+ /// Simulator to send the update to
+ public void SendUpdate(bool reliable, Simulator simulator)
+ {
+ // Since version 1.40.4 of the Linden simulator, sending this update
+ // causes corruption of the agent position in the simulator
+ if (simulator != null && (!simulator.AgentMovementComplete))
+ return;
+
+ Vector3 origin = Camera.Position;
+ Vector3 xAxis = Camera.LeftAxis;
+ Vector3 yAxis = Camera.AtAxis;
+ Vector3 zAxis = Camera.UpAxis;
+
+ // Attempted to sort these in a rough order of how often they might change
+ if (AgentControls == 0 &&
+ yAxis == LastCameraYAxis &&
+ origin == LastCameraCenter &&
+ State == lastState &&
+ HeadRotation == LastHeadRotation &&
+ BodyRotation == LastBodyRotation &&
+ xAxis == LastCameraXAxis &&
+ Camera.Far == LastFar &&
+ zAxis == LastCameraZAxis)
+ {
+ ++duplicateCount;
+ }
+ else
+ {
+ duplicateCount = 0;
+ }
+
+ if (Client.Settings.DISABLE_AGENT_UPDATE_DUPLICATE_CHECK || duplicateCount < 10)
+ {
+ // Store the current state to do duplicate checking
+ LastHeadRotation = HeadRotation;
+ LastBodyRotation = BodyRotation;
+ LastCameraYAxis = yAxis;
+ LastCameraCenter = origin;
+ LastCameraXAxis = xAxis;
+ LastCameraZAxis = zAxis;
+ LastFar = Camera.Far;
+ lastState = State;
+
+ // Build the AgentUpdate packet and send it
+ AgentUpdatePacket update = new AgentUpdatePacket();
+ update.Header.Reliable = reliable;
+
+ update.AgentData.AgentID = Client.Self.AgentID;
+ update.AgentData.SessionID = Client.Self.SessionID;
+ update.AgentData.HeadRotation = HeadRotation;
+ update.AgentData.BodyRotation = BodyRotation;
+ update.AgentData.CameraAtAxis = xAxis;
+ update.AgentData.CameraCenter = origin;
+ update.AgentData.CameraLeftAxis = yAxis;
+ update.AgentData.CameraUpAxis = zAxis;
+ update.AgentData.Far = Camera.Far;
+ update.AgentData.State = (byte)State;
+ update.AgentData.ControlFlags = AgentControls;
+ update.AgentData.Flags = (byte)Flags;
+
+ Client.Network.SendPacket(update, simulator);
+
+ if (AutoResetControls) {
+ ResetControlFlags();
+ }
+ }
+ }
+
+ ///
+ /// Builds an AgentUpdate packet entirely from parameters. This
+ /// will not touch the state of Self.Movement or
+ /// Self.Movement.Camera in any way
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void SendManualUpdate(AgentManager.ControlFlags controlFlags, Vector3 position, Vector3 forwardAxis,
+ Vector3 leftAxis, Vector3 upAxis, Quaternion bodyRotation, Quaternion headRotation, float farClip,
+ AgentFlags flags, AgentState state, bool reliable)
+ {
+ // Since version 1.40.4 of the Linden simulator, sending this update
+ // causes corruption of the agent position in the simulator
+ if (Client.Network.CurrentSim != null && (!Client.Network.CurrentSim.HandshakeComplete))
+ return;
+
+ AgentUpdatePacket update = new AgentUpdatePacket();
+
+ update.AgentData.AgentID = Client.Self.AgentID;
+ update.AgentData.SessionID = Client.Self.SessionID;
+ update.AgentData.BodyRotation = bodyRotation;
+ update.AgentData.HeadRotation = headRotation;
+ update.AgentData.CameraCenter = position;
+ update.AgentData.CameraAtAxis = forwardAxis;
+ update.AgentData.CameraLeftAxis = leftAxis;
+ update.AgentData.CameraUpAxis = upAxis;
+ update.AgentData.Far = farClip;
+ update.AgentData.ControlFlags = (uint)controlFlags;
+ update.AgentData.Flags = (byte)flags;
+ update.AgentData.State = (byte)state;
+
+ update.Header.Reliable = reliable;
+
+ Client.Network.SendPacket(update);
+ }
+
+ private bool GetControlFlag(ControlFlags flag)
+ {
+ return (AgentControls & (uint)flag) != 0;
+ }
+
+ private void SetControlFlag(ControlFlags flag, bool value)
+ {
+ if (value) AgentControls |= (uint)flag;
+ else AgentControls &= ~((uint)flag);
+ }
+
+ public void ResetControlFlags()
+ {
+ // Reset all of the flags except for persistent settings like
+ // away, fly, mouselook, and crouching
+ AgentControls &=
+ (uint)(ControlFlags.AGENT_CONTROL_AWAY |
+ ControlFlags.AGENT_CONTROL_FLY |
+ ControlFlags.AGENT_CONTROL_MOUSELOOK |
+ ControlFlags.AGENT_CONTROL_UP_NEG);
+ }
+
+
+ ///
+ /// Sends update of Field of Vision vertical angle to the simulator
+ ///
+ /// Angle in radians
+ public void SetFOVVerticalAngle(float angle)
+ {
+ OpenMetaverse.Packets.AgentFOVPacket msg = new OpenMetaverse.Packets.AgentFOVPacket();
+ msg.AgentData.AgentID = Client.Self.AgentID;
+ msg.AgentData.SessionID = Client.Self.SessionID;
+ msg.AgentData.CircuitCode = Client.Network.CircuitCode;
+ msg.FOVBlock.GenCounter = 0;
+ msg.FOVBlock.VerticalAngle = angle;
+ Client.Network.SendPacket(msg);
+ }
+
+ private void UpdateTimer_Elapsed(object obj)
+ {
+ if (Client.Network.Connected && Client.Settings.SEND_AGENT_UPDATES)
+ {
+ //Send an AgentUpdate packet
+ SendUpdate(false, Client.Network.CurrentSim);
+ }
+ }
+ }
+ }
+}
diff --git a/LibreMetaverse/GridManager.cs b/LibreMetaverse/GridManager.cs
index e273a077..7a50f22b 100644
--- a/LibreMetaverse/GridManager.cs
+++ b/LibreMetaverse/GridManager.cs
@@ -93,28 +93,40 @@ public struct GridRegion
/// Access level
public SimAccess Access;
/// Appears to always be zero (None)
- public RegionFlags RegionFlags;
+ public RegionFlags RegionFlags;
/// Water Height
public byte WaterHeight;
///
public byte Agents;
/// UUID of the World Map image
public UUID MapImageID;
- /// Unique identifier for this region, a combination of the X
+ /// Unique identifier for this region, a combination of the X
/// and Y position
public ulong RegionHandle;
-
+ ///
+ ///
+ ///
+ ///
public override string ToString()
{
- return $"{Name} ({X}/{Y}), Handle: {RegionHandle}, MapImage: {MapImageID}, Access: {Access}";
+ return $"{Name} ({X}/{Y}), Handle: {RegionHandle}, MapImage: {MapImageID}, Access: {Access}";
}
+ ///
+ ///
+ ///
+ ///
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
+ ///
+ ///
+ ///
+ ///
+ ///
public override bool Equals(object obj)
{
return (obj is GridRegion region) && Equals(region);
@@ -173,7 +185,7 @@ public ulong RegionHandle
/// Represents an agent or group of agents location
///
public class MapAgentLocation : MapItem
- {
+ {
public int AvatarCount;
public string Identifier;
}
@@ -182,25 +194,25 @@ public class MapAgentLocation : MapItem
/// Represents a Telehub location
///
public class MapTelehub : MapItem
- {
+ {
}
///
/// Represents a non-adult parcel of land for sale
///
public class MapLandForSale : MapItem
- {
+ {
public int Size;
public int Price;
public string Name;
- public UUID ID;
+ public UUID ID;
}
///
/// Represents an Adult parcel of land for sale
///
public class MapAdultLandForSale : MapItem
- {
+ {
public int Size;
public int Price;
public string Name;
@@ -260,7 +272,7 @@ protected virtual void OnCoarseLocationUpdate(CoarseLocationUpdateEventArgs e)
/// Thread sync lock object
private readonly object m_CoarseLocationUpdateLock = new object();
- /// Raised when the simulator sends a
+ /// Raised when the simulator sends a
/// containing the location of agents in the simulator
public event EventHandler CoarseLocationUpdate
{
@@ -283,7 +295,7 @@ protected virtual void OnGridRegion(GridRegionEventArgs e)
/// Thread sync lock object
private readonly object m_GridRegionLock = new object();
- /// Raised when the simulator sends a Region Data in response to
+ /// Raised when the simulator sends a Region Data in response to
/// a Map request
public event EventHandler GridRegion
{
@@ -446,7 +458,7 @@ public void RequestMapRegion(string regionName, GridLayerType layer)
///
///
///
- public void RequestMapBlocks(GridLayerType layer, ushort minX, ushort minY, ushort maxX, ushort maxY,
+ public void RequestMapBlocks(GridLayerType layer, ushort minX, ushort minY, ushort maxX, ushort maxY,
bool returnNonExistent)
{
MapBlockRequestPacket request = new MapBlockRequestPacket
@@ -472,7 +484,7 @@ public void RequestMapBlocks(GridLayerType layer, ushort minX, ushort minY, usho
}
///
- ///
+ ///
///
///
///
@@ -611,7 +623,7 @@ void Callback(object sender, GridRegionEventArgs e)
return false;
}
}
-
+
protected void MapLayerResponseHandler(HttpResponseMessage response, byte[] responseData, Exception error)
{
if (error != null)
@@ -799,7 +811,7 @@ protected void MapItemReplyHandler(object sender, PacketReceivedEventArgs e)
protected void SimulatorViewerTimeMessageHandler(object sender, PacketReceivedEventArgs e)
{
SimulatorViewerTimeMessagePacket time = (SimulatorViewerTimeMessagePacket)e.Packet;
-
+
SunPhase = time.TimeInfo.SunPhase;
SunDirection = time.TimeInfo.SunDirection;
SunAngVelocity = time.TimeInfo.SunAngVelocity;
@@ -860,7 +872,7 @@ protected void CoarseLocationHandler(object sender, PacketReceivedEventArgs e)
/// The sender
/// The EventArgs object containing the packet data
protected void RegionHandleReplyHandler(object sender, PacketReceivedEventArgs e)
- {
+ {
if (m_RegionHandleReply != null)
{
RegionIDAndHandleReplyPacket reply = (RegionIDAndHandleReplyPacket)e.Packet;
diff --git a/Programs/GridProxy/GridProxyMain.cs b/Programs/GridProxy/GridProxyMain.cs
index 432fef1c..97677a14 100644
--- a/Programs/GridProxy/GridProxyMain.cs
+++ b/Programs/GridProxy/GridProxyMain.cs
@@ -5,8 +5,8 @@ class ProxyMain
public static void Main(string[] args)
{
ProxyFrame p = new ProxyFrame(args);
- ProxyPlugin analyst = new Analyst(p);
- analyst.Init();
- p.proxy.Start();
+ ProxyPlugin analyst = new Analyst(p);
+ analyst.Init();
+ p.proxy.Start();
}
}
\ No newline at end of file
diff --git a/Programs/examples/TestClient/ClientManager.cs b/Programs/examples/TestClient/ClientManager.cs
index f7766d94..e114ac83 100644
--- a/Programs/examples/TestClient/ClientManager.cs
+++ b/Programs/examples/TestClient/ClientManager.cs
@@ -3,25 +3,25 @@
* Copyright (c) 2019-2022, Sjofn, LLC
* All rights reserved.
*
- * - Redistribution and use in source and binary forms, with or without
+ * - 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.
- * - Neither the name of the openmetaverse.co nor the names
+ * - Neither the name of the openmetaverse.co 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 OWNER 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
+ * 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 OWNER 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.
*/
@@ -86,8 +86,8 @@ public TestClient Login(string[] args)
LoginDetails account = new LoginDetails
{
- FirstName = args[0],
- LastName = args[1],
+ FirstName = args[0],
+ LastName = args[1],
Password = args[2]
};
@@ -132,7 +132,7 @@ public TestClient Login(string[] args)
}
///
- /// Login account with provided
+ /// Login account with provided
///
///
///
@@ -189,7 +189,7 @@ void PeopleDirCallback(object sender2, DirPeopleReplyEventArgs dpe)
}
else if (e.Status == LoginStatus.Failed)
{
- Logger.Log($"Failed to login {account.FirstName} {account.LastName}: {client.Network.LoginMessage}",
+ Logger.Log($"Failed to login {account.FirstName} {account.LastName}: {client.Network.LoginMessage}",
Helpers.LogLevel.Warning);
--PendingLogins;
}
@@ -202,7 +202,7 @@ void PeopleDirCallback(object sender2, DirPeopleReplyEventArgs dpe)
client.Throttle.Task = 1000000;
client.GroupCommands = account.GroupCommands;
- client.MasterName = account.MasterName;
+ client.MasterName = account.MasterName;
client.MasterKey = account.MasterKey;
client.AllowObjectMaster = client.MasterKey != UUID.Zero; // Require UUID for object master.
@@ -260,7 +260,7 @@ private void PrintPrompt()
}
///
- ///
+ ///
///
///
///
@@ -272,7 +272,7 @@ public void DoCommandAll(string cmd, UUID fromAgentID)
string[] tokens = cmd.Trim().Split(' ', '\t');
if (tokens.Length == 0)
return;
-
+
string firstToken = tokens[0].ToLower();
if (string.IsNullOrEmpty(firstToken))
return;
@@ -296,7 +296,7 @@ public void DoCommandAll(string cmd, UUID fromAgentID)
}
return;
}
-
+
string[] args = new string[tokens.Length - 1];
if (args.Length > 0)
Array.Copy(tokens, 1, args, 0, args.Length);
diff --git a/Programs/examples/TestClient/TestClient.csproj b/Programs/examples/TestClient/TestClient.csproj
index 140c40b2..2668b23f 100644
--- a/Programs/examples/TestClient/TestClient.csproj
+++ b/Programs/examples/TestClient/TestClient.csproj
@@ -1,4 +1,4 @@
-
+
TestClient
Exe
diff --git a/README.md b/README.md
index 8e95aa97..274376e6 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
```
- _ _ _ __ __ ___ _____ ___ _____ ___ ___ ___
+ _ _ _ __ __ ___ _____ ___ _____ ___ ___ ___
| (_) |__ _ _ ___| \/ | __|_ _/_\ \ / / __| _ \/ __| __|
-| | | '_ \ '_/ -_) |\/| | _| | |/ _ \ V /| _|| /\__ \ _|
+| | | '_ \ '_/ -_) |\/| | _| | |/ _ \ V /| _|| /\__ \ _|
|_|_|_.__/_| \___|_| |_|___| |_/_/ \_\_/ |___|_|_\|___/___|
```
+
# LibreMetaverse
LibreMetaverse is a fork of libOpenMetaverse which in turn was a fork of
@@ -18,45 +19,45 @@ https://github.com/cinderblocks/libremetaverse
### Windows
-The `dotnet` utility is cross-platform so compilation is no different than on Linux/macOS.
-You may, however, opt to use Visual Studio as you would any other .NET application.
+- Make sure you have at least `dotnet` installed, with a valid net6.0/net7.0 SDK _and_ runtime available! (use `dotnet --list-runtimes` and `dotnet --list-sdks` to confirm)
### Linux/macOS
-- Make sure you have at least `dotnet` installed, with a valid SDK _and_ runtime of at least .NET5 available!
+- Make sure you have at least `dotnet` installed, with a valid SDK _and_ runtime of at least .NET5 available!
+
+- This update includes a solution file to skip GUI applications for non-Windows platforms. Use `LibreMetaverse.ReleaseNoGUI.sln` instead
-- This update includes a solution file to skip GUI applications for non-Windows platforms. Use `LibreMetaverse.ReleaseNoGUI.sln` instead
+- From the root, run `dotnet msbuild LibreMetaverse.ReleaseNoGUI.sln`, and enjoy the superfast Roslyn compiler at work 😄
+ It should finish after a few minutes, depending on the speed of your machine.
-- From the root, run `dotnet restore LibreMetaverse.ReleaseNoGUI.sln`. You should get some errors regarding missing Windows libraries;
-that's ok, you can ignore those, they're to be expected since Linux/macOS do _not_ include such libraries. Some test applications are Windows-only.
-If all goes well, you should now have all dependent packages properly installed.
+- Your binaries will be under `../bin/net6.0` or `../bin/net7.0` (there might be a few more directories under `../bin`),
+ depending on what runtimes you have installed on your system. Make sure you `cd` to the correct directory depending on the runtime you have,
+ and then search for all your binaries there: they should be normal-looking executable files (with the `x` attribute set) and having the name
+ of the appropriate test application (e.g. `TestClient` for the interactive testing tool).
-- From the root, run `dotnet msbuild LibreMetaverse.ReleaseNoGUI.sln`, and enjoy the superfast Roslyn compiler at work 😄
-It should finish after a few minutes, depending on the speed of your machine.
+The `dotnet` utility is cross-platform so compilation is no different than on Linux/macOS; if you wish to skip the GUI applications, the instructions are the same as above.
-- Your binaries will be under `../bin/net6.0` or `../bin/net7.0` (there might be a few more directories under `../bin`),
-depending on what runtimes you have installed on your system. Make sure you `cd` to the correct directory depending on the runtime you have,
-and then search for all your binaries there: they should be normal-looking executable files (with the `x` attribute set) and having the name
-of the appropriate test application (e.g. `TestClient` for the interactive testing tool).
+You may, however, opt to use Visual Studio as you would any other .NET application, using the default `LibreMetaverse.sln`.
-- Unlike OpenSimulator and LibOpenMetaverse, you don't need to launch the binaries with Mono, they're _directly_ executable;
-the `dotnet` chain already embeds the small runtime that allows .NET apps to run natively on whatever operating system you've got.
+- Unlike OpenSimulator and LibOpenMetaverse, you don't need to launch the binaries with Mono, they're _directly_ executable;
+ the `dotnet` chain already embeds the small runtime that allows .NET apps to run natively on whatever operating system you've got.
### GUI support under Linux/macOS
-LibreMetaverse.GUI is not available on Linux/macOS due to Microsoft's lack of support for GDI/WinForms on non-Windows platforms.
+LibreMetaverse.GUI is not available on Linux/macOS due to Microsoft's lack of support for GDI/WinForms on non-Windows platforms.
They may work using Mono's implemention and can always be emulated using a product like Wine.
The GUI library is being phased out and eventually being replaced by a more cross-platform framework like Avalonia or MAUI.
-
-[![LibreMetaverse NuGet-Release](https://img.shields.io/nuget/v/libremetaverse.svg?label=LibreMetaverse)](https://www.nuget.org/packages/LibreMetaverse/)
-[![NuGet Downloads](https://img.shields.io/nuget/dt/LibreMetaverse?label=NuGet%20downloads)](https://www.nuget.org/packages/LibreMetaverse/)
-[![Build status](https://ci.appveyor.com/api/projects/status/pga5w0qken2k2nnl?svg=true)](https://ci.appveyor.com/project/cinderblocks57647/libremetaverse-ksbcr)
-[![Test status](https://img.shields.io/appveyor/tests/cinderblocks57647/libremetaverse-ksbcr?compact_message&svg=true)](https://ci.appveyor.com/project/cinderblocks57647/libremetaverse-ksbcr)
-[![Codacy Badge](https://app.codacy.com/project/badge/Grade/1cb97cd799c64ba49e2721f2ddda56ab)](https://www.codacy.com/gh/cinderblocks/libremetaverse/dashboard?utm_source=github.com&utm_medium=referral&utm_content=cinderblocks/libremetaverse&utm_campaign=Badge_Grade)
-[![.NET](https://github.com/cinderblocks/libremetaverse/actions/workflows/dotnet.yml/badge.svg)](https://github.com/cinderblocks/libremetaverse/actions/workflows/dotnet.yml)
-[![CodeQL](https://github.com/cinderblocks/libremetaverse/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/cinderblocks/libremetaverse/actions/workflows/codeql-analysis.yml)
-[![BSD Licensed](https://img.shields.io/github/license/cinderblocks/libremetaverse)](https://github.com/cinderblocks/libremetaverse/blob/master/LICENSE.txt)
-[![Commits per month](https://img.shields.io/github/commit-activity/m/cinderblocks/libremetaverse/master)](https://www.github.com/cinderblocks/libremetaverse/)
-[![ZEC](https://img.shields.io/keybase/zec/cinder)](https://keybase.io/cinder) [![BTC](https://img.shields.io/keybase/btc/cinder)](https://keybase.io/cinder)
+**Note:** Microsoft has [dropped support for .NET 5.0](https://devblogs.microsoft.com/dotnet/dotnet-5-end-of-support-update/) as of May 2022, so you will have to use .NET 6.0 or 7.0 instead.
+
+[![LibreMetaverse NuGet-Release](https://img.shields.io/nuget/v/libremetaverse.svg?label=LibreMetaverse)](https://www.nuget.org/packages/LibreMetaverse/)
+[![NuGet Downloads](https://img.shields.io/nuget/dt/LibreMetaverse?label=NuGet%20downloads)](https://www.nuget.org/packages/LibreMetaverse/)
+[![Build status](https://ci.appveyor.com/api/projects/status/pga5w0qken2k2nnl?svg=true)](https://ci.appveyor.com/project/cinderblocks57647/libremetaverse-ksbcr)
+[![Test status](https://img.shields.io/appveyor/tests/cinderblocks57647/libremetaverse-ksbcr?compact_message&svg=true)](https://ci.appveyor.com/project/cinderblocks57647/libremetaverse-ksbcr)
+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/1cb97cd799c64ba49e2721f2ddda56ab)](https://www.codacy.com/gh/cinderblocks/libremetaverse/dashboard?utm_source=github.com&utm_medium=referral&utm_content=cinderblocks/libremetaverse&utm_campaign=Badge_Grade)
+[![.NET](https://github.com/cinderblocks/libremetaverse/actions/workflows/dotnet.yml/badge.svg)](https://github.com/cinderblocks/libremetaverse/actions/workflows/dotnet.yml)
+[![CodeQL](https://github.com/cinderblocks/libremetaverse/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/cinderblocks/libremetaverse/actions/workflows/codeql-analysis.yml)
+[![BSD Licensed](https://img.shields.io/github/license/cinderblocks/libremetaverse)](https://github.com/cinderblocks/libremetaverse/blob/master/LICENSE.txt)
+[![Commits per month](https://img.shields.io/github/commit-activity/m/cinderblocks/libremetaverse/master)](https://www.github.com/cinderblocks/libremetaverse/)
+[![ZEC](https://img.shields.io/keybase/zec/cinder)](https://keybase.io/cinder) [![BTC](https://img.shields.io/keybase/btc/cinder)](https://keybase.io/cinder)
diff --git a/util/.editorconfig b/util/.editorconfig
new file mode 100644
index 00000000..29af8c97
--- /dev/null
+++ b/util/.editorconfig
@@ -0,0 +1,26 @@
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+charset = utf-8
+indent_style = tab
+indent_size = tab
+tab_width = 2
+trim_trailing_whitespace = true
+
+# The property below is not yet universally supported
+[*.md]
+max_line_length = 108
+word_wrap = true
+# Markdown sometimes uses two spaces at the end to
+# mark soft line breaks
+trim_trailing_whitespace = false
+
+[*.yml]
+end_of_line = lf
+charset = utf-8
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
\ No newline at end of file
diff --git a/util/.gitignore b/util/.gitignore
new file mode 100644
index 00000000..1a2d6eb8
--- /dev/null
+++ b/util/.gitignore
@@ -0,0 +1,58 @@
+~*
+# Stupid macOS temporary files
+
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+Icon?
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# Stuff from the Nova editor
+.nova
+node_modules
+package.json
+package-lock.json
+.eslintrc.yml
+.prettierrc.json
+
+# Original LibreMetaverse .gitignore follows
+compile.bat
+*.user
+*.userprefs
+*.suo
+*.cache
+*.pfx
+
+LibreMetaverse/LibreMetaverse.XML
+LibreMetaverse.*.XML
+
+[Oo]bj/
+[Bb]in/
+packages/
+.idea/
+.vs/
+/Programs/examples/TestClient/Properties/launchSettings.json