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