diff --git a/Programs/Simian/Agent.cs b/Programs/Simian/Agent.cs index 0299d8a8..4815e627 100644 --- a/Programs/Simian/Agent.cs +++ b/Programs/Simian/Agent.cs @@ -19,7 +19,7 @@ namespace Simian public int Balance; public bool Running; public AgentManager.ControlFlags ControlFlags = AgentManager.ControlFlags.NONE; - public List Animations = new List(); + public AnimationSet Animations = new AnimationSet(); public Dictionary Inventory = new Dictionary(); public Dictionary Library = new Dictionary(); public Dictionary Wearables = new Dictionary(); diff --git a/Programs/Simian/Extensions/AvatarManager.cs b/Programs/Simian/Extensions/AvatarManager.cs index 6c0e93a4..b052923e 100644 --- a/Programs/Simian/Extensions/AvatarManager.cs +++ b/Programs/Simian/Extensions/AvatarManager.cs @@ -6,131 +6,11 @@ using OpenMetaverse.Packets; namespace Simian.Extensions { - public struct Animation - { - public UUID ID; - public int SequenceNum; - - public Animation(UUID id, int sequenceNum) - { - ID = id; - SequenceNum = sequenceNum; - } - } - - public class AnimationSet - { - private Animation defaultAnimation; - private List animations = new List(); - - public AnimationSet() - { - ResetDefaultAnimation(); - } - - public bool HasAnimation(UUID animID) - { - if (defaultAnimation.ID == animID) - return true; - - lock (animations) - { - for (int i = 0; i < animations.Count; ++i) - { - if (animations[i].ID == animID) - return true; - } - } - - return false; - } - - public bool Add(UUID animID, int sequenceNum) - { - lock (animations) - { - if (!HasAnimation(animID)) - { - animations.Add(new Animation(animID, sequenceNum)); - return true; - } - } - - return false; - } - - public bool Remove(UUID animID) - { - if (defaultAnimation.ID == animID) - { - ResetDefaultAnimation(); - return true; - } - else if (HasAnimation(animID)) - { - lock (animations) - { - for (int i = 0; i < animations.Count; i++) - { - if (animations[i].ID == animID) - { - animations.RemoveAt(i); - return true; - } - } - } - } - - return false; - } - - public void Clear() - { - ResetDefaultAnimation(); - lock (animations) animations.Clear(); - } - - public bool SetDefaultAnimation(UUID animID, int sequenceNum) - { - if (defaultAnimation.ID != animID) - { - defaultAnimation = new Animation(animID, sequenceNum); - return true; - } - else - { - return false; - } - } - - public void GetArrays(out UUID[] animIDs, out int[] sequenceNums) - { - lock (animations) - { - animIDs = new UUID[animations.Count + 1]; - sequenceNums = new int[animations.Count + 1]; - - animIDs[0] = defaultAnimation.ID; - sequenceNums[0] = defaultAnimation.SequenceNum; - - for (int i = 0; i < animations.Count; ++i) - { - animIDs[i + 1] = animations[i].ID; - sequenceNums[i + 1] = animations[i].SequenceNum; - } - } - } - - protected bool ResetDefaultAnimation() - { - return SetDefaultAnimation(Animations.STAND, 1); - } - } - - class AvatarManager : ISimianExtension + class AvatarManager : ISimianExtension, IAvatarManager { Simian Server; int currentWearablesSerialNum = -1; + int currentAnimSequenceNum = 0; public AvatarManager(Simian server) { @@ -143,12 +23,96 @@ namespace Simian.Extensions Server.UDPServer.RegisterPacketCallback(PacketType.AgentWearablesRequest, new UDPServer.PacketCallback(AgentWearablesRequestHandler)); Server.UDPServer.RegisterPacketCallback(PacketType.AgentIsNowWearing, new UDPServer.PacketCallback(AgentIsNowWearingHandler)); Server.UDPServer.RegisterPacketCallback(PacketType.AgentSetAppearance, new UDPServer.PacketCallback(AgentSetAppearanceHandler)); + Server.UDPServer.RegisterPacketCallback(PacketType.AgentAnimation, new UDPServer.PacketCallback(AgentAnimationHandler)); + Server.UDPServer.RegisterPacketCallback(PacketType.ViewerEffect, new UDPServer.PacketCallback(ViewerEffectHandler)); } public void Stop() { } + public bool SetDefaultAnimation(Agent agent, UUID animID) + { + return agent.Animations.SetDefaultAnimation(animID, ref currentAnimSequenceNum); + } + + public bool AddAnimation(Agent agent, UUID animID) + { + return agent.Animations.Add(animID, ref currentAnimSequenceNum); + } + + public bool RemoveAnimation(Agent agent, UUID animID) + { + return agent.Animations.Remove(animID); + } + + public void SendAnimations(Agent agent) + { + AvatarAnimationPacket sendAnim = new AvatarAnimationPacket(); + sendAnim.Sender.ID = agent.AgentID; + sendAnim.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[1]; + sendAnim.AnimationSourceList[0] = new AvatarAnimationPacket.AnimationSourceListBlock(); + sendAnim.AnimationSourceList[0].ObjectID = agent.AgentID; + + UUID[] animIDS; + int[] sequenceNums; + agent.Animations.GetArrays(out animIDS, out sequenceNums); + + sendAnim.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animIDS.Length]; + for (int i = 0; i < animIDS.Length; i++) + { + sendAnim.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock(); + sendAnim.AnimationList[i].AnimID = animIDS[i]; + sendAnim.AnimationList[i].AnimSequenceID = sequenceNums[i]; + } + + lock (Server.Agents) + { + foreach (Agent recipient in Server.Agents.Values) + recipient.SendPacket(sendAnim); + } + } + + void AgentAnimationHandler(Packet packet, Agent agent) + { + AgentAnimationPacket animPacket = (AgentAnimationPacket)packet; + bool changed = false; + + for (int i = 0; i < animPacket.AnimationList.Length; i++) + { + AgentAnimationPacket.AnimationListBlock block = animPacket.AnimationList[i]; + + if (block.StartAnim) + { + if (agent.Animations.Add(block.AnimID, ref currentAnimSequenceNum)) + changed = true; + } + else + { + if (agent.Animations.Remove(block.AnimID)) + changed = true; + } + } + + if (changed) + SendAnimations(agent); + } + + void ViewerEffectHandler(Packet packet, Agent agent) + { + ViewerEffectPacket effect = (ViewerEffectPacket)packet; + + effect.AgentData.AgentID = UUID.Zero; + effect.AgentData.SessionID = UUID.Zero; + + // Broadcast this to everyone + lock (Server.Agents) + { + foreach (Agent recipient in Server.Agents.Values) + recipient.SendPacket(effect); + } + } + void AvatarPropertiesRequestHandler(Packet packet, Agent agent) { AvatarPropertiesRequestPacket request = (AvatarPropertiesRequestPacket)packet; diff --git a/Programs/Simian/Extensions/Movement.cs b/Programs/Simian/Extensions/Movement.cs index fbb4703d..cceebb6c 100644 --- a/Programs/Simian/Extensions/Movement.cs +++ b/Programs/Simian/Extensions/Movement.cs @@ -9,20 +9,18 @@ namespace Simian.Extensions { public class Movement : ISimianExtension { - Simian server; - Timer updateTimer; - long lastTick; - int animationSerialNum; - const int UPDATE_ITERATION = 100; - const float WALK_SPEED = 3f; const float RUN_SPEED = 6f; const float FLY_SPEED = 12f; const float FALL_FORGIVENESS = 0.5f; - const float SQRT_TWO = 1.41421356f; + Simian server; + AvatarManager avatarManager; + Timer updateTimer; + long lastTick; + public int LastTick { get { return (int) Interlocked.Read(ref lastTick); } @@ -36,11 +34,9 @@ namespace Simian.Extensions public void Start() { - server.UDPServer.RegisterPacketCallback(PacketType.AgentAnimation, new UDPServer.PacketCallback(AgentAnimationHandler)); server.UDPServer.RegisterPacketCallback(PacketType.AgentUpdate, new UDPServer.PacketCallback(AgentUpdateHandler)); server.UDPServer.RegisterPacketCallback(PacketType.AgentHeightWidth, new UDPServer.PacketCallback(AgentHeightWidthHandler)); server.UDPServer.RegisterPacketCallback(PacketType.SetAlwaysRun, new UDPServer.PacketCallback(SetAlwaysRunHandler)); - server.UDPServer.RegisterPacketCallback(PacketType.ViewerEffect, new UDPServer.PacketCallback(ViewerEffectHandler)); updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed)); LastTick = Environment.TickCount; @@ -52,29 +48,6 @@ namespace Simian.Extensions updateTimer.Dispose(); } - void SetAgentAnimations(Agent agent, List animations) - { - lock (agent.Animations) - { - //definitely update - if (animations.Count != agent.Animations.Count) SendAnimationUpdate(agent); - - else //maybe update - { - foreach (UUID checkAnim in animations) - { - if (!agent.Animations.Contains(checkAnim)) - { - //yes, update - agent.Animations = animations; - SendAnimationUpdate(agent); - break; - } - } - } - } - } - void UpdateTimer_Elapsed(object sender) { int tick = Environment.TickCount; @@ -85,13 +58,18 @@ namespace Simian.Extensions { foreach (Agent agent in server.Agents.Values) { + bool animsChanged = false; + + // Reset velocity and acceleration agent.Avatar.Acceleration = Vector3.Zero; agent.Avatar.Velocity = Vector3.Zero; + // Create forward and left vectors from the current avatar rotation Matrix4 rotMatrix = Matrix4.CreateFromQuaternion(agent.Avatar.Rotation); Vector3 fwd = Vector3.Transform(Vector3.UnitX, rotMatrix); Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix); + // Check control flags bool heldForward = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; bool heldBack = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG; bool heldLeft = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS; @@ -154,34 +132,72 @@ namespace Simian.Extensions if (agent.Avatar.Position.Z < lowerLimit) agent.Avatar.Position.Z = lowerLimit; - List animations = new List(); - - bool movingHorizontally = (agent.Avatar.Velocity.X * agent.Avatar.Velocity.X) + (agent.Avatar.Velocity.Y * agent.Avatar.Velocity.Y) > 0f; + bool movingHorizontally = + (agent.Avatar.Velocity.X * agent.Avatar.Velocity.X) + + (agent.Avatar.Velocity.Y * agent.Avatar.Velocity.Y) > 0f; if (flying) { - if (movingHorizontally) animations.Add(Animations.FLY); - else if (heldUp && !heldDown) animations.Add(Animations.HOVER_UP); - else if (heldDown && !heldUp) animations.Add(Animations.HOVER_DOWN); - else animations.Add(Animations.HOVER); + if (movingHorizontally) + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.FLY)) + animsChanged = true; + } + else if (heldUp && !heldDown) + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.HOVER_UP)) + animsChanged = true; + } + else if (heldDown && !heldUp) + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.HOVER_DOWN)) + animsChanged = true; + } + else + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.HOVER)) + animsChanged = true; + } } else if (falling) { - animations.Add(Animations.FALLDOWN); + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.FALLDOWN)) + animsChanged = true; } else //on the ground { if (movingHorizontally) { - if (heldDown) animations.Add(Animations.CROUCHWALK); - else if (agent.Running) animations.Add(Animations.RUN); - else animations.Add(Animations.WALK); + if (heldDown) + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.CROUCHWALK)) + animsChanged = true; + } + else if (agent.Running) + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.RUN)) + animsChanged = true; + } + else + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.WALK)) + animsChanged = true; + } + } + else if (heldDown) + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.CROUCH)) + animsChanged = true; + } + else + { + if (server.AvatarManager.SetDefaultAnimation(agent, Animations.STAND)) + animsChanged = true; } - else if (heldDown) animations.Add(Animations.CROUCH); - else animations.Add(Animations.STAND); } - SetAgentAnimations(agent, animations); + if (animsChanged) + server.AvatarManager.SendAnimations(agent); } } } @@ -195,33 +211,14 @@ namespace Simian.Extensions agent.State = update.AgentData.State; agent.Flags = (LLObject.ObjectFlags)update.AgentData.Flags; + ObjectUpdatePacket fullUpdate = BuildFullUpdate(agent, agent.Avatar, server.RegionHandle, + agent.State, agent.Flags); + lock (server.Agents) { - ObjectUpdatePacket fullUpdate = BuildFullUpdate(agent, agent.Avatar, server.RegionHandle, - agent.State, agent.Flags); - foreach (Agent recipient in server.Agents.Values) - { recipient.SendPacket(fullUpdate); - - - if (agent.Animations.Count == 0) //TODO: need to start default standing animation - { - agent.Animations.Add(Animations.STAND); - - AgentAnimationPacket startAnim = new AgentAnimationPacket(); - startAnim.AgentData.AgentID = agent.AgentID; - startAnim.AnimationList = new AgentAnimationPacket.AnimationListBlock[1]; - startAnim.AnimationList[0] = new AgentAnimationPacket.AnimationListBlock(); - startAnim.AnimationList[0].AnimID = Animations.STAND; - startAnim.AnimationList[0].StartAnim = true; - startAnim.PhysicalAvatarEventList = new AgentAnimationPacket.PhysicalAvatarEventListBlock[0]; - - recipient.SendPacket(startAnim); - } - } } - } void SetAlwaysRunHandler(Packet packet, Agent agent) @@ -260,46 +257,6 @@ namespace Simian.Extensions return ((lerpX + lerpY) / 2); } - void SendAnimationUpdate(Agent agent) - { - lock (agent.Animations) - { - AvatarAnimationPacket sendAnim = new AvatarAnimationPacket(); - sendAnim.Sender.ID = agent.AgentID; - sendAnim.AnimationList = new AvatarAnimationPacket.AnimationListBlock[agent.Animations.Count]; - sendAnim.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[agent.Animations.Count]; - - int i = 0; - foreach (UUID anim in agent.Animations) - { - sendAnim.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock(); - sendAnim.AnimationList[i].AnimID = anim; - sendAnim.AnimationList[i].AnimSequenceID = (int)Interlocked.Increment(ref animationSerialNum); - sendAnim.AnimationSourceList[i] = new AvatarAnimationPacket.AnimationSourceListBlock(); - sendAnim.AnimationSourceList[i].ObjectID = agent.AgentID; - i++; - } - - lock (server.Agents) - { - foreach (Agent recipient in server.Agents.Values) - recipient.SendPacket(sendAnim); - } - } - } - - void AgentAnimationHandler(Packet packet, Agent agent) - { - AgentAnimationPacket animPacket = (AgentAnimationPacket)packet; - - List animations = new List(); - - foreach (AgentAnimationPacket.AnimationListBlock block in animPacket.AnimationList) - if (block.StartAnim && !animations.Contains(block.AnimID)) animations.Add(block.AnimID); - - SetAgentAnimations(agent, animations); - } - void AgentHeightWidthHandler(Packet packet, Agent agent) { AgentHeightWidthPacket heightWidth = (AgentHeightWidthPacket)packet; @@ -308,21 +265,6 @@ namespace Simian.Extensions heightWidth.HeightWidthBlock.Height, heightWidth.HeightWidthBlock.Width), Helpers.LogLevel.Info); } - void ViewerEffectHandler(Packet packet, Agent agent) - { - ViewerEffectPacket effect = (ViewerEffectPacket)packet; - - effect.AgentData.AgentID = UUID.Zero; - effect.AgentData.SessionID = UUID.Zero; - - // Broadcast this to everyone - lock (server.Agents) - { - foreach (Agent recipient in server.Agents.Values) - recipient.SendPacket(effect); - } - } - public static ObjectUpdatePacket BuildFullUpdate(Agent agent, LLObject obj, ulong regionHandle, byte state, LLObject.ObjectFlags flags) { byte[] objectData = new byte[60]; @@ -339,7 +281,7 @@ namespace Simian.Extensions ObjectUpdatePacket update = new ObjectUpdatePacket(); update.RegionData.RegionHandle = regionHandle; - update.RegionData.TimeDilation = Helpers.FloatToByte(1f, 0f, 1f); + update.RegionData.TimeDilation = UInt16.MaxValue; update.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; update.ObjectData[0] = new ObjectUpdatePacket.ObjectDataBlock(); update.ObjectData[0].ClickAction = (byte)0; diff --git a/Programs/Simian/Interfaces/IAvatarManager.cs b/Programs/Simian/Interfaces/IAvatarManager.cs new file mode 100644 index 00000000..4dbdfaab --- /dev/null +++ b/Programs/Simian/Interfaces/IAvatarManager.cs @@ -0,0 +1,13 @@ +using System; +using OpenMetaverse; + +namespace Simian +{ + public interface IAvatarManager + { + bool SetDefaultAnimation(Agent agent, UUID animID); + bool AddAnimation(Agent agent, UUID animID); + bool RemoveAnimation(Agent agent, UUID animID); + void SendAnimations(Agent agent); + } +} diff --git a/Programs/Simian/Simian.cs b/Programs/Simian/Simian.cs index abc5ae7e..2d3232aa 100644 --- a/Programs/Simian/Simian.cs +++ b/Programs/Simian/Simian.cs @@ -22,6 +22,9 @@ namespace Simian public float[] Heightmap = new float[65536]; public Dictionary AssetStore = new Dictionary(); + // Interfaces + public IAvatarManager AvatarManager; + /// All of the agents currently connected to this UDP server public Dictionary Agents = new Dictionary(); @@ -57,6 +60,15 @@ namespace Simian { Logger.DebugLog("Loading extension " + extension.GetType().Name); extension.Start(); + + // Assign to an interface if possible + TryAssignToInterface(extension); + } + + if (!CheckInterfaces()) + { + Logger.Log("Missing interfaces, shutting down", Helpers.LogLevel.Error); + Stop(); } } @@ -84,6 +96,26 @@ namespace Simian } } + void TryAssignToInterface(ISimianExtension extension) + { + if (extension is IAvatarManager) + { + IAvatarManager manager = (IAvatarManager)extension; + AvatarManager = manager; + } + } + + bool CheckInterfaces() + { + if (AvatarManager == null) + { + Logger.Log("No AvatarManager interface loaded", Helpers.LogLevel.Error); + return false; + } + + return true; + } + void InitUDPServer(int port) { UDPServer = new UDPServer(port, this);