diff --git a/libsecondlife-cs/GroupManager.cs b/libsecondlife-cs/GroupManager.cs index d3928653..449d6e42 100644 --- a/libsecondlife-cs/GroupManager.cs +++ b/libsecondlife-cs/GroupManager.cs @@ -691,14 +691,14 @@ namespace libsecondlife private void GroupActiveProposalItemHandler(Packet packet, Simulator simulator) { - GroupActiveProposalItemReplyPacket proposal = (GroupActiveProposalItemReplyPacket)packet; + //GroupActiveProposalItemReplyPacket proposal = (GroupActiveProposalItemReplyPacket)packet; // TODO: Create a proposal class to represent the fields in a proposal item } private void GroupVoteHistoryItemHandler(Packet packet, Simulator simulator) { - GroupVoteHistoryItemReplyPacket history = (GroupVoteHistoryItemReplyPacket)packet; + //GroupVoteHistoryItemReplyPacket history = (GroupVoteHistoryItemReplyPacket)packet; // TODO: This was broken in the official viewer when I was last trying to work on it } @@ -763,7 +763,9 @@ namespace libsecondlife private void GroupAccountTransactionsHandler(Packet packet, Simulator simulator) { - GroupAccountTransactionsReplyPacket transactions = (GroupAccountTransactionsReplyPacket)packet; + //GroupAccountTransactionsReplyPacket transactions = (GroupAccountTransactionsReplyPacket)packet; + + // TODO: This one is slightly different than the previous two //if (GroupAccountTransactionsCallbacks.ContainsKey(transactions.AgentData.GroupID)) //{ diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs index 88a33333..4a2146dc 100644 --- a/libsecondlife-cs/NetworkManager.cs +++ b/libsecondlife-cs/NetworkManager.cs @@ -354,6 +354,52 @@ namespace libsecondlife } } + private void SendAck(ushort id) + { + PacketAckPacket ack = new PacketAckPacket(); + + ack.Packets = new PacketAckPacket.PacketsBlock[1]; + ack.Packets[0] = new PacketAckPacket.PacketsBlock(); + ack.Packets[0].ID = id; + ack.Header.Reliable = false; + + lock (PendingAcks) + { + if (PendingAcks.Contains(id)) + { + PendingAcks.Remove(id); + } + } + + SendPacket(ack, true); + } + + private void SendAcks() + { + lock (PendingAcks) + { + if (PendingAcks.Count > 0) + { + int i = 0; + PacketAckPacket acks = new PacketAckPacket(); + acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count]; + + foreach (uint ack in PendingAcks) + { + acks.Packets[i] = new PacketAckPacket.PacketsBlock(); + acks.Packets[i].ID = ack; + i++; + } + + acks.Header.Reliable = false; + + SendPacket(acks, true); + + PendingAcks.Clear(); + } + } + } + private void OnReceivedData(IAsyncResult result) { Packet packet = null; @@ -398,6 +444,11 @@ namespace libsecondlife // Track the sequence number for this packet if it's marked as reliable if (packet.Header.Reliable) { + if (PendingAcks.Count > 10) + { + SendAcks(); + } + // Check if we already received this packet lock (Inbox) { @@ -407,13 +458,20 @@ namespace libsecondlife packet.Header.Sequence + ", resent=" + ((packet.Header.Resent) ? "Yes" : "No"), Helpers.LogLevel.Info); + // Send an ACK for this packet immediately + SendAck(packet.Header.Sequence); + // Avoid firing a callback twice for the same packet return; } else { Inbox.Add(packet.Header.Sequence, packet.Header.Sequence); - PendingAcks.Add((uint)packet.Header.Sequence); + + lock (PendingAcks) + { + PendingAcks.Add((uint)packet.Header.Sequence); + } } } } @@ -498,27 +556,7 @@ namespace libsecondlife return; } - lock (PendingAcks) - { - if (PendingAcks.Count > 0) - { - int i = 0; - PacketAckPacket acks = new PacketAckPacket(); - acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count]; - acks.Header.Reliable = false; - - foreach (uint ack in PendingAcks) - { - acks.Packets[i] = new PacketAckPacket.PacketsBlock(); - acks.Packets[i].ID = ack; - i++; - } - - SendPacket(acks, true); - - PendingAcks.Clear(); - } - } + SendAcks(); } } diff --git a/libsecondlife-cs/Parcel.cs b/libsecondlife-cs/Parcel.cs index 28171384..7ea41948 100644 --- a/libsecondlife-cs/Parcel.cs +++ b/libsecondlife-cs/Parcel.cs @@ -366,13 +366,18 @@ namespace libsecondlife Client = client; ParcelsForSale = new List(); + // Setup the timer + DirLandTimer = new Timer(8000); + DirLandTimer.Elapsed += new ElapsedEventHandler(DirLandTimerEvent); + DirLandTimeout = false; + // Setup the callbacks Client.Network.RegisterCallback(PacketType.DirLandReply, new PacketCallback(DirLandReplyHandler)); Client.Network.RegisterCallback(PacketType.ParcelInfoReply, new PacketCallback(ParcelInfoReplyHandler)); Client.Network.RegisterCallback(PacketType.ParcelProperties, new PacketCallback(ParcelPropertiesHandler)); Client.Network.RegisterCallback(PacketType.ParcelDwellReply, new PacketCallback(ParcelDwellReplyHandler)); - ParcelInfoParcel = new DirectoryParcel(); + ParcelInfoParcel = null; } /// @@ -450,9 +455,7 @@ namespace libsecondlife // Clear the list ParcelsForSale.Clear(); - // Setup the timer - DirLandTimer = new Timer(15000); - DirLandTimer.Elapsed += new ElapsedEventHandler(DirLandTimerEvent); + // Start the timer DirLandTimeout = false; DirLandTimer.Start(); @@ -608,50 +611,53 @@ namespace libsecondlife private void ParcelInfoReplyHandler(Packet packet, Simulator simulator) { - ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)packet; - - if (!reply.Data.ParcelID.Equals(ParcelInfoParcel.ID)) + if (ParcelInfoParcel != null) { - Client.Log("Received a ParcelInfoReply for " + reply.Data.ParcelID.ToString() + - ", looking for " + ParcelInfoParcel.ID.ToString(), Helpers.LogLevel.Warning); + ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)packet; - // Build and resend the ParcelInfoRequest packet - ParcelInfoRequestPacket request = new ParcelInfoRequestPacket(); - request.AgentData.AgentID = Client.Network.AgentID; - request.AgentData.SessionID = Client.Network.SessionID; - request.Data.ParcelID = ParcelInfoParcel.ID; + if (!reply.Data.ParcelID.Equals(ParcelInfoParcel.ID)) + { + Client.Log("Received a ParcelInfoReply for " + reply.Data.ParcelID.ToString() + + ", looking for " + ParcelInfoParcel.ID.ToString(), Helpers.LogLevel.Warning); - Client.Network.SendPacket(request); + // Build and resend the ParcelInfoRequest packet + ParcelInfoRequestPacket request = new ParcelInfoRequestPacket(); + request.AgentData.AgentID = Client.Network.AgentID; + request.AgentData.SessionID = Client.Network.SessionID; + request.Data.ParcelID = ParcelInfoParcel.ID; - return; + Client.Network.SendPacket(request); + + return; + } + + ParcelInfoParcel.SimName = Helpers.FieldToString(reply.Data.SimName); + ParcelInfoParcel.ActualArea = reply.Data.ActualArea; + ParcelInfoParcel.GlobalPosition.X = reply.Data.GlobalX; + ParcelInfoParcel.GlobalPosition.Y = reply.Data.GlobalY; + ParcelInfoParcel.GlobalPosition.Z = reply.Data.GlobalZ; + ParcelInfoParcel.Name = Helpers.FieldToString(reply.Data.Name); + ParcelInfoParcel.Desc = Helpers.FieldToString(reply.Data.Desc); + ParcelInfoParcel.SalePrice = reply.Data.SalePrice; + ParcelInfoParcel.OwnerID = reply.Data.OwnerID; + ParcelInfoParcel.SnapshotID = reply.Data.SnapshotID; + ParcelInfoParcel.Dwell = reply.Data.Dwell; + + // Get RegionHandle from GlobalX/GlobalY + uint handleX = (uint)Math.Floor(ParcelInfoParcel.GlobalPosition.X / 256.0F); + handleX *= 256; + uint handleY = (uint)Math.Floor(ParcelInfoParcel.GlobalPosition.Y / 256.0F); + handleY *= 256; + // FIXME: Helpers function needed + //ParcelInfoParcel.RegionHandle = new U64(handleX, handleY); + + // Get SimPosition from GlobalX/GlobalY and RegionHandle + ParcelInfoParcel.SimPosition.X = ParcelInfoParcel.GlobalPosition.X - (float)handleX; + ParcelInfoParcel.SimPosition.Y = ParcelInfoParcel.GlobalPosition.Y - (float)handleY; + ParcelInfoParcel.SimPosition.Z = ParcelInfoParcel.GlobalPosition.Z; + + Finished = true; } - - ParcelInfoParcel.SimName = Helpers.FieldToString(reply.Data.SimName); - ParcelInfoParcel.ActualArea = reply.Data.ActualArea; - ParcelInfoParcel.GlobalPosition.X = reply.Data.GlobalX; - ParcelInfoParcel.GlobalPosition.Y = reply.Data.GlobalY; - ParcelInfoParcel.GlobalPosition.Z = reply.Data.GlobalZ; - ParcelInfoParcel.Name = Helpers.FieldToString(reply.Data.Name); - ParcelInfoParcel.Desc = Helpers.FieldToString(reply.Data.Desc); - ParcelInfoParcel.SalePrice = reply.Data.SalePrice; - ParcelInfoParcel.OwnerID = reply.Data.OwnerID; - ParcelInfoParcel.SnapshotID = reply.Data.SnapshotID; - ParcelInfoParcel.Dwell = reply.Data.Dwell; - - // Get RegionHandle from GlobalX/GlobalY - uint handleX = (uint)Math.Floor(ParcelInfoParcel.GlobalPosition.X / 256.0F); - handleX *= 256; - uint handleY = (uint)Math.Floor(ParcelInfoParcel.GlobalPosition.Y / 256.0F); - handleY *= 256; - // FIXME: Helpers function needed - //ParcelInfoParcel.RegionHandle = new U64(handleX, handleY); - - // Get SimPosition from GlobalX/GlobalY and RegionHandle - ParcelInfoParcel.SimPosition.X = ParcelInfoParcel.GlobalPosition.X - (float)handleX; - ParcelInfoParcel.SimPosition.Y = ParcelInfoParcel.GlobalPosition.Y - (float)handleY; - ParcelInfoParcel.SimPosition.Z = ParcelInfoParcel.GlobalPosition.Z; - - Finished = true; } //private void ParcelInfoTimerEvent(object source, System.Timers.ElapsedEventArgs ea) diff --git a/libsecondlife-cs/Textures.cs b/libsecondlife-cs/Textures.cs index 11654a67..61700267 100644 --- a/libsecondlife-cs/Textures.cs +++ b/libsecondlife-cs/Textures.cs @@ -30,11 +30,35 @@ using System.Text; namespace libsecondlife { + /// + /// + /// public class TextureEntry { - private Dictionary Textures; + /// public TextureEntryFace DefaultTexture; + private Dictionary Textures; + + /// + /// + /// + public TextureEntry() + { + Textures = new Dictionary(); + DefaultTexture = new TextureEntryFace(null); + } + + /// + /// + /// + /// + /// + public TextureEntry(byte[] data, int pos) + { + FromBytes(data, pos); + } + public TextureEntryFace GetFace(uint index) { if (Textures.ContainsKey(index)) @@ -43,6 +67,11 @@ namespace libsecondlife return DefaultTexture; } + /// + /// + /// + /// + /// public TextureEntryFace SetFace(uint index) { if (!Textures.ContainsKey(index)) @@ -51,18 +80,16 @@ namespace libsecondlife return Textures[index]; } - public TextureEntry() + /// + /// + /// + /// + public byte[] ToBytes() { - Textures = new Dictionary(); - DefaultTexture = new TextureEntryFace(null); + ; } - public TextureEntry(byte[] data, int pos) - { - FromByte(data, pos); - } - - private bool readFaceBitfield(byte[] data, ref int pos, ref uint faceBits, ref uint bitfieldSize) + private bool ReadFaceBitfield(byte[] data, ref int pos, ref uint faceBits, ref uint bitfieldSize) { faceBits = 0; bitfieldSize = 0; @@ -92,7 +119,7 @@ namespace libsecondlife return (float)((QV * QF - (0.5F * range)) + QF); } - private void FromByte(byte[] data, int pos) + private void FromBytes(byte[] data, int pos) { Textures = new Dictionary(); DefaultTexture = new TextureEntryFace(null); @@ -105,7 +132,7 @@ namespace libsecondlife DefaultTexture.TextureID = new LLUUID(data, i); i += 16; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { LLUUID tmpUUID = new LLUUID(data, i); i += 16; @@ -118,7 +145,7 @@ namespace libsecondlife DefaultTexture.RGBA = (uint)(data[i] + (data[i + 1] << 8) + (data[i + 2] << 16) + (data[i + 3] << 24)); i += 4; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { uint tmpUint = (uint)(data[i] + (data[i + 1] << 8) + (data[i + 2] << 16) + (data[i + 3] << 24)); i += 4; @@ -131,7 +158,7 @@ namespace libsecondlife DefaultTexture.RepeatU = Dequantize(data, i, -101.0F, 101.0F) + 1.0F; i += 2; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { float tmpFloat = Dequantize(data, i, -101.0F, 101.0F) + 1.0F; i += 2; @@ -144,7 +171,7 @@ namespace libsecondlife DefaultTexture.RepeatV = Dequantize(data, i, -101.0F, 101.0F) + 1.0F; i += 2; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { float tmpFloat = Dequantize(data, i, -101.0F, 101.0F) + 1.0F; i += 2; @@ -157,7 +184,7 @@ namespace libsecondlife DefaultTexture.OffsetU = Dequantize(data, i, -1.0F, 1.0F); i += 2; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { float tmpFloat = Dequantize(data, i, -1.0F, 1.0F); i += 2; @@ -170,7 +197,7 @@ namespace libsecondlife DefaultTexture.OffsetV = Dequantize(data, i, -1.0F, 1.0F); i += 2; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { float tmpFloat = Dequantize(data, i, -1.0F, 1.0F); i += 2; @@ -183,7 +210,7 @@ namespace libsecondlife DefaultTexture.Rotation = Dequantize(data, i, -359.995F, 359.995F); i += 2; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { float tmpFloat = Dequantize(data, i, -359.995F, 359.995F); i += 2; @@ -196,7 +223,7 @@ namespace libsecondlife DefaultTexture.Flags1 = data[i]; i++; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { byte tmpByte = data[i]; i++; @@ -209,7 +236,7 @@ namespace libsecondlife DefaultTexture.Flags2 = data[i]; i++; - while (readFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) + while (ReadFaceBitfield(data, ref i, ref faceBits, ref BitfieldSize)) { byte tmpByte = data[i]; i++; @@ -221,10 +248,13 @@ namespace libsecondlife } } + /// + /// + /// public class TextureEntryFace { [Flags] - private enum TextureAttributes : uint + public enum TextureAttributes : uint { None, TextureID, @@ -239,20 +269,10 @@ namespace libsecondlife All = 0xFFFFFFFF } - private TextureAttributes hasAttribute; - - private TextureEntryFace DefaultTexture; - - private LLUUID _TextureID; - private uint _RGBA; - private float _RepeatU; - private float _RepeatV; - private float _OffsetU; - private float _OffsetV; - private float _Rotation; - private byte _Flags1; - private byte _Flags2; - + /// + /// + /// + /// public TextureEntryFace(TextureEntryFace defaultTexture) { DefaultTexture = defaultTexture; @@ -262,6 +282,9 @@ namespace libsecondlife hasAttribute = TextureAttributes.None; } + /// + /// + /// public LLUUID TextureID { get @@ -278,6 +301,9 @@ namespace libsecondlife } } + /// + /// + /// public uint RGBA { get @@ -294,6 +320,9 @@ namespace libsecondlife } } + /// + /// + /// public float RepeatU { get @@ -310,6 +339,9 @@ namespace libsecondlife } } + /// + /// + /// public float RepeatV { get @@ -326,6 +358,9 @@ namespace libsecondlife } } + /// + /// + /// public float OffsetU { get @@ -342,6 +377,9 @@ namespace libsecondlife } } + /// + /// + /// public float OffsetV { get @@ -358,6 +396,9 @@ namespace libsecondlife } } + /// + /// + /// public float Rotation { get @@ -374,6 +415,9 @@ namespace libsecondlife } } + /// + /// + /// public byte Flags1 { get @@ -390,6 +434,9 @@ namespace libsecondlife } } + /// + /// + /// public byte Flags2 { get @@ -405,5 +452,17 @@ namespace libsecondlife hasAttribute |= TextureAttributes.Flags2; } } + + private TextureAttributes hasAttribute; + private TextureEntryFace DefaultTexture; + private LLUUID _TextureID; + private uint _RGBA; + private float _RepeatU; + private float _RepeatV; + private float _OffsetU; + private float _OffsetV; + private float _Rotation; + private byte _Flags1; + private byte _Flags2; } }