Esempio n. 1
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="simulator"></param>
        protected void CompressedUpdateHandler(Packet packet, Simulator simulator)
        {
            ObjectUpdateCompressedPacket update = (ObjectUpdateCompressedPacket)packet;

            for (int b = 0; b < update.ObjectData.Length; b++)
            {
                ObjectUpdateCompressedPacket.ObjectDataBlock block = update.ObjectData[b];
                int i = 0;

                try
                {
                    // UUID
                    LLUUID FullID = new LLUUID(block.Data, 0);
                    i += 16;
                    // Local ID
                    uint LocalID = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
                        (block.Data[i++] << 16) + (block.Data[i++] << 24));
                    // PCode
                    PCode pcode = (PCode)block.Data[i++];

                    #region Relevance check
                    if (!Client.Settings.ALWAYS_DECODE_OBJECTS)
                    {
                        switch (pcode)
                        {
                            case PCode.Grass:
                            case PCode.Tree:
                            case PCode.NewTree:
                                if (OnNewFoliage == null) continue;
                                break;
                            case PCode.Prim:
                                if (OnNewPrim == null) continue;
                                break;
                        }
                    }
                    #endregion Relevance check

                    Primitive prim = GetPrimitive(simulator, LocalID, FullID);

                    prim.LocalID = LocalID;
                    prim.ID = FullID;
                    prim.Flags = (LLObject.ObjectFlags)block.UpdateFlags;
                    prim.Data.PCode = pcode;

                    switch (pcode)
                    {
                        case PCode.Grass:
                        case PCode.Tree:
                        case PCode.NewTree:
                            #region Foliage Decoding

                            // State
                            prim.Data.State = block.Data[i++];
                            // CRC
                            i += 4;
                            // Material
                            prim.Data.Material = (LLObject.MaterialType)block.Data[i++];
                            // Click action
                            prim.ClickAction = (ClickAction)block.Data[i++];
                            // Scale
                            prim.Scale = new LLVector3(block.Data, i);
                            i += 12;
                            // Position
                            prim.Position = new LLVector3(block.Data, i);
                            i += 12;
                            // Rotation
                            prim.Rotation = new LLQuaternion(block.Data, i, true);
                            i += 12;

                            #endregion Foliage Decoding

                            // FIXME: We are leaving a lot of data left undecoded here, including the
                            // tree species. Need to understand what is going on with these packets
                            // and fix it soon!

                            FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation);

                            break;
                        case PCode.Prim:
                            #region Decode block and update Prim
                            // State
                            prim.Data.State = block.Data[i++];
                            // CRC
                            i += 4;
                            // Material
                            prim.Data.Material = (LLObject.MaterialType)block.Data[i++];
                            // Click action
                            prim.ClickAction = (ClickAction)block.Data[i++];
                            // Scale
                            prim.Scale = new LLVector3(block.Data, i);
                            i += 12;
                            // Position
                            prim.Position = new LLVector3(block.Data, i);
                            i += 12;
                            // Rotation
                            prim.Rotation = new LLQuaternion(block.Data, i, true);
                            i += 12;
                            // Compressed flags
                            CompressedFlags flags = (CompressedFlags)Helpers.BytesToUIntBig(block.Data, i);
                            i += 4;

                            prim.OwnerID = new LLUUID(block.Data, i);
                            i += 16;
			    

                            // Angular velocity
                            if ((flags & CompressedFlags.HasAngularVelocity) != 0)
                            {
                                prim.AngularVelocity = new LLVector3(block.Data, i);
                                i += 12;
                            }

                            // Parent ID
                            if ((flags & CompressedFlags.HasParent) != 0)
                            {
                                prim.ParentID = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
                                (block.Data[i++] << 16) + (block.Data[i++] << 24));
                            }
                            else
                            {
                                prim.ParentID = 0;
                            }

                            // Tree data
                            if ((flags & CompressedFlags.Tree) != 0)
                            {
                                prim.GenericData = new byte[1];
                                prim.GenericData[0] = block.Data[i++];
                            }
                            // Scratch pad
                            else if ((flags & CompressedFlags.ScratchPad) != 0)
                            {
                                int size = block.Data[i++];
                                prim.GenericData = new byte[size];
                                Buffer.BlockCopy(block.Data, i, prim.GenericData, 0, size);
                                i += size;
                            }

                            // Floating text
                            if ((flags & CompressedFlags.HasText) != 0)
                            {
                                string text = String.Empty;
                                while (block.Data[i] != 0)
                                {
                                    text += (char)block.Data[i];
                                    i++;
                                }
                                i++;

                                // Floating text
                                prim.Text = text;

                                // Text color
                                prim.TextColor = new LLColor(block.Data, i, false);
                                // FIXME: Is alpha inversed here as well?
                                i += 4;
                            }
                            else
                            {
                                prim.Text = String.Empty;
                            }

                            // Media URL
                            if ((flags & CompressedFlags.MediaURL) != 0)
                            {
                                string text = String.Empty;
                                while (block.Data[i] != 0)
                                {
                                    text += (char)block.Data[i];
                                    i++;
                                }
                                i++;

                                prim.MediaURL = text;
                            }

                            // Particle system
                            if ((flags & CompressedFlags.HasParticles) != 0)
                            {
                                prim.ParticleSys = new Primitive.ParticleSystem(block.Data, i);
                                i += 86;
                            }

                            // Extra parameters
                            i += prim.SetExtraParamsFromBytes(block.Data, i);

                            //Sound data
                            if ((flags & CompressedFlags.HasSound) != 0)
                            {
                                prim.Sound = new LLUUID(block.Data, i);
                                i += 16;

                                if (!BitConverter.IsLittleEndian)
                                {
                                    Array.Reverse(block.Data, i, 4);
                                    Array.Reverse(block.Data, i + 5, 4);
                                }

                                prim.SoundGain = BitConverter.ToSingle(block.Data, i);
                                i += 4;
                                prim.SoundFlags = block.Data[i++];
                                prim.SoundRadius = BitConverter.ToSingle(block.Data, i);
                                i += 4;
                            }

                            // Name values
                            if ((flags & CompressedFlags.HasNameValues) != 0)
                            {
                                string text = String.Empty;
                                while (block.Data[i] != 0)
                                {
                                    text += (char)block.Data[i];
                                    i++;
                                }
                                i++;

                                // Parse the name values
                                if (text.Length > 0)
                                {
                                    string[] lines = text.Split('\n');
                                    prim.NameValues = new NameValue[lines.Length];

                                    for (int j = 0; j < lines.Length; j++)
                                    {
                                        if (!String.IsNullOrEmpty(lines[j]))
                                        {
                                            NameValue nv = new NameValue(lines[j]);
                                            prim.NameValues[j] = nv;
                                        }
                                    }
                                }
                            }

                            prim.Data.PathCurve = (LLObject.PathCurve)block.Data[i++];
                            ushort pathBegin = Helpers.BytesToUInt16(block.Data, i); i += 2;
                            prim.Data.PathBegin = LLObject.UnpackBeginCut(pathBegin);
                            ushort pathEnd = Helpers.BytesToUInt16(block.Data, i); i += 2;
                            prim.Data.PathEnd = LLObject.UnpackEndCut(pathEnd);
                            prim.Data.PathScaleX = LLObject.UnpackPathScale(block.Data[i++]);
                            prim.Data.PathScaleY = LLObject.UnpackPathScale(block.Data[i++]);
                            prim.Data.PathShearX = LLObject.UnpackPathShear((sbyte)block.Data[i++]);
                            prim.Data.PathShearY = LLObject.UnpackPathShear((sbyte)block.Data[i++]);
                            prim.Data.PathTwist = LLObject.UnpackPathTwist((sbyte)block.Data[i++]);
                            prim.Data.PathTwistBegin = LLObject.UnpackPathTwist((sbyte)block.Data[i++]);
                            prim.Data.PathRadiusOffset = LLObject.UnpackPathTwist((sbyte)block.Data[i++]);
                            prim.Data.PathTaperX = LLObject.UnpackPathTaper((sbyte)block.Data[i++]);
                            prim.Data.PathTaperY = LLObject.UnpackPathTaper((sbyte)block.Data[i++]);
                            prim.Data.PathRevolutions = LLObject.UnpackPathRevolutions(block.Data[i++]);
                            prim.Data.PathSkew = LLObject.UnpackPathTwist((sbyte)block.Data[i++]);

                            prim.Data.profileCurve = block.Data[i++];
                            ushort profileBegin = Helpers.BytesToUInt16(block.Data, i); i += 2;
                            prim.Data.ProfileBegin = LLObject.UnpackBeginCut(profileBegin);
                            ushort profileEnd = Helpers.BytesToUInt16(block.Data, i); i += 2;
                            prim.Data.ProfileEnd = LLObject.UnpackEndCut(profileEnd);
                            ushort profileHollow = Helpers.BytesToUInt16(block.Data, i); i += 2;
                            prim.Data.ProfileHollow = LLObject.UnpackProfileHollow(profileHollow);

                            // TextureEntry
                            int textureEntryLength = (int)Helpers.BytesToUIntBig(block.Data, i);
                            i += 4;
                            prim.Textures = new LLObject.TextureEntry(block.Data, i, textureEntryLength);
                            i += textureEntryLength;

                            // Texture animation
                            if ((flags & CompressedFlags.TextureAnimation) != 0)
                            {
                                //int textureAnimLength = (int)Helpers.BytesToUIntBig(block.Data, i);
                                i += 4;
                                prim.TextureAnim = new Primitive.TextureAnimation(block.Data, i);
                            }

                            #endregion

                            #region Fire Events

                            // Fire the appropriate callback
                            if ((flags & CompressedFlags.HasNameValues) != 0 && prim.ParentID != 0)
                                FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, 
                                    update.RegionData.TimeDilation);
                            else if ((flags & CompressedFlags.Tree) != 0)
                                FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, 
                                    update.RegionData.TimeDilation);
                            else
                                FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, 
                                    update.RegionData.TimeDilation);

                            #endregion

                            break;
                        default:
                            Client.DebugLog("Got an ObjectUpdateCompressed for PCode " + pcode.ToString() +
                                ", implement this!");
                            break;
                    }
                }
                catch (IndexOutOfRangeException e)
                {
                    Client.Log("Had a problem decoding an ObjectUpdateCompressed packet: " +
                        e.ToString(), Helpers.LogLevel.Warning);
                    Client.Log(block.ToString(), Helpers.LogLevel.Warning);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Used for new prims, or significant changes to existing prims
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="simulator"></param>
        protected void UpdateHandler(Packet packet, Simulator simulator)
        {
            ObjectUpdatePacket update = (ObjectUpdatePacket)packet;
			UpdateDilation(simulator, update.RegionData.TimeDilation);

            for (int b = 0; b < update.ObjectData.Length; b++)
            {
                ObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[b];

                LLVector4 collisionPlane = LLVector4.Zero;
                LLVector3 position;
                LLVector3 velocity;
                LLVector3 acceleration;
                LLQuaternion rotation;
                LLVector3 angularVelocity;
                NameValue[] nameValues;
                bool attachment = false;
                PCode pcode = (PCode)block.PCode;

                #region Relevance check

                // Check if we are interested in this object
                if (!Client.Settings.ALWAYS_DECODE_OBJECTS)
                {
                    switch (pcode)
                    {
                        case PCode.Grass:
                        case PCode.Tree:
                        case PCode.NewTree:
                            if (OnNewFoliage == null) continue;
                            break;
                        case PCode.Prim:
                            if (OnNewPrim == null) continue;
                            break;
                        case PCode.Avatar:
                            // Make an exception for updates about our own agent
                            if (block.FullID != Client.Self.AgentID && OnNewAvatar == null) continue;
                            break;
                        case PCode.ParticleSystem:
                            continue; // TODO: Do something with these
                    }
                }

                #endregion Relevance check

                #region NameValue parsing

                string nameValue = Helpers.FieldToUTF8String(block.NameValue);
                if (nameValue.Length > 0)
                {
                    string[] lines = nameValue.Split('\n');
                    nameValues = new NameValue[lines.Length];

                    for (int i = 0; i < lines.Length; i++)
                    {
                        if (!String.IsNullOrEmpty(lines[i]))
                        {
                            NameValue nv = new NameValue(lines[i]);
                            if (nv.Name == "AttachItemID") attachment = true;
                            nameValues[i] = nv;
                        }
                    }
                }
                else
                {
                    nameValues = new NameValue[0];
                }

                #endregion NameValue parsing

                #region Decode Object (primitive) parameters
                LLObject.ObjectData data = new LLObject.ObjectData();
                data.State = block.State;
                data.Material = (LLObject.MaterialType)block.Material;
                data.PathCurve = (LLObject.PathCurve)block.PathCurve;
                data.profileCurve = block.ProfileCurve;
                data.PathBegin = LLObject.UnpackBeginCut(block.PathBegin);
                data.PathEnd = LLObject.UnpackEndCut(block.PathEnd);
                data.PathScaleX = LLObject.UnpackPathScale(block.PathScaleX);
                data.PathScaleY = LLObject.UnpackPathScale(block.PathScaleY);
                data.PathShearX = LLObject.UnpackPathShear((sbyte)block.PathShearX);
                data.PathShearY = LLObject.UnpackPathShear((sbyte)block.PathShearY);
                data.PathTwist = LLObject.UnpackPathTwist(block.PathTwist);
                data.PathTwistBegin = LLObject.UnpackPathTwist(block.PathTwistBegin);
                data.PathRadiusOffset = LLObject.UnpackPathTwist(block.PathRadiusOffset);
                data.PathTaperX = LLObject.UnpackPathTaper(block.PathTaperX);
                data.PathTaperY = LLObject.UnpackPathTaper(block.PathTaperY);
                data.PathRevolutions = LLObject.UnpackPathRevolutions(block.PathRevolutions);
                data.PathSkew = LLObject.UnpackPathTwist(block.PathSkew);
                data.ProfileBegin = LLObject.UnpackBeginCut(block.ProfileBegin);
                data.ProfileEnd = LLObject.UnpackEndCut(block.ProfileEnd);
                data.ProfileHollow = LLObject.UnpackProfileHollow(block.ProfileHollow);
                data.PCode = pcode;
                #endregion

                #region Decode Additional packed parameters in ObjectData
                int pos = 0;
                switch (block.ObjectData.Length)
                {
                    case 76:
                        // Collision normal for avatar
                        collisionPlane = new LLVector4(block.ObjectData, pos);
                        pos += 16;

                        goto case 60;
                    case 60:
                        // Position
                        position = new LLVector3(block.ObjectData, pos);
                        pos += 12;
                        // Velocity
                        velocity = new LLVector3(block.ObjectData, pos);
                        pos += 12;
                        // Acceleration
                        acceleration = new LLVector3(block.ObjectData, pos);
                        pos += 12;
                        // Rotation (theta)
                        rotation = new LLQuaternion(block.ObjectData, pos, true);
                        pos += 12;
                        // Angular velocity (omega)
                        angularVelocity = new LLVector3(block.ObjectData, pos);
                        pos += 12;

                        break;
                    case 48:
                        // Collision normal for avatar
                        collisionPlane = new LLVector4(block.ObjectData, pos);
                        pos += 16;

                        goto case 32;
                    case 32:
                        // The data is an array of unsigned shorts

                        // Position
                        position = new LLVector3(
                            Helpers.UInt16ToFloat(block.ObjectData, pos, -0.5f * 256.0f, 1.5f * 256.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -0.5f * 256.0f, 1.5f * 256.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 3.0f * 256.0f));
                        pos += 6;
                        // Velocity
                        velocity = new LLVector3(
                            Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
                        pos += 6;
                        // Acceleration
                        acceleration = new LLVector3(
                            Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
                        pos += 6;
                        // Rotation (theta)
                        rotation = new LLQuaternion(
                            Helpers.UInt16ToFloat(block.ObjectData, pos, -1.0f, 1.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -1.0f, 1.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 6, -1.0f, 1.0f));
                        pos += 8;
                        // Angular velocity (omega)
                        angularVelocity = new LLVector3(
                            Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
                            Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
                        pos += 6;

                        break;
                    case 16:
                        // The data is an array of single bytes (8-bit numbers)

                        // Position
                        position = new LLVector3(
                            Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
                        pos += 3;
                        // Velocity
                        velocity = new LLVector3(
                            Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
                        pos += 3;
                        // Accleration
                        acceleration = new LLVector3(
                            Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
                        pos += 3;
                        // Rotation
                        rotation = new LLQuaternion(
                            Helpers.ByteToFloat(block.ObjectData, pos, -1.0f, 1.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 1, -1.0f, 1.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 3, -1.0f, 1.0f));
                        pos += 4;
                        // Angular Velocity
                        angularVelocity = new LLVector3(
                            Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
                            Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
                        pos += 3;

                        break;
                    default:
                        Client.Log("Got an ObjectUpdate block with ObjectUpdate field length of " +
                            block.ObjectData.Length, Helpers.LogLevel.Warning);

                        continue;
                }
                #endregion

                // Determine the object type and create the appropriate class
                switch (pcode)
                {
                    #region Prim and Foliage
                    case PCode.Grass:
                    case PCode.Tree:
                    case PCode.NewTree:
                    case PCode.Prim:
                        Primitive prim = GetPrimitive(simulator, block.ID, block.FullID);

                        #region Update Prim Info with decoded data                            
                        prim.Flags = (LLObject.ObjectFlags)block.UpdateFlags;

                        if ((prim.Flags & LLObject.ObjectFlags.ZlibCompressed) != 0)
                        {
                            Client.Log("Got a ZlibCompressed ObjectUpdate, implement me!", 
                                Helpers.LogLevel.Warning);
                            continue;
                        }

                        // Automatically request ObjectProperties for prim if it was rezzed selected.
                        if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) == LLObject.ObjectFlags.CreateSelected)
                            SelectObject(simulator, prim.LocalID);

                        prim.NameValues = nameValues;
                        prim.LocalID = block.ID;
                        prim.ID = block.FullID;
                        prim.ParentID = block.ParentID;
					    prim.RegionHandle = update.RegionData.RegionHandle;
                        prim.Scale = block.Scale;
                        prim.ClickAction = (ClickAction)block.ClickAction;
                        prim.OwnerID = block.OwnerID;
                        prim.MediaURL = Helpers.FieldToUTF8String(block.MediaURL);
                        prim.Text = Helpers.FieldToUTF8String(block.Text);
                        prim.TextColor = new LLColor(block.TextColor, 0, false);
                        // Only alpha is inversed
                        prim.TextColor.A = (byte)(1.0f - prim.TextColor.A);

                        // Sound information
                        prim.Sound = block.Sound;
                        prim.SoundFlags = block.Flags;
                        prim.SoundGain = block.Gain;
                        prim.SoundRadius = block.Radius;

                        // Joint information
                        prim.Joint = (Primitive.JointType)block.JointType;
                        prim.JointPivot = block.JointPivot;
                        prim.JointAxisOrAnchor = block.JointAxisOrAnchor;
                        
                        // Object parameters
                        prim.Data = data;

                        // Textures, texture animations, particle system, and extra params
                        prim.Textures = new LLObject.TextureEntry(block.TextureEntry, 0,
                            block.TextureEntry.Length);

                        prim.TextureAnim = new Primitive.TextureAnimation(block.TextureAnim, 0);
                        prim.ParticleSys = new Primitive.ParticleSystem(block.PSBlock, 0);
                        prim.SetExtraParamsFromBytes(block.ExtraParams, 0);

                        // PCode-specific data
                        prim.GenericData = block.Data;

                        // Packed parameters
                        prim.CollisionPlane = collisionPlane;
                        prim.Position = position;
                        prim.Velocity = velocity;
                        prim.Acceleration = acceleration;
                        prim.Rotation = rotation;
                        prim.AngularVelocity = angularVelocity;
                        #endregion

                        if (attachment)
                            FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, 
                                update.RegionData.TimeDilation);
                        else if (pcode == PCode.Prim)
                            FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, 
                                update.RegionData.TimeDilation);
                        else
                            FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, 
                                update.RegionData.TimeDilation);

                        break;
                    #endregion Prim and Foliage
                    #region Avatar
                    case PCode.Avatar:
                        // Update some internals if this is our avatar
                        if (block.FullID == Client.Self.AgentID)
                        {
                            #region Update Client.Self
                            
                            // We need the local ID to recognize terse updates for our agent
                            Client.Self.localID = block.ID;
                            
                            // Packed parameters
                            Client.Self.collisionPlane = collisionPlane;
                            Client.Self.relativePosition = position;
                            Client.Self.velocity = velocity;
                            Client.Self.acceleration = acceleration;
                            Client.Self.relativeRotation = rotation;
                            Client.Self.angularVelocity = angularVelocity;

                            #endregion
                        }

                        #region Create an Avatar from the decoded data

                        Avatar avatar = GetAvatar(simulator, block.ID, block.FullID);
                        uint oldSeatID = avatar.sittingOn;

                        avatar.ID = block.FullID;
                        avatar.LocalID = block.ID;
                        avatar.CollisionPlane = collisionPlane;
                        avatar.Position = position;
                        avatar.Velocity = velocity;
                        avatar.Acceleration = acceleration;
                        avatar.Rotation = rotation;
                        avatar.AngularVelocity = angularVelocity;
                        avatar.NameValues = nameValues;
                        avatar.Data = data;
                        avatar.GenericData = block.Data;
                        avatar.sittingOn = block.ParentID;

                        SetAvatarSittingOn(simulator, avatar, block.ParentID, oldSeatID);

                        // Set the current simulator for this avatar
                        avatar.CurrentSim = simulator;

                        // Textures
                        avatar.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, 
                            block.TextureEntry.Length);

                        #endregion Create an Avatar from the decoded data

                        FireOnNewAvatar(simulator, avatar, update.RegionData.RegionHandle, 
                            update.RegionData.TimeDilation);

                        break;
                    #endregion Avatar
                    case PCode.ParticleSystem:
                        DecodeParticleUpdate(block);
                        // TODO: Create a callback for particle updates
                        break;
                    default:
                        Client.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + pcode.ToString());
                        break;
                }
            }
        }