Пример #1
0
        private static OSD ParseLLSDBinaryElement(Stream stream)
        {
            SkipWhiteSpace(stream);
            OSD osd;

            int marker = stream.ReadByte();
            if (marker < 0)
                throw new OSDException("Binary LLSD parsing: Unexpected end of stream.");

            switch ((byte)marker)
            {
                case undefBinaryValue:
                    osd = new OSD();
                    break;
                case trueBinaryValue:
                    osd = OSD.FromBoolean(true);
                    break;
                case falseBinaryValue:
                    osd = OSD.FromBoolean(false);
                    break;
                case integerBinaryMarker:
                    int integer = NetworkToHostInt(ConsumeBytes(stream, int32Length));
                    osd = OSD.FromInteger(integer);
                    break;
                case realBinaryMarker:
                    double dbl = NetworkToHostDouble(ConsumeBytes(stream, doubleLength));
                    osd = OSD.FromReal(dbl);
                    break;
                case GuidBinaryMarker:
                    Guid guid = new Guid();
                    guid.FromBytes(ConsumeBytes(stream, 16), 0);
                    osd = OSD.FromGuid(guid);
                    break;
                case binaryBinaryMarker:
                    int binaryLength = NetworkToHostInt(ConsumeBytes(stream, int32Length));
                    osd = OSD.FromBinary(ConsumeBytes(stream, binaryLength));
                    break;
                case stringBinaryMarker:
                    int stringLength = NetworkToHostInt(ConsumeBytes(stream, int32Length));
                    string ss = Encoding.UTF8.GetString(ConsumeBytes(stream, stringLength));
                    osd = OSD.FromString(ss);
                    break;
                case uriBinaryMarker:
                    int uriLength = NetworkToHostInt(ConsumeBytes(stream, int32Length));
                    string sUri = Encoding.UTF8.GetString(ConsumeBytes(stream, uriLength));
                    Uri uri;
                    try
                    {
                        uri = new Uri(sUri, UriKind.RelativeOrAbsolute);
                    }
                    catch
                    {
                        throw new OSDException("Binary LLSD parsing: Invalid Uri format detected.");
                    }
                    osd = OSD.FromUri(uri);
                    break;
                case dateBinaryMarker:
                    double timestamp = NetworkToHostDouble(ConsumeBytes(stream, doubleLength));
                    DateTime dateTime = DateTime.SpecifyKind(Utils.Epoch, DateTimeKind.Utc);
                    dateTime = dateTime.AddSeconds(timestamp);
                    osd = OSD.FromDate(dateTime.ToLocalTime());
                    break;
                case arrayBeginBinaryMarker:
                    osd = ParseLLSDBinaryArray(stream);
                    break;
                case mapBeginBinaryMarker:
                    osd = ParseLLSDBinaryMap(stream);
                    break;
                default:
                    throw new OSDException("Binary LLSD parsing: Unknown type marker.");

            }
            return osd;
        }
Пример #2
0
        public Guid GuidFromVoiceAccount(string accountName)
        {
            if (accountName.Length == 25 && accountName[0] == 'x' && accountName[23] == '=' && accountName[24] == '=')
            {
                accountName = accountName.Replace('/', '_').Replace('+', '-');
                byte[] idBytes = Convert.FromBase64String(accountName);

                if (idBytes.Length == 16)
                {
                    Guid guid = new Guid();
                    guid.FromBytes(idBytes, 0);
                    return guid;
                }
                else
                {
                    return Guid.Empty;
                }
            }
            else
            {
                return Guid.Empty;
            }
        }
Пример #3
0
        public Guid UnpackGuid()
        {
            if (bitPos != 0) throw new IndexOutOfRangeException();

            Guid val = new Guid();
            val.FromBytes(Data, bytePos);
            bytePos += 16;
            return val;
        }
Пример #4
0
            private void FromBytes(byte[] data, int pos, int length)
            {
                if (length <= 0)
                {
                    // No TextureEntry to process
                    DefaultTexture = null;
                    return;
                }
                else
                {
                    DefaultTexture = new TextureEntryFace(null);
                }

                uint bitfieldSize = 0;
                uint faceBits = 0;
                int i = pos;

                #region Texture
                DefaultTexture.TextureID = new Guid();
                DefaultTexture.TextureID.FromBytes(data, i);
                i += 16;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    Guid tmpGuid = new Guid();
                    tmpGuid.FromBytes(data, i);
                    i += 16;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).TextureID = tmpGuid;
                }
                #endregion Texture

                #region Color
                DefaultTexture.RGBA = new Color4(data, i, true);
                i += 4;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    Color4 tmpColor = new Color4(data, i, true);
                    i += 4;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).RGBA = tmpColor;
                }
                #endregion Color

                #region RepeatU
                DefaultTexture.RepeatU = Utils.BytesToFloat(data, i);
                i += 4;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    float tmpFloat = Utils.BytesToFloat(data, i);
                    i += 4;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).RepeatU = tmpFloat;
                }
                #endregion RepeatU

                #region RepeatV
                DefaultTexture.RepeatV = Utils.BytesToFloat(data, i);
                i += 4;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    float tmpFloat = Utils.BytesToFloat(data, i);
                    i += 4;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).RepeatV = tmpFloat;
                }
                #endregion RepeatV

                #region OffsetU
                DefaultTexture.OffsetU = Helpers.TEOffsetFloat(data, i);
                i += 2;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    float tmpFloat = Helpers.TEOffsetFloat(data, i);
                    i += 2;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).OffsetU = tmpFloat;
                }
                #endregion OffsetU

                #region OffsetV
                DefaultTexture.OffsetV = Helpers.TEOffsetFloat(data, i);
                i += 2;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    float tmpFloat = Helpers.TEOffsetFloat(data, i);
                    i += 2;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).OffsetV = tmpFloat;
                }
                #endregion OffsetV

                #region Rotation
                DefaultTexture.Rotation = Helpers.TERotationFloat(data, i);
                i += 2;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    float tmpFloat = Helpers.TERotationFloat(data, i);
                    i += 2;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).Rotation = tmpFloat;
                }
                #endregion Rotation

                #region Material
                DefaultTexture.material = data[i];
                i++;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    byte tmpByte = data[i];
                    i++;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).material = tmpByte;
                }
                #endregion Material

                #region Media
                DefaultTexture.media = data[i];
                i++;

                while (i - pos < length && ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    byte tmpByte = data[i];
                    i++;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).media = tmpByte;
                }
                #endregion Media

                #region Glow
                DefaultTexture.Glow = Helpers.TEGlowFloat(data, i);
                i++;

                while (ReadFaceBitfield(data, ref i, ref faceBits, ref bitfieldSize))
                {
                    float tmpFloat = Helpers.TEGlowFloat(data, i);
                    i++;

                    for (uint face = 0, bit = 1; face < bitfieldSize; face++, bit <<= 1)
                        if ((faceBits & bit) != 0)
                            CreateFace(face).Glow = tmpFloat;
                }
 	  	        #endregion Glow
            }
Пример #5
0
        /// <summary>
        /// Process an incoming effect
        /// </summary>
        private void ViewerEffectHandler(Packet packet, Simulator simulator)
        {
            ViewerEffectPacket effect = (ViewerEffectPacket)packet;

            foreach (ViewerEffectPacket.EffectBlock block in effect.Effect)
            {
                EffectType type = (EffectType)block.Type;

                //Color4 color;
                //if (block.Color.Length == 4)
                //{
                //    color = new Color4(block.Color, 0);
                //}
                //else
                //{
                //    Client.Log("Received a ViewerEffect.EffectBlock.Color array with " + block.Color.Length + 
                //        " bytes", Helpers.LogLevel.Warning);
                //    color = Color4.Black;
                //}

                // Each ViewerEffect type uses it's own custom binary format for additional data. Fun eh?
                switch (type)
                {
                    case EffectType.Text:
                        Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!",
                            Helpers.LogLevel.Warning, Client);
                        break;
                    case EffectType.Icon:
                        Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!",
                            Helpers.LogLevel.Warning, Client);
                        break;
                    case EffectType.Connector:
                        Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!",
                            Helpers.LogLevel.Warning, Client);
                        break;
                    case EffectType.FlexibleObject:
                        Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!",
                            Helpers.LogLevel.Warning, Client);
                        break;
                    case EffectType.AnimalControls:
                        Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!",
                            Helpers.LogLevel.Warning, Client);
                        break;
                    case EffectType.AnimationObject:
                        Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!",
                            Helpers.LogLevel.Warning, Client);
                        break;
                    case EffectType.Cloth:
                        Logger.Log("Received a ViewerEffect of type " + type.ToString() + ", implement me!",
                            Helpers.LogLevel.Warning, Client);
                        break;
                    case EffectType.Glow:
                        Logger.Log("Received a Glow ViewerEffect which is not implemented yet",
                            Helpers.LogLevel.Warning, Client);
                        break;
                    case EffectType.Beam:
                    case EffectType.Point:
                    case EffectType.Trail:
                    case EffectType.Sphere:
                    case EffectType.Spiral:
                    case EffectType.Edit:
                        if (OnEffect != null)
                        {
                            if (block.TypeData.Length == 56)
                            {
                                Guid sourceAvatar = new Guid();
                                sourceAvatar.FromBytes(block.TypeData, 0);
                                Guid targetObject = new Guid();
                                targetObject.FromBytes(block.TypeData, 16);
                                Vector3d targetPos = new Vector3d(block.TypeData, 32);

                                try { OnEffect(type, sourceAvatar, targetObject, targetPos, block.Duration, block.ID); }
                                catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                            }
                            else
                            {
                                Logger.Log("Received a " + type.ToString() + 
                                    " ViewerEffect with an incorrect TypeData size of " +
                                    block.TypeData.Length + " bytes", Helpers.LogLevel.Warning, Client);
                            }
                        }
                        break;
                    case EffectType.LookAt:
                        if (OnLookAt != null)
                        {
                            if (block.TypeData.Length == 57)
                            {
                                Guid sourceAvatar = new Guid();
                                sourceAvatar.FromBytes(block.TypeData, 0);
                                Guid targetObject = new Guid();
                                targetObject.FromBytes(block.TypeData, 16);
                                Vector3d targetPos = new Vector3d(block.TypeData, 32);
                                LookAtType lookAt = (LookAtType)block.TypeData[56];

                                try { OnLookAt(sourceAvatar, targetObject, targetPos, lookAt, block.Duration,
                                    block.ID); }
                                catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                            }
                            else
                            {
                                Logger.Log("Received a LookAt ViewerEffect with an incorrect TypeData size of " +
                                    block.TypeData.Length + " bytes", Helpers.LogLevel.Warning, Client);
                            }
                        }
                        break;
                    case EffectType.PointAt:
                        if (OnPointAt != null)
                        {
                            if (block.TypeData.Length == 57)
                            {
                                Guid sourceAvatar = new Guid();
                                sourceAvatar.FromBytes(block.TypeData, 0);
                                Guid targetObject = new Guid();
                                targetObject.FromBytes(block.TypeData, 16);
                                Vector3d targetPos = new Vector3d(block.TypeData, 32);
                                PointAtType pointAt = (PointAtType)block.TypeData[56];

                                try { OnPointAt(sourceAvatar, targetObject, targetPos, pointAt, block.Duration, 
                                    block.ID); }
                                catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                            }
                            else
                            {
                                Logger.Log("Received a PointAt ViewerEffect with an incorrect TypeData size of " +
                                    block.TypeData.Length + " bytes", Helpers.LogLevel.Warning, Client);
                            }
                        }
                        break;
                    default:
                        Logger.Log("Received a ViewerEffect with an unknown type " + type, Helpers.LogLevel.Warning, Client);
                        break;
                }
            }
        }
Пример #6
0
        /// <summary></summary>
        /// <param name="packet"></param>
        /// <param name="simulator"></param>
        private void EstateOwnerMessageHandler(Packet packet, Simulator simulator)
        {
            EstateOwnerMessagePacket message = (EstateOwnerMessagePacket)packet;
            uint estateID;
            string method = Utils.BytesToString(message.MethodData.Method);
            //List<string> parameters = new List<string>();

            if (method == "estateupdateinfo")
            {
                string estateName = Utils.BytesToString(message.ParamList[0].Parameter);
                Guid estateOwner = new Guid(Utils.BytesToString(message.ParamList[1].Parameter));
                estateID = Utils.BytesToUInt(message.ParamList[2].Parameter);
                /*
                foreach (EstateOwnerMessagePacket.ParamListBlock param in message.ParamList)
                {
                    parameters.Add(Utils.BytesToString(param.Parameter));
                }
                */
                bool denyNoPaymentInfo;
                if (Utils.BytesToUInt(message.ParamList[8].Parameter) == 0) denyNoPaymentInfo = true;
                else denyNoPaymentInfo = false;

                if (OnGetEstateUpdateInfo != null)
                {
                    try
                    {
                        OnGetEstateUpdateInfo(estateName, estateOwner, estateID, denyNoPaymentInfo);
                    }
                    catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                }
            }

            else if (method == "setaccess")
            {
                int count;
                estateID = Utils.BytesToUInt(message.ParamList[0].Parameter);
                if (message.ParamList.Length > 1)
                {
                    //param comes in as a string for some reason
                    uint param;
                    if (!uint.TryParse(Utils.BytesToString(message.ParamList[1].Parameter), out param)) return;

                    EstateAccessReplyDelta accessType = (EstateAccessReplyDelta)param;

                    switch (accessType)
                    {
                        case EstateAccessReplyDelta.EstateManagers:
                            if (OnGetEstateManagers != null)
                            {
                                if (message.ParamList.Length > 5)
                                {
                                    if (!int.TryParse(Utils.BytesToString(message.ParamList[5].Parameter), out count)) return;
                                    List<Guid> managers = new List<Guid>();
                                    for (int i = 6; i < message.ParamList.Length; i++)
                                    {
                                        try
                                        {
                                            Guid managerID = new Guid();
                                            managerID.FromBytes(message.ParamList[i].Parameter, 0);
                                            managers.Add(managerID);
                                        }
                                        catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                                    }
                                    try { OnGetEstateManagers(estateID, count, managers); }
                                    catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                                }
                            }
                            break;

                        case EstateAccessReplyDelta.EstateBans:
                            if (OnGetEstateBans != null)
                            {
                                if (message.ParamList.Length > 6)
                                {
                                    if (!int.TryParse(Utils.BytesToString(message.ParamList[4].Parameter), out count)) return;
                                    List<Guid> bannedUsers = new List<Guid>();
                                    for (int i = 7; i < message.ParamList.Length; i++)
                                    {
                                        try
                                        {
                                            Guid bannedID = new Guid();
                                            bannedID.FromBytes(message.ParamList[i].Parameter, 0);
                                            bannedUsers.Add(bannedID);
                                        }
                                        catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                                    }
                                    try { OnGetEstateBans(estateID, count, bannedUsers); }
                                    catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                                }
                            }
                            break;

                        case EstateAccessReplyDelta.AllowedUsers:
                            if (OnGetAllowedUsers != null)
                            {
                                if (message.ParamList.Length > 5)
                                {
                                    if (!int.TryParse(Utils.BytesToString(message.ParamList[2].Parameter), out count)) return;
                                    List<Guid> allowedUsers = new List<Guid>();
                                    for (int i = 6; i < message.ParamList.Length; i++)
                                    {
                                        try
                                        {
                                            Guid allowedID = new Guid();
                                            allowedID.FromBytes(message.ParamList[i].Parameter, 0);
                                            allowedUsers.Add(allowedID);
                                        }
                                        catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                                    }
                                    try { OnGetAllowedUsers(estateID, count, allowedUsers); }
                                    catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                                }
                            }
                            break;

                        case EstateAccessReplyDelta.AllowedGroups:
                            if (OnGetAllowedGroups != null)
                            {
                                if (message.ParamList.Length > 5)
                                {
                                    if (!int.TryParse(Utils.BytesToString(message.ParamList[3].Parameter), out count)) return;
                                    List<Guid> allowedGroups = new List<Guid>();
                                    for (int i = 5; i < message.ParamList.Length; i++)
                                    {
                                        try
                                        {
                                            Guid groupID = new Guid();
                                            groupID.FromBytes(message.ParamList[i].Parameter, 0);
                                            allowedGroups.Add(groupID);
                                        }
                                        catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                                    }
                                    try { OnGetAllowedGroups(estateID, count, allowedGroups); }
                                    catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                                }
                            }
                            break;
                    }
                }
            }

            /*
            Console.WriteLine("--- " + method + " ---");
            foreach (EstateOwnerMessagePacket.ParamListBlock block in message.ParamList)
            {
                Console.WriteLine(Utils.BytesToString(block.Parameter));
            }
            Console.WriteLine("------");
            */
        }
Пример #7
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
                {
                    // Guid
                    Guid fullID = new Guid();
                    fullID.FromBytes(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 = (PrimFlags)block.UpdateFlags;
                    prim.PrimData.PCode = pcode;

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

                            // State
                            prim.PrimData.State = block.Data[i++];
                            // CRC
                            i += 4;
                            // Material
                            prim.PrimData.Material = (Material)block.Data[i++];
                            // Click action
                            prim.ClickAction = (ClickAction)block.Data[i++];
                            // Scale
                            prim.Scale.FromBytes(block.Data, i);
                            i += 12;
                            // Position
                            prim.Position.FromBytes(block.Data, i);
                            i += 12;
                            // Rotation
                            prim.Rotation.FromBytes(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.PrimData.State = block.Data[i++];
                            // CRC
                            i += 4;
                            // Material
                            prim.PrimData.Material = (Material)block.Data[i++];
                            // Click action
                            prim.ClickAction = (ClickAction)block.Data[i++];
                            // Scale
                            prim.Scale.FromBytes(block.Data, i);
                            i += 12;
                            // Position
                            prim.Position.FromBytes(block.Data, i);
                            i += 12;
                            // Rotation
                            prim.Rotation.FromBytes(block.Data, i, true);
                            i += 12;
                            // Compressed flags
                            CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block.Data, i);
                            i += 4;

                            prim.OwnerID.FromBytes(block.Data, i);
                            i += 16;
			                
                            // Angular velocity
                            if ((flags & CompressedFlags.HasAngularVelocity) != 0)
                            {
                                prim.AngularVelocity.FromBytes(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 Color4(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.FromBytes(block.Data, i);
                                i += 16;

                                prim.SoundGain = Utils.BytesToFloat(block.Data, i);
                                i += 4;
                                prim.SoundFlags = block.Data[i++];
                                prim.SoundRadius = Utils.BytesToFloat(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.PrimData.PathCurve = (PathCurve)block.Data[i++];
                            ushort pathBegin = Utils.BytesToUInt16(block.Data, i); i += 2;
                            prim.PrimData.PathBegin = Primitive.UnpackBeginCut(pathBegin);
                            ushort pathEnd = Utils.BytesToUInt16(block.Data, i); i += 2;
                            prim.PrimData.PathEnd = Primitive.UnpackEndCut(pathEnd);
                            prim.PrimData.PathScaleX = Primitive.UnpackPathScale(block.Data[i++]);
                            prim.PrimData.PathScaleY = Primitive.UnpackPathScale(block.Data[i++]);
                            prim.PrimData.PathShearX = Primitive.UnpackPathShear((sbyte)block.Data[i++]);
                            prim.PrimData.PathShearY = Primitive.UnpackPathShear((sbyte)block.Data[i++]);
                            prim.PrimData.PathTwist = Primitive.UnpackPathTwist((sbyte)block.Data[i++]);
                            prim.PrimData.PathTwistBegin = Primitive.UnpackPathTwist((sbyte)block.Data[i++]);
                            prim.PrimData.PathRadiusOffset = Primitive.UnpackPathTwist((sbyte)block.Data[i++]);
                            prim.PrimData.PathTaperX = Primitive.UnpackPathTaper((sbyte)block.Data[i++]);
                            prim.PrimData.PathTaperY = Primitive.UnpackPathTaper((sbyte)block.Data[i++]);
                            prim.PrimData.PathRevolutions = Primitive.UnpackPathRevolutions(block.Data[i++]);
                            prim.PrimData.PathSkew = Primitive.UnpackPathTwist((sbyte)block.Data[i++]);

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

                            // TextureEntry
                            int textureEntryLength = (int)Utils.BytesToUInt(block.Data, i);
                            i += 4;
                            prim.Textures = new Primitive.TextureEntry(block.Data, i, textureEntryLength);
                            i += textureEntryLength;

                            // Texture animation
                            if ((flags & CompressedFlags.TextureAnimation) != 0)
                            {
                                //int textureAnimLength = (int)Utils.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:
                            Logger.DebugLog("Got an ObjectUpdateCompressed for PCode " + pcode.ToString() +
                                ", implement this!", Client);
                            break;
                    }
                }
                catch (IndexOutOfRangeException e)
                {
                    Logger.Log("Error decoding an ObjectUpdateCompressed packet", Helpers.LogLevel.Warning, Client, e);
                    Logger.Log(block, Helpers.LogLevel.Warning);
                }
            }
        }