diff --git a/OpenMetaverse.Http/CapsServer.cs b/OpenMetaverse.Http/CapsServer.cs index 67d2e9fc..1df5446d 100644 --- a/OpenMetaverse.Http/CapsServer.cs +++ b/OpenMetaverse.Http/CapsServer.cs @@ -75,16 +75,14 @@ namespace OpenMetaverse.Http { serverOwned = true; capsHandler = BuildCapsHandler(@"^/caps/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"); - server = HttpListener.Create(address, port); - server.LogWriter = new log4netLogWriter(Logger.Log); + server = HttpListener.Create(log4netLogWriter.Instance, address, port); } public CapsServer(IPAddress address, int port, X509Certificate sslCertificate, X509Certificate rootCA, bool requireClientCertificate) { serverOwned = true; capsHandler = BuildCapsHandler(@"^/caps/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"); - server = HttpListener.Create(address, port, sslCertificate, rootCA, SslProtocols.Default, requireClientCertificate); - server.LogWriter = new log4netLogWriter(Logger.Log); + server = HttpListener.Create(log4netLogWriter.Instance, address, port, sslCertificate, rootCA, SslProtocols.Default, requireClientCertificate); } public CapsServer(HttpListener httpServer, string handlerPath) diff --git a/OpenMetaverse.Http/log4netLogWriter.cs b/OpenMetaverse.Http/log4netLogWriter.cs index 5abed1a1..b3361ab3 100644 --- a/OpenMetaverse.Http/log4netLogWriter.cs +++ b/OpenMetaverse.Http/log4netLogWriter.cs @@ -6,9 +6,14 @@ namespace OpenMetaverse.Http { public class log4netLogWriter : ILogWriter { + /// + /// Singleton instance of this class + /// + public static log4netLogWriter Instance = new log4netLogWriter(Logger.Log); + ILog Log; - public log4netLogWriter(ILog log) + log4netLogWriter(ILog log) { Log = log; } @@ -18,6 +23,7 @@ namespace OpenMetaverse.Http switch (prio) { case LogPrio.Trace: + return; // This logging is very noisy case LogPrio.Debug: Log.DebugFormat("{0}: {1}", source, message); break; diff --git a/Programs/Simian/AnimationSet.cs b/Programs/Simian/AnimationSet.cs index 3528c538..9f624da9 100644 --- a/Programs/Simian/AnimationSet.cs +++ b/Programs/Simian/AnimationSet.cs @@ -131,21 +131,18 @@ namespace Simian } } - public void GetArrays(out UUID[] animIDs, out int[] sequenceNums) + public AnimationTrigger[] GetAnimations() { lock (animations) { - animIDs = new UUID[animations.Count + 1]; - sequenceNums = new int[animations.Count + 1]; + AnimationTrigger[] triggers = new AnimationTrigger[animations.Count + 1]; - animIDs[0] = defaultAnimation.ID; - sequenceNums[0] = defaultAnimation.SequenceNum; + triggers[0] = new AnimationTrigger(defaultAnimation.ID, defaultAnimation.SequenceNum); - for (int i = 0; i < animations.Count; ++i) - { - animIDs[i + 1] = animations[i].ID; - sequenceNums[i + 1] = animations[i].SequenceNum; - } + for (int i = 0; i < animations.Count; i++) + triggers[i + 1] = new AnimationTrigger(animations[i].ID, animations[i].SequenceNum); + + return triggers; } } diff --git a/Programs/Simian/Extensions/AvatarManager.cs b/Programs/Simian/Extensions/AvatarManager.cs index edcad733..232860c7 100644 --- a/Programs/Simian/Extensions/AvatarManager.cs +++ b/Programs/Simian/Extensions/AvatarManager.cs @@ -71,39 +71,12 @@ namespace Simian.Extensions public void SendAnimations(Agent agent) { - AvatarAnimationPacket sendAnim = new AvatarAnimationPacket(); - sendAnim.Sender.ID = agent.Avatar.ID; - sendAnim.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[1]; - sendAnim.AnimationSourceList[0] = new AvatarAnimationPacket.AnimationSourceListBlock(); - sendAnim.AnimationSourceList[0].ObjectID = agent.Avatar.ID; - - 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]; - } - - server.UDP.BroadcastPacket(sendAnim, PacketCategory.State); + server.Scene.ObjectAnimate(this, agent.Avatar.ID, agent.Avatar.ID, agent.Animations.GetAnimations()); } public void TriggerSound(Agent agent, UUID soundID, float gain) { - SoundTriggerPacket sound = new SoundTriggerPacket(); - sound.SoundData.Handle = server.Scene.RegionHandle; - sound.SoundData.ObjectID = agent.Avatar.ID; - sound.SoundData.ParentID = agent.Avatar.ID; - sound.SoundData.OwnerID = agent.Avatar.ID; - sound.SoundData.Position = agent.Avatar.Position; - sound.SoundData.SoundID = soundID; - sound.SoundData.Gain = gain; - - server.UDP.BroadcastPacket(sound, PacketCategory.State); + server.Scene.TriggerSound(this, agent.Avatar.ID, agent.Avatar.ID, agent.Avatar.ID, soundID, agent.Avatar.Position, gain); } public void SendAlert(Agent agent, string message) @@ -142,10 +115,15 @@ namespace Simian.Extensions { ViewerEffectPacket effect = (ViewerEffectPacket)packet; - effect.AgentData.AgentID = UUID.Zero; - effect.AgentData.SessionID = UUID.Zero; + ViewerEffect[] effects = new ViewerEffect[effect.Effect.Length]; - server.UDP.BroadcastPacket(effect, PacketCategory.State); + for (int i = 0; i < effects.Length; i++) + { + ViewerEffectPacket.EffectBlock block = effect.Effect[i]; + effects[i] = new ViewerEffect(block.ID, (EffectType)block.Type, block.AgentID, new Color4(block.Color, 0, true), block.Duration); + } + + server.Scene.TriggerEffects(this, effects); } void AvatarPropertiesRequestHandler(Packet packet, Agent agent) diff --git a/Programs/Simian/Extensions/ImageDelivery.cs b/Programs/Simian/Extensions/ImageDelivery.cs index 8cba68cb..d4dba396 100644 --- a/Programs/Simian/Extensions/ImageDelivery.cs +++ b/Programs/Simian/Extensions/ImageDelivery.cs @@ -46,8 +46,9 @@ namespace Simian.Extensions } else { + // No layers, send the full image DiscardLevel = 0; - StopPacket = GetPacketForBytePosition(Texture.AssetData.Length); + StopPacket = GetPacketForBytePosition(Texture.AssetData.Length - 1); } CurrentPacket = Utils.Clamp(packet, 1, TexturePacketCount()); diff --git a/Programs/Simian/Extensions/ObjectManager.cs b/Programs/Simian/Extensions/ObjectManager.cs index 6bdc09ff..4b274be8 100644 --- a/Programs/Simian/Extensions/ObjectManager.cs +++ b/Programs/Simian/Extensions/ObjectManager.cs @@ -538,7 +538,7 @@ namespace Simian.Extensions { SimulationObject obj; if (server.Scene.TryGetObject(image.ObjectData[i].ObjectLocalID, out obj)) - server.Scene.ObjectImage(this, obj, + server.Scene.ObjectModifyTextures(this, obj, Utils.BytesToString(image.ObjectData[i].MediaURL), new Primitive.TextureEntry(image.ObjectData[i].TextureEntry, 0, image.ObjectData[i].TextureEntry.Length)); } diff --git a/Programs/Simian/Extensions/SceneManager.cs b/Programs/Simian/Extensions/SceneManager.cs index c6009685..881aae52 100644 --- a/Programs/Simian/Extensions/SceneManager.cs +++ b/Programs/Simian/Extensions/SceneManager.cs @@ -43,11 +43,14 @@ namespace Simian.Extensions public event ObjectRemoveCallback OnObjectRemove; public event ObjectTransformCallback OnObjectTransform; public event ObjectFlagsCallback OnObjectFlags; - public event ObjectImageCallback OnObjectImage; public event ObjectModifyCallback OnObjectModify; + public event ObjectModifyTexturesCallback OnObjectModifyTextures; + public event ObjectAnimateCallback OnObjectAnimate; public event AgentAddCallback OnAgentAdd; public event AgentRemoveCallback OnAgentRemove; public event AgentAppearanceCallback OnAgentAppearance; + public event TriggerSoundCallback OnTriggerSound; + public event TriggerEffectsCallback OnTriggerEffects; public event TerrainUpdateCallback OnTerrainUpdate; public uint RegionX { get { return 7777; } } @@ -150,6 +153,8 @@ namespace Simian.Extensions public bool ObjectRemove(object sender, uint localID) { SimulationObject obj; + Agent agent; + if (sceneObjects.TryGetValue(localID, out obj)) { if (OnObjectRemove != null) @@ -165,27 +170,22 @@ namespace Simian.Extensions server.UDP.BroadcastPacket(kill, PacketCategory.State); return true; } + else if (sceneAgents.TryGetValue(localID, out agent)) + { + AgentRemove(sender, agent); + return true; + } else { - Agent agent; - if (sceneAgents.TryGetValue(localID, out agent)) - { - if (OnAgentRemove != null) - OnAgentRemove(sender, agent); - - AgentRemove(agent); - return true; - } - else - { - return false; - } + return false; } } public bool ObjectRemove(object sender, UUID id) { SimulationObject obj; + Agent agent; + if (sceneObjects.TryGetValue(id, out obj)) { if (OnObjectRemove != null) @@ -201,26 +201,22 @@ namespace Simian.Extensions server.UDP.BroadcastPacket(kill, PacketCategory.State); return true; } + else if (sceneAgents.TryGetValue(id, out agent)) + { + AgentRemove(sender, agent); + return true; + } else { - Agent agent; - if (sceneAgents.TryGetValue(id, out agent)) - { - if (OnAgentRemove != null) - OnAgentRemove(sender, agent); - - AgentRemove(agent); - return true; - } - else - { - return false; - } + return false; } } - void AgentRemove(Agent agent) + void AgentRemove(object sender, Agent agent) { + if (OnAgentRemove != null) + OnAgentRemove(sender, agent); + Logger.Log("Removing agent " + agent.FullName + " from the scene", Helpers.LogLevel.Info); sceneAgents.Remove(agent.Avatar.LocalID, agent.Avatar.ID); @@ -304,21 +300,6 @@ namespace Simian.Extensions BroadcastObjectUpdate(obj.Prim); } - public void ObjectImage(object sender, SimulationObject obj, string mediaURL, Primitive.TextureEntry textureEntry) - { - if (OnObjectImage != null) - { - OnObjectImage(sender, obj, mediaURL, textureEntry); - } - - // Update the object - obj.Prim.Textures = textureEntry; - obj.Prim.MediaURL = mediaURL; - - // Inform clients - BroadcastObjectUpdate(obj.Prim); - } - public void ObjectModify(object sender, uint localID, Primitive.ConstructionData data) { SimulationObject obj; @@ -337,6 +318,92 @@ namespace Simian.Extensions } } + public void ObjectModifyTextures(object sender, SimulationObject obj, string mediaURL, Primitive.TextureEntry textureEntry) + { + if (OnObjectModifyTextures != null) + { + OnObjectModifyTextures(sender, obj, mediaURL, textureEntry); + } + + // Update the object + obj.Prim.Textures = textureEntry; + obj.Prim.MediaURL = mediaURL; + + // Inform clients + BroadcastObjectUpdate(obj.Prim); + } + + public void ObjectAnimate(object sender, UUID senderID, UUID objectID, AnimationTrigger[] animations) + { + if (OnObjectAnimate != null) + { + OnObjectAnimate(sender, senderID, objectID, animations); + } + + AvatarAnimationPacket sendAnim = new AvatarAnimationPacket(); + sendAnim.Sender.ID = senderID; + sendAnim.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[1]; + sendAnim.AnimationSourceList[0] = new AvatarAnimationPacket.AnimationSourceListBlock(); + sendAnim.AnimationSourceList[0].ObjectID = objectID; + + sendAnim.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length]; + for (int i = 0; i < animations.Length; i++) + { + sendAnim.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock(); + sendAnim.AnimationList[i].AnimID = animations[i].AnimationID; + sendAnim.AnimationList[i].AnimSequenceID = animations[i].SequenceID; + } + + server.UDP.BroadcastPacket(sendAnim, PacketCategory.State); + } + + public void TriggerSound(object sender, UUID objectID, UUID parentID, UUID ownerID, UUID soundID, Vector3 position, float gain) + { + if (OnTriggerSound != null) + { + OnTriggerSound(sender, objectID, parentID, ownerID, soundID, position, gain); + } + + SoundTriggerPacket sound = new SoundTriggerPacket(); + sound.SoundData.Handle = server.Scene.RegionHandle; + sound.SoundData.ObjectID = objectID; + sound.SoundData.ParentID = parentID; + sound.SoundData.OwnerID = ownerID; + sound.SoundData.Position = position; + sound.SoundData.SoundID = soundID; + sound.SoundData.Gain = gain; + + server.UDP.BroadcastPacket(sound, PacketCategory.State); + } + + public void TriggerEffects(object sender, ViewerEffect[] effects) + { + if (OnTriggerEffects != null) + { + OnTriggerEffects(sender, effects); + } + + ViewerEffectPacket effect = new ViewerEffectPacket(); + effect.AgentData.AgentID = UUID.Zero; + effect.AgentData.SessionID = UUID.Zero; + + effect.Effect = new ViewerEffectPacket.EffectBlock[effects.Length]; + + for (int i = 0; i < effects.Length; i++) + { + ViewerEffect currentEffect = effects[i]; + ViewerEffectPacket.EffectBlock block = new ViewerEffectPacket.EffectBlock(); + + block.AgentID = currentEffect.AgentID; + block.Color = currentEffect.Color.GetBytes(true); + block.Duration = currentEffect.Duration; + block.ID = currentEffect.EffectID; + block.Type = (byte)currentEffect.Type; + } + + server.UDP.BroadcastPacket(effect, PacketCategory.State); + } + public bool ContainsObject(uint localID) { return sceneObjects.ContainsKey(localID) || sceneAgents.ContainsKey(localID); diff --git a/Programs/Simian/Interfaces/ISceneProvider.cs b/Programs/Simian/Interfaces/ISceneProvider.cs index d937acaf..4de9cafc 100644 --- a/Programs/Simian/Interfaces/ISceneProvider.cs +++ b/Programs/Simian/Interfaces/ISceneProvider.cs @@ -16,18 +16,67 @@ namespace Simian } } + public struct AnimationTrigger + { + public UUID AnimationID; + public int SequenceID; + + public AnimationTrigger(UUID animationID, int sequenceID) + { + AnimationID = animationID; + SequenceID = sequenceID; + } + } + + public struct ViewerEffect + { + public UUID EffectID; + public EffectType Type; + public UUID AgentID; + public Color4 Color; + public float Duration; + + public ViewerEffect(UUID effectID, EffectType type, UUID agentID, Color4 color, float duration) + { + EffectID = effectID; + Type = type; + AgentID = agentID; + Color = color; + Duration = duration; + } + } + + public enum SceneActionType + { + None = 0, + ObjectAdd, + ObjectRemove, + ObjectTransform, + ObjectFlags, + ObjectModify, + ObjectModifyTextures, + ObjectAnimate, + AgentAdd, + AgentAppearance, + TriggerSound, + TriggerEffects, + TerrainUpdate, + } + + //public delegate void SceneActionCallback(SceneActionType type, OSD actionData); + public delegate void ObjectAddCallback(object sender, SimulationObject obj, PrimFlags creatorFlags); public delegate void ObjectRemoveCallback(object sender, SimulationObject obj); - public delegate void ObjectTransformCallback(object sender, SimulationObject obj, Vector3 position, - Quaternion rotation, Vector3 velocity, Vector3 acceleration, Vector3 angularVelocity); + public delegate void ObjectTransformCallback(object sender, SimulationObject obj, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 acceleration, Vector3 angularVelocity); public delegate void ObjectFlagsCallback(object sender, SimulationObject obj, PrimFlags flags); - public delegate void ObjectImageCallback(object sender, SimulationObject obj, - string mediaURL, Primitive.TextureEntry textureEntry); public delegate void ObjectModifyCallback(object sender, SimulationObject obj, Primitive.ConstructionData data); + public delegate void ObjectModifyTexturesCallback(object sender, SimulationObject obj, string mediaURL, Primitive.TextureEntry textureEntry); + public delegate void ObjectAnimateCallback(object sender, UUID senderID, UUID objectID, AnimationTrigger[] animations); public delegate void AgentAddCallback(object sender, Agent agent, PrimFlags creatorFlags); public delegate void AgentRemoveCallback(object sender, Agent agent); - public delegate void AgentAppearanceCallback(object sender, Agent agent, Primitive.TextureEntry textures, - byte[] visualParams); + public delegate void AgentAppearanceCallback(object sender, Agent agent, Primitive.TextureEntry textures, byte[] visualParams); + public delegate void TriggerSoundCallback(object sender, UUID objectID, UUID parentID, UUID ownerID, UUID soundID, Vector3 position, float gain); + public delegate void TriggerEffectsCallback(object sender, ViewerEffect[] effects); public delegate void TerrainUpdateCallback(object sender, uint x, uint y, float[,] patchData); public interface ISceneProvider @@ -37,9 +86,13 @@ namespace Simian event ObjectTransformCallback OnObjectTransform; event ObjectFlagsCallback OnObjectFlags; event ObjectModifyCallback OnObjectModify; + event ObjectModifyTexturesCallback OnObjectModifyTextures; + event ObjectAnimateCallback OnObjectAnimate; event AgentAddCallback OnAgentAdd; event AgentRemoveCallback OnAgentRemove; event AgentAppearanceCallback OnAgentAppearance; + event TriggerSoundCallback OnTriggerSound; + event TriggerEffectsCallback OnTriggerEffects; event TerrainUpdateCallback OnTerrainUpdate; uint RegionX { get; } @@ -54,26 +107,28 @@ namespace Simian uint TerrainPatchWidth { get; } uint TerrainPatchHeight { get; } - float[,] GetTerrainPatch(uint x, uint y); void SetTerrainPatch(object sender, uint x, uint y, float[,] patchData); - bool ObjectAdd(object sender, SimulationObject obj, PrimFlags creatorFlags); bool ObjectRemove(object sender, uint localID); bool ObjectRemove(object sender, UUID id); - void ObjectTransform(object sender, uint localID, Vector3 position, Quaternion rotation, Vector3 velocity, - Vector3 acceleration, Vector3 angularVelocity); + void ObjectTransform(object sender, uint localID, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 acceleration, Vector3 angularVelocity); void ObjectFlags(object sender, SimulationObject obj, PrimFlags flags); - void ObjectImage(object sender, SimulationObject obj, string mediaURL, Primitive.TextureEntry textureEntry); void ObjectModify(object sender, uint localID, Primitive.ConstructionData data); + void ObjectModifyTextures(object sender, SimulationObject obj, string mediaURL, Primitive.TextureEntry textureEntry); + void ObjectAnimate(object sender, UUID senderID, UUID objectID, AnimationTrigger[] animations); + void TriggerSound(object sender, UUID objectID, UUID parentID, UUID ownerID, UUID soundID, Vector3 position, float gain); + void TriggerEffects(object sender, ViewerEffect[] effects); + bool AgentAdd(object sender, Agent agent, PrimFlags creatorFlags); + void AgentAppearance(object sender, Agent agent, Primitive.TextureEntry textures, byte[] visualParams); + + float[,] GetTerrainPatch(uint x, uint y); bool ContainsObject(uint localID); bool ContainsObject(UUID id); int ObjectCount(); bool TryGetObject(uint localID, out SimulationObject obj); bool TryGetObject(UUID id, out SimulationObject obj); void ForEachObject(Action obj); - - bool AgentAdd(object sender, Agent agent, PrimFlags creatorFlags); - void AgentAppearance(object sender, Agent agent, Primitive.TextureEntry textures, byte[] visualParams); + int AgentCount(); bool TryGetAgent(uint localID, out Agent agent); bool TryGetAgent(UUID id, out Agent agent); diff --git a/Programs/Simian/Simian.cs b/Programs/Simian/Simian.cs index beb6d76e..a9bb12ea 100644 --- a/Programs/Simian/Simian.cs +++ b/Programs/Simian/Simian.cs @@ -66,7 +66,7 @@ namespace Simian } // TODO: SSL support - HttpServer = HttpListener.Create(IPAddress.Any, HttpPort); + HttpServer = HttpListener.Create(log4netLogWriter.Instance, IPAddress.Any, HttpPort); HttpServer.Start(10); try diff --git a/Programs/Simian/SimulationObject.cs b/Programs/Simian/SimulationObject.cs index db8076ad..bf873d81 100644 --- a/Programs/Simian/SimulationObject.cs +++ b/Programs/Simian/SimulationObject.cs @@ -17,8 +17,8 @@ namespace Simian public bool Frozen; protected Simian Server; - protected SimpleMesh[] Meshes = new SimpleMesh[4]; - protected SimpleMesh[] WorldTransformedMeshes = new SimpleMesh[4]; + protected SimpleMesh[] Meshes; + protected SimpleMesh[] WorldTransformedMeshes; public SimulationObject(SimulationObject obj) { @@ -39,6 +39,8 @@ namespace Simian { int i = (int)lod; + if (Meshes == null) Meshes = new SimpleMesh[4]; + if (Meshes[i] != null) { return Meshes[i]; @@ -56,6 +58,8 @@ namespace Simian { int i = (int)lod; + if (WorldTransformedMeshes == null) WorldTransformedMeshes = new SimpleMesh[4]; + if (WorldTransformedMeshes[i] != null) { return WorldTransformedMeshes[i];