From 1324082b90a0c52a8f6d61802aff3442fb95df67 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Tue, 17 Nov 2009 15:05:40 +0000
Subject: refactor: move most animation methods from ScenePresence into a new
ScenePresenceAnimator class
---
.../Scenes/Animation/ScenePresenceAnimator.cs | 388 +++++++++++++++++++++
1 file changed, 388 insertions(+)
create mode 100644 OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
(limited to 'OpenSim/Region/Framework/Scenes/Animation')
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
new file mode 100644
index 0000000..d22e24a
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project 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 DEVELOPERS ``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 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 OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.Framework.Scenes;
+using OpenSim.Region.Physics.Manager;
+
+namespace OpenSim.Region.Framework.Scenes.Animation
+{
+ ///
+ /// Handle all animation duties for a scene presence
+ ///
+ public class ScenePresenceAnimator
+ {
+ public AnimationSet Animations
+ {
+ get { return m_animations; }
+ }
+ protected AnimationSet m_animations = new AnimationSet();
+
+ ///
+ /// The current movement animation
+ ///
+ public string CurrentMovementAnimation
+ {
+ get { return m_movementAnimation; }
+ }
+ protected string m_movementAnimation = "DEFAULT";
+
+ private int m_animTickFall;
+ private int m_animTickJump;
+
+ ///
+ /// The scene presence that this animator applies to
+ ///
+ protected ScenePresence m_scenePresence;
+
+ public ScenePresenceAnimator(ScenePresence sp)
+ {
+ m_scenePresence = sp;
+ }
+
+ public void AddAnimation(UUID animID, UUID objectID)
+ {
+ if (m_scenePresence.IsChildAgent)
+ return;
+
+ if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID))
+ SendAnimPack();
+ }
+
+ // Called from scripts
+ public void AddAnimation(string name, UUID objectID)
+ {
+ if (m_scenePresence.IsChildAgent)
+ return;
+
+ UUID animID = m_scenePresence.ControllingClient.GetDefaultAnimation(name);
+ if (animID == UUID.Zero)
+ return;
+
+ AddAnimation(animID, objectID);
+ }
+
+ public void RemoveAnimation(UUID animID)
+ {
+ if (m_scenePresence.IsChildAgent)
+ return;
+
+ if (m_animations.Remove(animID))
+ SendAnimPack();
+ }
+
+ // Called from scripts
+ public void RemoveAnimation(string name)
+ {
+ if (m_scenePresence.IsChildAgent)
+ return;
+
+ UUID animID = m_scenePresence.ControllingClient.GetDefaultAnimation(name);
+ if (animID == UUID.Zero)
+ return;
+
+ RemoveAnimation(animID);
+ }
+
+ public void ResetAnimations()
+ {
+ m_animations.Clear();
+ }
+
+ ///
+ /// The movement animation is reserved for "main" animations
+ /// that are mutually exclusive, e.g. flying and sitting.
+ ///
+ public void TrySetMovementAnimation(string anim)
+ {
+ //m_log.DebugFormat("Updating movement animation to {0}", anim);
+
+ if (!m_scenePresence.IsChildAgent)
+ {
+ if (m_animations.TrySetDefaultAnimation(
+ anim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, UUID.Zero))
+ {
+ // 16384 is CHANGED_ANIMATION
+ m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { 16384 });
+ SendAnimPack();
+ }
+ }
+ }
+
+ ///
+ /// This method determines the proper movement related animation
+ ///
+ public string GetMovementAnimation()
+ {
+ const float FALL_DELAY = 0.33f;
+ const float PREJUMP_DELAY = 0.25f;
+
+ #region Inputs
+
+ AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags;
+ PhysicsActor actor = m_scenePresence.PhysicsActor;
+
+ // Create forward and left vectors from the current avatar rotation
+ Matrix4 rotMatrix = Matrix4.CreateFromQuaternion(m_scenePresence.Rotation);
+ Vector3 fwd = Vector3.Transform(Vector3.UnitX, rotMatrix);
+ Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix);
+
+ // Check control flags
+ bool heldForward = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS;
+ bool heldBack = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG;
+ bool heldLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS;
+ bool heldRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG;
+ //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT;
+ //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT;
+ bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS;
+ bool heldDown = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG;
+ //bool flying = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) == AgentManager.ControlFlags.AGENT_CONTROL_FLY;
+ //bool mouselook = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) == AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK;
+
+ // Direction in which the avatar is trying to move
+ Vector3 move = Vector3.Zero;
+ if (heldForward) { move.X += fwd.X; move.Y += fwd.Y; }
+ if (heldBack) { move.X -= fwd.X; move.Y -= fwd.Y; }
+ if (heldLeft) { move.X += left.X; move.Y += left.Y; }
+ if (heldRight) { move.X -= left.X; move.Y -= left.Y; }
+ if (heldUp) { move.Z += 1; }
+ if (heldDown) { move.Z -= 1; }
+
+ // Is the avatar trying to move?
+// bool moving = (move != Vector3.Zero);
+ bool jumping = m_animTickJump != 0;
+
+ #endregion Inputs
+
+ #region Flying
+
+ if (actor != null && actor.Flying)
+ {
+ m_animTickFall = 0;
+ m_animTickJump = 0;
+
+ if (move.X != 0f || move.Y != 0f)
+ {
+ return (m_scenePresence.Scene.m_useFlySlow ? "FLYSLOW" : "FLY");
+ }
+ else if (move.Z > 0f)
+ {
+ return "HOVER_UP";
+ }
+ else if (move.Z < 0f)
+ {
+ if (actor != null && actor.IsColliding)
+ return "LAND";
+ else
+ return "HOVER_DOWN";
+ }
+ else
+ {
+ return "HOVER";
+ }
+ }
+
+ #endregion Flying
+
+ #region Falling/Floating/Landing
+
+ if (actor == null || !actor.IsColliding)
+ {
+ float fallElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f;
+ float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f;
+
+ if (m_animTickFall == 0 || (fallElapsed > FALL_DELAY && fallVelocity >= 0.0f))
+ {
+ // Just started falling
+ m_animTickFall = Environment.TickCount;
+ }
+ else if (!jumping && fallElapsed > FALL_DELAY)
+ {
+ // Falling long enough to trigger the animation
+ return "FALLDOWN";
+ }
+
+ return m_movementAnimation;
+ }
+
+ #endregion Falling/Floating/Landing
+
+ #region Ground Movement
+
+ if (m_movementAnimation == "FALLDOWN")
+ {
+ m_animTickFall = Environment.TickCount;
+
+ // TODO: SOFT_LAND support
+ return "LAND";
+ }
+ else if (m_movementAnimation == "LAND")
+ {
+ float landElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f;
+
+ if (landElapsed <= FALL_DELAY)
+ return "LAND";
+ }
+
+ m_animTickFall = 0;
+
+ if (move.Z > 0f)
+ {
+ // Jumping
+ if (!jumping)
+ {
+ // Begin prejump
+ m_animTickJump = Environment.TickCount;
+ return "PREJUMP";
+ }
+ else if (Environment.TickCount - m_animTickJump > PREJUMP_DELAY * 1000.0f)
+ {
+ // Start actual jump
+ if (m_animTickJump == -1)
+ {
+ // Already jumping! End the current jump
+ m_animTickJump = 0;
+ return "JUMP";
+ }
+
+ m_animTickJump = -1;
+ return "JUMP";
+ }
+ }
+ else
+ {
+ // Not jumping
+ m_animTickJump = 0;
+
+ if (move.X != 0f || move.Y != 0f)
+ {
+ // Walking / crouchwalking / running
+ if (move.Z < 0f)
+ return "CROUCHWALK";
+ else if (m_scenePresence.SetAlwaysRun)
+ return "RUN";
+ else
+ return "WALK";
+ }
+ else
+ {
+ // Not walking
+ if (move.Z < 0f)
+ return "CROUCH";
+ else
+ return "STAND";
+ }
+ }
+
+ #endregion Ground Movement
+
+ return m_movementAnimation;
+ }
+
+ ///
+ /// Update the movement animation of this avatar according to its current state
+ ///
+ public void UpdateMovementAnimations()
+ {
+ m_movementAnimation = GetMovementAnimation();
+
+ if (m_movementAnimation == "PREJUMP" && !m_scenePresence.Scene.m_usePreJump)
+ {
+ // This was the previous behavior before PREJUMP
+ TrySetMovementAnimation("JUMP");
+ }
+ else
+ {
+ TrySetMovementAnimation(m_movementAnimation);
+ }
+ }
+
+ public UUID[] GetAnimationArray()
+ {
+ UUID[] animIDs;
+ int[] sequenceNums;
+ UUID[] objectIDs;
+ m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs);
+ return animIDs;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void SendAnimPack(UUID[] animations, int[] seqs, UUID[] objectIDs)
+ {
+ if (m_scenePresence.IsChildAgent)
+ return;
+
+ m_scenePresence.Scene.ForEachClient(
+ delegate(IClientAPI client)
+ {
+ client.SendAnimations(animations, seqs, m_scenePresence.ControllingClient.AgentId, objectIDs);
+ });
+ }
+
+ public void SendAnimPackToClient(IClientAPI client)
+ {
+ if (m_scenePresence.IsChildAgent)
+ return;
+
+ UUID[] animIDs;
+ int[] sequenceNums;
+ UUID[] objectIDs;
+
+ m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs);
+
+ m_scenePresence.ControllingClient.SendAnimations(
+ animIDs, sequenceNums, m_scenePresence.ControllingClient.AgentId, objectIDs);
+ }
+
+ ///
+ /// Send animation information about this avatar to all clients.
+ ///
+ public void SendAnimPack()
+ {
+ //m_log.Debug("Sending animation pack to all");
+
+ if (m_scenePresence.IsChildAgent)
+ return;
+
+ UUID[] animIDs;
+ int[] sequenceNums;
+ UUID[] objectIDs;
+
+ m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs);
+
+ SendAnimPack(animIDs, sequenceNums, objectIDs);
+ }
+ }
+}
\ No newline at end of file
--
cgit v1.1