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; }
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; } }
public Guid UnpackGuid() { if (bitPos != 0) throw new IndexOutOfRangeException(); Guid val = new Guid(); val.FromBytes(Data, bytePos); bytePos += 16; return val; }
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 }
/// <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; } } }
/// <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("------"); */ }
/// <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); } } }