Пример #1
0
        private void CompressedUpdateHandler(Packet packet, Simulator simulator)
        {
            ObjectUpdateCompressedPacket update = (ObjectUpdateCompressedPacket)packet;
            PrimObject prim;

            foreach (ObjectUpdateCompressedPacket.ObjectDataBlock block in update.ObjectData)
            {
                int i = 0;
                prim = new PrimObject(Client);

                try
                {
                    prim.ID      = new LLUUID(block.Data, 0);
                    i           += 16;
                    prim.LocalID = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
                                          (block.Data[i++] << 16) + (block.Data[i++] << 24));

                    byte pcode = block.Data[i++];

                    if (pcode == (byte)PCode.Prim)
                    {
                        #region PrimRegion
                        prim.State    = (uint)block.Data[i++];
                        i            += 4; // CRC
                        prim.Material = (uint)block.Data[i++];
                        i++;               // TODO: ClickAction

                        prim.Scale    = new LLVector3(block.Data, i);
                        i            += 12;
                        prim.Position = new LLVector3(block.Data, i);
                        i            += 12;
                        prim.Rotation = new LLQuaternion(block.Data, i, true);
                        i            += 12;

                        uint flags = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
                                            (block.Data[i++] << 16) + (block.Data[i++] << 24));

                        if ((flags & 0x02) != 0)
                        {
                            byte TreeData = block.Data[i++];

                            // TODO: Unknown byte
                            i++;

                            if (OnNewPrim != null)
                            {
                                OnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
                            }
                            continue;
                        }

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

                        if ((flags & 0x80) != 0)
                        {
                            // TODO: Use this. What is it?
                            LLVector3 Omega = new LLVector3(block.Data, i);
                            i += 12;
                        }

                        if ((flags & 0x04) != 0)
                        {
                            string text = "";
                            while (block.Data[i] != 0)
                            {
                                text += (char)block.Data[i];
                                i++;
                            }
                            prim.Text = text;
                            i++;

                            // Text color
                            i += 4;
                        }
                        else
                        {
                            prim.Text = "";
                        }

                        if ((flags & 0x08) != 0)
                        {
                            prim.ParticleSys = new ParticleSystem(block.Data, i);
                            i += 86;
                        }

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

                        //Sound data
                        if ((flags & 0x10) != 0)
                        {
                            //TODO: use this data
                            LLUUID SoundUUID = new LLUUID(block.Data, i);
                            i += 16;
                            LLUUID OwnerUUID = new LLUUID(block.Data, i);
                            i += 16;

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

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

                        //Indicates that this is an attachment?
                        if ((flags & 0x100) != 0)
                        {
                            //A string
                            //Example: "AttachItemID STRING RW SV fa9a5ab8-1bad-b449-9873-cf5b803e664e"
                            while (block.Data[i] != 0)
                            {
                                i++;
                            }
                            i++;
                        }

                        prim.PathCurve        = (uint)block.Data[i++];
                        prim.PathBegin        = PrimObject.PathBeginFloat(block.Data[i++]);
                        prim.PathEnd          = PrimObject.PathEndFloat(block.Data[i++]);
                        prim.PathTaperX       = PrimObject.PathScaleFloat(block.Data[i++]);
                        prim.PathTaperY       = PrimObject.PathScaleFloat(block.Data[i++]);
                        prim.PathShearX       = PrimObject.PathShearFloat(block.Data[i++]);
                        prim.PathShearY       = PrimObject.PathShearFloat(block.Data[i++]);
                        prim.PathTwist        = (int)block.Data[i++];
                        prim.PathTwistBegin   = (int)block.Data[i++];
                        prim.PathRadiusOffset = PrimObject.PathRadiusOffsetFloat((sbyte)block.Data[i++]);
                        //prim.PathTaperX = PrimObject.PathTaperFloat(block.Data[i++]);
                        //prim.PathTaperY = PrimObject.PathTaperFloat(block.Data[i++]);
                        i += 2;
                        prim.PathRevolutions = PrimObject.PathRevolutionsFloat(block.Data[i++]);
                        prim.PathSkew        = PrimObject.PathSkewFloat(block.Data[i++]);

                        prim.ProfileCurve  = (uint)block.Data[i++];
                        prim.ProfileBegin  = PrimObject.ProfileBeginFloat(block.Data[i++]);
                        prim.ProfileEnd    = PrimObject.ProfileEndFloat(block.Data[i++]);
                        prim.ProfileHollow = (uint)block.Data[i++];

                        int textureEntryLength = (int)(block.Data[i++] + (block.Data[i++] << 8) +
                                                       (block.Data[i++] << 16) + (block.Data[i++] << 24));

                        prim.Textures = new TextureEntry(block.Data, i, textureEntryLength);

                        i += textureEntryLength;

                        if (i < block.Data.Length)
                        {
                            int textureAnimLength = (int)(block.Data[i++] + (block.Data[i++] << 8) +
                                                          (block.Data[i++] << 16) + (block.Data[i++] << 24));

                            prim.TextureAnim = new TextureAnimation(block.Data, i);
                        }

                        if (OnNewPrim != null)
                        {
                            OnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation);
                        }

                        #endregion PrimRegion
                    }
                    else if (pcode == (byte)PCode.Avatar)
                    {
                        Client.Log("######### Got an ObjectUpdateCompressed for an avatar, implement this! #########",
                                   Helpers.LogLevel.Warning);
                    }
                    else if (pcode == (byte)PCode.Grass || pcode == (byte)PCode.Tree)
                    {
                        // TODO: Add new_tree and any other tree-like prims
                        ;
                    }
                    else
                    {
                        // TODO: ...
                        continue;
                    }
                }
                catch (System.IndexOutOfRangeException e)
                {
                    Client.Log("Had a problem decoding an ObjectUpdateCompressed packet: " +
                               e.ToString(), Helpers.LogLevel.Warning);
                    Client.Log(block.ToString(), Helpers.LogLevel.Warning);
                }
            }
        }
Пример #2
0
        void SendObjectPacket(SimulationObject obj, bool canUseCompressed, bool canUseImproved, PrimFlags creatorFlags, UpdateFlags updateFlags)
        {
            if (!canUseImproved && !canUseCompressed)
            {
                #region ObjectUpdate

                Logger.DebugLog("Sending ObjectUpdate");

                if (sceneAgents.ContainsKey(obj.Prim.OwnerID))
                {
                    // Send an update out to the creator
                    ObjectUpdatePacket updateToOwner = new ObjectUpdatePacket();
                    updateToOwner.RegionData.RegionHandle = regionHandle;
                    updateToOwner.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue);
                    updateToOwner.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
                    updateToOwner.ObjectData[0] = SimulationObject.BuildUpdateBlock(obj.Prim,
                        obj.Prim.Flags | creatorFlags | PrimFlags.ObjectYouOwner, obj.CRC);

                    udp.SendPacket(obj.Prim.OwnerID, updateToOwner, PacketCategory.State);
                }

                // Send an update out to everyone else
                ObjectUpdatePacket updateToOthers = new ObjectUpdatePacket();
                updateToOthers.RegionData.RegionHandle = regionHandle;
                updateToOthers.RegionData.TimeDilation = UInt16.MaxValue;
                updateToOthers.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
                updateToOthers.ObjectData[0] = SimulationObject.BuildUpdateBlock(obj.Prim,
                    obj.Prim.Flags, obj.CRC);

                ForEachAgent(
                    delegate(Agent recipient)
                    {
                        if (recipient.ID != obj.Prim.OwnerID)
                            udp.SendPacket(recipient.ID, updateToOthers, PacketCategory.State);
                    }
                );

                #endregion ObjectUpdate
            }
            else if (!canUseImproved)
            {
                #region ObjectUpdateCompressed

                #region Size calculation and field serialization

                CompressedFlags flags = 0;
                int size = 84;
                byte[] textBytes = null;
                byte[] mediaURLBytes = null;
                byte[] particleBytes = null;
                byte[] extraParamBytes = null;
                byte[] nameValueBytes = null;
                byte[] textureBytes = null;
                byte[] textureAnimBytes = null;

                if ((updateFlags & UpdateFlags.AngularVelocity) != 0)
                {
                    flags |= CompressedFlags.HasAngularVelocity;
                    size += 12;
                }
                if ((updateFlags & UpdateFlags.ParentID) != 0)
                {
                    flags |= CompressedFlags.HasParent;
                    size += 4;
                }
                if ((updateFlags & UpdateFlags.ScratchPad) != 0)
                {
                    switch (obj.Prim.PrimData.PCode)
                    {
                        case PCode.Grass:
                        case PCode.Tree:
                        case PCode.NewTree:
                            flags |= CompressedFlags.Tree;
                            size += 2; // Size byte plus one byte
                            break;
                        default:
                            flags |= CompressedFlags.ScratchPad;
                            size += 1 + obj.Prim.ScratchPad.Length; // Size byte plus bytes
                            break;
                    }
                }
                if ((updateFlags & UpdateFlags.Text) != 0)
                {
                    flags |= CompressedFlags.HasText;
                    textBytes = Utils.StringToBytes(obj.Prim.Text);
                    size += textBytes.Length; // Null-terminated, no size byte
                    size += 4; // Text color
                }
                if ((updateFlags & UpdateFlags.MediaURL) != 0)
                {
                    flags |= CompressedFlags.MediaURL;
                    mediaURLBytes = Utils.StringToBytes(obj.Prim.MediaURL);
                    size += mediaURLBytes.Length; // Null-terminated, no size byte
                }
                if ((updateFlags & UpdateFlags.Particles) != 0)
                {
                    flags |= CompressedFlags.HasParticles;
                    particleBytes = obj.Prim.ParticleSys.GetBytes();
                    size += particleBytes.Length; // Should be exactly 86 bytes
                }

                // Extra Params
                extraParamBytes = obj.Prim.GetExtraParamsBytes();
                size += extraParamBytes.Length;

                if ((updateFlags & UpdateFlags.Sound) != 0)
                {
                    flags |= CompressedFlags.HasSound;
                    size += 25; // SoundID, SoundGain, SoundFlags, SoundRadius
                }
                if ((updateFlags & UpdateFlags.NameValue) != 0)
                {
                    flags |= CompressedFlags.HasNameValues;
                    nameValueBytes = Utils.StringToBytes(NameValue.NameValuesToString(obj.Prim.NameValues));
                    size += nameValueBytes.Length; // Null-terminated, no size byte
                }

                size += 23; // PrimData
                size += 4; // Texture Length
                textureBytes = obj.Prim.Textures.GetBytes();
                size += textureBytes.Length; // Texture Entry

                if ((updateFlags & UpdateFlags.TextureAnim) != 0)
                {
                    flags |= CompressedFlags.TextureAnimation;
                    size += 4; // TextureAnim Length
                    textureAnimBytes = obj.Prim.TextureAnim.GetBytes();
                    size += textureAnimBytes.Length; // TextureAnim
                }

                #endregion Size calculation and field serialization

                #region Packet serialization

                int pos = 0;
                byte[] data = new byte[size];

                // UUID
                obj.Prim.ID.ToBytes(data, 0);
                pos += 16;
                // LocalID
                Utils.UIntToBytes(obj.Prim.LocalID, data, pos);
                pos += 4;
                // PCode
                data[pos++] = (byte)obj.Prim.PrimData.PCode;
                // State
                data[pos++] = obj.Prim.PrimData.State;
                // CRC
                Utils.UIntToBytes(obj.CRC, data, pos);
                pos += 4;
                // Material
                data[pos++] = (byte)obj.Prim.PrimData.Material;
                // ClickAction
                data[pos++] = (byte)obj.Prim.ClickAction;
                // Scale
                obj.Prim.Scale.ToBytes(data, pos);
                pos += 12;
                // Position
                obj.Prim.Position.ToBytes(data, pos);
                pos += 12;
                // Rotation
                obj.Prim.Rotation.ToBytes(data, pos);
                pos += 12;
                // Compressed Flags
                Utils.UIntToBytes((uint)flags, data, pos);
                pos += 4;
                // OwnerID
                obj.Prim.OwnerID.ToBytes(data, pos);
                pos += 16;

                if ((flags & CompressedFlags.HasAngularVelocity) != 0)
                {
                    obj.Prim.AngularVelocity.ToBytes(data, pos);
                    pos += 12;
                }
                if ((flags & CompressedFlags.HasParent) != 0)
                {
                    Utils.UIntToBytes(obj.Prim.ParentID, data, pos);
                    pos += 4;
                }
                if ((flags & CompressedFlags.ScratchPad) != 0)
                {
                    data[pos++] = (byte)obj.Prim.ScratchPad.Length;
                    Buffer.BlockCopy(obj.Prim.ScratchPad, 0, data, pos, obj.Prim.ScratchPad.Length);
                    pos += obj.Prim.ScratchPad.Length;
                }
                else if ((flags & CompressedFlags.Tree) != 0)
                {
                    data[pos++] = 1;
                    data[pos++] = (byte)obj.Prim.TreeSpecies;
                }
                if ((flags & CompressedFlags.HasText) != 0)
                {
                    Buffer.BlockCopy(textBytes, 0, data, pos, textBytes.Length);
                    pos += textBytes.Length;
                    obj.Prim.TextColor.ToBytes(data, pos, false);
                    pos += 4;
                }
                if ((flags & CompressedFlags.MediaURL) != 0)
                {
                    Buffer.BlockCopy(mediaURLBytes, 0, data, pos, mediaURLBytes.Length);
                    pos += mediaURLBytes.Length;
                }
                if ((flags & CompressedFlags.HasParticles) != 0)
                {
                    Buffer.BlockCopy(particleBytes, 0, data, pos, particleBytes.Length);
                    pos += particleBytes.Length;
                }

                // Extra Params
                Buffer.BlockCopy(extraParamBytes, 0, data, pos, extraParamBytes.Length);
                pos += extraParamBytes.Length;

                if ((flags & CompressedFlags.HasSound) != 0)
                {
                    obj.Prim.Sound.ToBytes(data, pos);
                    pos += 16;
                    Utils.FloatToBytes(obj.Prim.SoundGain, data, pos);
                    pos += 4;
                    data[pos++] = (byte)obj.Prim.SoundFlags;
                    Utils.FloatToBytes(obj.Prim.SoundRadius, data, pos);
                    pos += 4;
                }
                if ((flags & CompressedFlags.HasNameValues) != 0)
                {
                    Buffer.BlockCopy(nameValueBytes, 0, data, pos, nameValueBytes.Length);
                    pos += nameValueBytes.Length;
                }

                // Path PrimData
                data[pos++] = (byte)obj.Prim.PrimData.PathCurve;
                Utils.UInt16ToBytes(Primitive.PackBeginCut(obj.Prim.PrimData.PathBegin), data, pos); pos += 2;
                Utils.UInt16ToBytes(Primitive.PackEndCut(obj.Prim.PrimData.PathEnd), data, pos); pos += 2;
                data[pos++] = Primitive.PackPathScale(obj.Prim.PrimData.PathScaleX);
                data[pos++] = Primitive.PackPathScale(obj.Prim.PrimData.PathScaleY);
                data[pos++] = (byte)Primitive.PackPathShear(obj.Prim.PrimData.PathShearX);
                data[pos++] = (byte)Primitive.PackPathShear(obj.Prim.PrimData.PathShearY);
                data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathTwist);
                data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathTwistBegin);
                data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathRadiusOffset);
                data[pos++] = (byte)Primitive.PackPathTaper(obj.Prim.PrimData.PathTaperX);
                data[pos++] = (byte)Primitive.PackPathTaper(obj.Prim.PrimData.PathTaperY);
                data[pos++] = Primitive.PackPathRevolutions(obj.Prim.PrimData.PathRevolutions);
                data[pos++] = (byte)Primitive.PackPathTwist(obj.Prim.PrimData.PathSkew);
                // Profile PrimData
                data[pos++] = obj.Prim.PrimData.profileCurve;
                Utils.UInt16ToBytes(Primitive.PackBeginCut(obj.Prim.PrimData.ProfileBegin), data, pos); pos += 2;
                Utils.UInt16ToBytes(Primitive.PackEndCut(obj.Prim.PrimData.ProfileEnd), data, pos); pos += 2;
                Utils.UInt16ToBytes(Primitive.PackProfileHollow(obj.Prim.PrimData.ProfileHollow), data, pos); pos += 2;

                // Texture Length
                Utils.UIntToBytes((uint)textureBytes.Length, data, pos);
                pos += 4;
                // Texture Entry
                Buffer.BlockCopy(textureBytes, 0, data, pos, textureBytes.Length);
                pos += textureBytes.Length;

                if ((flags & CompressedFlags.TextureAnimation) != 0)
                {
                    Utils.UIntToBytes((uint)textureAnimBytes.Length, data, pos);
                    pos += 4;
                    Buffer.BlockCopy(textureAnimBytes, 0, data, pos, textureAnimBytes.Length);
                    pos += textureAnimBytes.Length;
                }

                #endregion Packet serialization

                #region Packet sending

                //Logger.DebugLog("Sending ObjectUpdateCompressed with " + flags.ToString());

                if (sceneAgents.ContainsKey(obj.Prim.OwnerID))
                {
                    // Send an update out to the creator
                    ObjectUpdateCompressedPacket updateToOwner = new ObjectUpdateCompressedPacket();
                    updateToOwner.RegionData.RegionHandle = regionHandle;
                    updateToOwner.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue);
                    updateToOwner.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[1];
                    updateToOwner.ObjectData[0] = new ObjectUpdateCompressedPacket.ObjectDataBlock();
                    updateToOwner.ObjectData[0].UpdateFlags = (uint)(obj.Prim.Flags | creatorFlags | PrimFlags.ObjectYouOwner);
                    updateToOwner.ObjectData[0].Data = data;

                    udp.SendPacket(obj.Prim.OwnerID, updateToOwner, PacketCategory.State);
                }

                // Send an update out to everyone else
                ObjectUpdateCompressedPacket updateToOthers = new ObjectUpdateCompressedPacket();
                updateToOthers.RegionData.RegionHandle = regionHandle;
                updateToOthers.RegionData.TimeDilation = UInt16.MaxValue;
                updateToOthers.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[1];
                updateToOthers.ObjectData[0] = new ObjectUpdateCompressedPacket.ObjectDataBlock();
                updateToOthers.ObjectData[0].UpdateFlags = (uint)obj.Prim.Flags;
                updateToOthers.ObjectData[0].Data = data;

                ForEachAgent(
                    delegate(Agent recipient)
                    {
                        if (recipient.ID != obj.Prim.OwnerID)
                            udp.SendPacket(recipient.ID, updateToOthers, PacketCategory.State);
                    }
                );

                #endregion Packet sending

                #endregion ObjectUpdateCompressed
            }
            else
            {
                #region ImprovedTerseObjectUpdate

                //Logger.DebugLog("Sending ImprovedTerseObjectUpdate");

                int pos = 0;
                byte[] data = new byte[(obj.Prim is Avatar ? 60 : 44)];

                // LocalID
                Utils.UIntToBytes(obj.Prim.LocalID, data, pos);
                pos += 4;
                // Avatar/CollisionPlane
                data[pos++] = obj.Prim.PrimData.State;
                if (obj.Prim is Avatar)
                {
                    data[pos++] = 1;
                    obj.Prim.CollisionPlane.ToBytes(data, pos);
                    pos += 16;
                }
                else
                {
                    ++pos;
                }
                // Position
                obj.Prim.Position.ToBytes(data, pos);
                pos += 12;

                // Velocity
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.X, -128.0f, 128.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.Y, -128.0f, 128.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Velocity.Z, -128.0f, 128.0f), data, pos); pos += 2;
                // Acceleration
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.X, -64.0f, 64.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2;
                // Rotation
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.X, -1.0f, 1.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.Y, -1.0f, 1.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.Z, -1.0f, 1.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.Rotation.W, -1.0f, 1.0f), data, pos); pos += 2;
                // Angular Velocity
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
                Utils.UInt16ToBytes(Utils.FloatToUInt16(obj.Prim.AngularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;

                ImprovedTerseObjectUpdatePacket update = new ImprovedTerseObjectUpdatePacket();
                update.RegionData.RegionHandle = RegionHandle;
                update.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue);
                update.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
                update.ObjectData[0] = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
                update.ObjectData[0].Data = data;

                if ((updateFlags & UpdateFlags.Textures) != 0)
                {
                    byte[] textureBytes = obj.Prim.Textures.GetBytes();
                    byte[] textureEntry = new byte[textureBytes.Length + 4];

                    // Texture Length
                    Utils.IntToBytes(textureBytes.Length, textureEntry, 0);
                    // Texture
                    Buffer.BlockCopy(textureBytes, 0, textureEntry, 4, textureBytes.Length);

                    update.ObjectData[0].TextureEntry = textureEntry;
                }
                else
                {
                    update.ObjectData[0].TextureEntry = Utils.EmptyBytes;
                }

                udp.BroadcastPacket(update, PacketCategory.State);

                #endregion ImprovedTerseObjectUpdate
            }
        }
Пример #3
0
        private void SendEntityPackets(QueuedInterestListEvent[] eventDatas, IScenePresence presence)
        {
            if (!(presence is LLAgent) || presence.InterestList == null)
                return;
            LLAgent agent = (LLAgent)presence;

            Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
            Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
            Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();

            for (int i = 0; i < eventDatas.Length; i++)
            {
                EntityAddOrUpdateArgs e = (EntityAddOrUpdateArgs)eventDatas[i].Event.State;
                ISceneEntity entity = e.Entity;

                #region UpdateFlags to packet type conversion

                UpdateFlags updateFlags = e.UpdateFlags;
                LLUpdateFlags llUpdateFlags = (LLUpdateFlags)e.ExtraFlags;

                bool canUseImproved = true;

                if (updateFlags.HasFlag(UpdateFlags.FullUpdate) ||
                    updateFlags.HasFlag(UpdateFlags.Parent) ||
                    updateFlags.HasFlag(UpdateFlags.Scale) ||
                    updateFlags.HasFlag(UpdateFlags.Shape) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.PrimFlags) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Text) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.NameValue) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.ExtraData) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.TextureAnim) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Sound) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Particles) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Material) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.ClickAction) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.MediaURL) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Joint))
                {
                    canUseImproved = false;
                }

                #endregion UpdateFlags to packet type conversion

                #region Block Construction

                if (!canUseImproved)
                {
                    if (entity is IScenePresence)
                        objectUpdateBlocks.Value.Add(CreateAvatarObjectUpdateBlock((IScenePresence)entity, presence));
                    else
                        objectUpdateBlocks.Value.Add(CreateObjectUpdateBlock(entity, presence));
                }
                else
                {
                    terseUpdateBlocks.Value.Add(CreateTerseUpdateBlock(entity, llUpdateFlags.HasFlag(LLUpdateFlags.Textures)));
                }

                #endregion Block Construction

                // Unset CreateSelected after it has been sent once
                if (entity is LLPrimitive)
                {
                    LLPrimitive prim = (LLPrimitive)entity;
                    prim.Prim.Flags &= ~PrimFlags.CreateSelected;
                }
            }

            #region Packet Sending

            ushort timeDilation = (m_physics != null) ?
                Utils.FloatToUInt16(m_physics.TimeDilation, 0.0f, 1.0f) :
                UInt16.MaxValue;

            if (objectUpdateBlocks.IsValueCreated)
            {
                List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;

                ObjectUpdatePacket packet = new ObjectUpdatePacket();
                packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition);
                packet.RegionData.TimeDilation = timeDilation;
                packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];

                for (int i = 0; i < blocks.Count; i++)
                    packet.ObjectData[i] = blocks[i];

                m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true);
            }

            if (compressedUpdateBlocks.IsValueCreated)
            {
                List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;

                ObjectUpdateCompressedPacket packet = new ObjectUpdateCompressedPacket();
                packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition);
                packet.RegionData.TimeDilation = timeDilation;
                packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];

                for (int i = 0; i < blocks.Count; i++)
                    packet.ObjectData[i] = blocks[i];

                m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true);
            }

            if (terseUpdateBlocks.IsValueCreated)
            {
                List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;

                ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
                packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition);
                packet.RegionData.TimeDilation = timeDilation;
                packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];

                for (int i = 0; i < blocks.Count; i++)
                    packet.ObjectData[i] = blocks[i];

                m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true);
            }

            #endregion Packet Sending
        }
Пример #4
0
        private void SendEntityPackets(QueuedInterestListEvent[] eventDatas, IScenePresence presence)
        {
            if (!(presence is LLAgent) || presence.InterestList == null)
                return;
            LLAgent agent = (LLAgent)presence;

            Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
            Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
            Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
            Lazy<List<ObjectUpdateCachedPacket.ObjectDataBlock>> cachedUpdateBlocks = new Lazy<List<ObjectUpdateCachedPacket.ObjectDataBlock>>();

            for (int i = 0; i < eventDatas.Length; i++)
            {
                EntityAddOrUpdateArgs e = (EntityAddOrUpdateArgs)eventDatas[i].Event.State;
                ISceneEntity entity = e.Entity;

                #region Determine packet type

                UpdateFlags updateFlags = e.UpdateFlags;
                LLUpdateFlags llUpdateFlags = (LLUpdateFlags)e.ExtraFlags;
                LLPrimitive prim = entity as LLPrimitive;

                bool canUseCached = false;
                bool canUseTerse = true;
                DateTime lastSeen;

                if (CACHE_CHECK_ENABLED &&
                    prim != null &&
                    updateFlags.HasFlag(UpdateFlags.FullUpdate) &&
                    !llUpdateFlags.HasFlag(LLUpdateFlags.NoCachedUpdate) &&
                    m_recentAvatars.TryGetValue(presence.ID, out lastSeen) &&
                    lastSeen > prim.LastUpdated)
                {
                    // This avatar was marked as leaving the same later than the last update
                    // timestamp of this prim. Send a cache check
                    canUseCached = true;
                }
                else if (updateFlags.HasFlag(UpdateFlags.FullUpdate) ||
                    updateFlags.HasFlag(UpdateFlags.Parent) ||
                    updateFlags.HasFlag(UpdateFlags.Scale) ||
                    updateFlags.HasFlag(UpdateFlags.Shape) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.PrimFlags) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Text) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.NameValue) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.ExtraData) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.TextureAnim) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Sound) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Particles) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Material) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.ClickAction) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.MediaURL) ||
                    llUpdateFlags.HasFlag(LLUpdateFlags.Joint))
                {
                    canUseTerse = false;
                }

                #endregion Determine packet type

                #region Block Construction

                if (canUseCached && prim != null)
                {
                    cachedUpdateBlocks.Value.Add(new ObjectUpdateCachedPacket.ObjectDataBlock
                        { CRC = prim.GetCrc(), ID = prim.LocalID });
                }
                else if (!canUseTerse)
                {
                    if (entity is IScenePresence)
                    {
                        IScenePresence thisPresence = (IScenePresence)entity;
                        ObjectUpdatePacket.ObjectDataBlock block = CreateAvatarObjectUpdateBlock(thisPresence);
                        block.UpdateFlags = (uint)GetUpdateFlags(thisPresence, presence);
                        objectUpdateBlocks.Value.Add(block);
                    }
                    else if (prim != null)
                    {
                        ObjectUpdateCompressedPacket.ObjectDataBlock block = CreateCompressedObjectUpdateBlock(prim, prim.GetCrc());
                        block.UpdateFlags = (uint)GetUpdateFlags(prim, presence, m_permissions);
                        compressedUpdateBlocks.Value.Add(block);

                        // ObjectUpdateCompressed doesn't carry velocity or acceleration fields, so
                        // we need to send a separate terse packet if this prim has a non-zero
                        // velocity or acceleration
                        if (prim.Velocity != Vector3.Zero || prim.Acceleration != Vector3.Zero)
                            terseUpdateBlocks.Value.Add(CreateTerseUpdateBlock(entity, false));

                        //ObjectUpdatePacket.ObjectDataBlock block = CreateObjectUpdateBlock(prim);
                        //block.UpdateFlags = (uint)GetUpdateFlags(prim, presence, m_permissions);
                        //block.CRC = prim.GetCrc();
                        //objectUpdateBlocks.Value.Add(block);
                    }
                    else
                    {
                        // TODO: Create a generic representation for non-LLPrimitive entities?
                        continue;
                    }
                }
                else
                {
                    terseUpdateBlocks.Value.Add(CreateTerseUpdateBlock(entity, llUpdateFlags.HasFlag(LLUpdateFlags.Textures)));
                }

                #endregion Block Construction

                // Unset CreateSelected after it has been sent once
                if (prim != null)
                    prim.Prim.Flags &= ~PrimFlags.CreateSelected;
            }

            #region Packet Sending

            ushort timeDilation = (m_physics != null) ?
                Utils.FloatToUInt16(m_physics.TimeDilation, 0.0f, 1.0f) :
                UInt16.MaxValue;

            if (objectUpdateBlocks.IsValueCreated)
            {
                List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;

                ObjectUpdatePacket packet = new ObjectUpdatePacket();
                packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition);
                packet.RegionData.TimeDilation = timeDilation;
                packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];

                for (int i = 0; i < blocks.Count; i++)
                    packet.ObjectData[i] = blocks[i];

                m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true);
            }

            if (compressedUpdateBlocks.IsValueCreated)
            {
                List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;

                ObjectUpdateCompressedPacket packet = new ObjectUpdateCompressedPacket();
                packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition);
                packet.RegionData.TimeDilation = timeDilation;
                packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];

                for (int i = 0; i < blocks.Count; i++)
                    packet.ObjectData[i] = blocks[i];

                m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true);
            }

            if (terseUpdateBlocks.IsValueCreated)
            {
                List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;

                ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
                packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition);
                packet.RegionData.TimeDilation = timeDilation;
                packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];

                for (int i = 0; i < blocks.Count; i++)
                    packet.ObjectData[i] = blocks[i];

                m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true);
            }

            if (cachedUpdateBlocks.IsValueCreated)
            {
                List<ObjectUpdateCachedPacket.ObjectDataBlock> blocks = cachedUpdateBlocks.Value;

                ObjectUpdateCachedPacket packet = new ObjectUpdateCachedPacket();
                packet.RegionData.RegionHandle = Util.PositionToRegionHandle(m_scene.MinPosition);
                packet.RegionData.TimeDilation = timeDilation;
                packet.ObjectData = new ObjectUpdateCachedPacket.ObjectDataBlock[blocks.Count];

                for (int i = 0; i < blocks.Count; i++)
                    packet.ObjectData[i] = blocks[i];

                m_udp.SendPacket(agent, packet, ThrottleCategory.Task, true);
            }

            #endregion Packet Sending
        }