diff --git a/libsecondlife-cs/Avatar.cs b/libsecondlife-cs/Avatar.cs
index 127531ff..2dfb3481 100644
--- a/libsecondlife-cs/Avatar.cs
+++ b/libsecondlife-cs/Avatar.cs
@@ -31,606 +31,603 @@ using System.Collections;
namespace libsecondlife
{
- public delegate void ChatCallback(string message, byte audible, byte type, byte sourcetype,
- string name, LLUUID id, byte command, LLUUID commandID);
-
- public delegate void InstantMessageCallback(LLUUID FromAgentID, LLUUID ToAgentID,
- uint ParentEstateID, LLUUID RegionID, LLVector3 Position, byte Offline, byte Dialog,
- LLUUID ID, uint Timestamp, string AgentName, string Message, string Bucket);
-
- public delegate void FriendNotificationCallback(LLUUID AgentID, bool Online);
-
- public delegate void TeleportCallback(string message);
-
- public class Avatar
- {
- public LLUUID ID;
- public string Name;
- public bool Online;
- }
-
- public class MainAvatar
- {
- public LLUUID ID;
- public string FirstName;
- public string LastName;
- public string TeleportMessage;
- public LLVector3d Position;
- public LLVector3d LookAt;
- public LLVector3d HomePosition;
- public LLVector3d HomeLookAt;
-
- private SecondLife Client;
- private int TeleportStatus;
- private Timer TeleportTimer;
- private bool TeleportTimeout;
-
- public event ChatCallback OnChat;
- public event InstantMessageCallback OnInstantMessage;
- public event FriendNotificationCallback OnFriendNotification;
- public event TeleportCallback OnTeleport;
-
- public MainAvatar(SecondLife client)
- {
- Client = client;
- TeleportMessage = "";
-
- // Create emtpy vectors for now
- HomeLookAt = HomePosition = LookAt = Position = new LLVector3d();
-
- // Location callback
- PacketCallback callback = new PacketCallback(LocationHandler);
- Client.Network.RegisterCallback("CoarseLocationUpdate", callback);
-
- // Teleport callbacks
- callback = new PacketCallback(TeleportHandler);
- Client.Network.RegisterCallback("TeleportStart", callback);
- Client.Network.RegisterCallback("TeleportProgress", callback);
- Client.Network.RegisterCallback("TeleportFailed", callback);
- Client.Network.RegisterCallback("TeleportFinish", callback);
-
- // Instant Message callback
- callback = new PacketCallback(InstantMessageHandler);
- Client.Network.RegisterCallback("ImprovedInstantMessage", callback);
-
- // Chat callback
- callback = new PacketCallback(ChatHandler);
- Client.Network.RegisterCallback("ChatFromSimulator", callback);
-
- // Friend notification callback
- callback = new PacketCallback(FriendNotificationHandler);
- Client.Network.RegisterCallback("OnlineNotification", callback);
- Client.Network.RegisterCallback("OfflineNotification", callback);
-
- TeleportTimer = new Timer(8000);
- TeleportTimer.Elapsed += new ElapsedEventHandler(TeleportTimerEvent);
- TeleportTimeout = false;
- }
-
- private void FriendNotificationHandler(Packet packet, Simulator simulator)
- {
- // If the agent is online...
- if (packet.Layout.Name == "OnlineNotification")
- {
- LLUUID AgentID = new LLUUID();
-
- ArrayList blocks;
-
- blocks = packet.Blocks();
-
- foreach (Block block in blocks)
- {
- foreach (Field field in block.Fields)
- {
- if(field.Layout.Name == "AgentID")
- {
- AgentID = (LLUUID)field.Data;
-
- Client.AddAvatar(AgentID);
- Client.AvatarsMutex.WaitOne();
- ((Avatar)Client.Avatars[AgentID]).Online = true;
- Client.AvatarsMutex.ReleaseMutex();
-
- if (OnFriendNotification != null)
- {
- OnFriendNotification(AgentID, true);
- }
- }
- }
- }
-
- return;
- }
-
- // If the agent is Offline...
- if (packet.Layout.Name == "OfflineNotification")
- {
- LLUUID AgentID = new LLUUID();
-
- ArrayList blocks;
-
- blocks = packet.Blocks();
-
- foreach (Block block in blocks)
- {
- foreach (Field field in block.Fields)
- {
- if(field.Layout.Name == "AgentID")
- {
- AgentID = (LLUUID)field.Data;
-
- Client.AddAvatar(AgentID);
- Client.AvatarsMutex.WaitOne();
- ((Avatar)Client.Avatars[AgentID]).Online = false;
- Client.AvatarsMutex.ReleaseMutex();
-
- if (OnFriendNotification != null)
- {
- OnFriendNotification(AgentID, false);
- }
- }
- }
- }
-
- return;
- }
- }
-
- private void LocationHandler(Packet packet, Simulator simulator)
- {
- foreach (Block block in packet.Blocks())
- {
- foreach (Field field in block.Fields)
- {
- if (field.Layout.Name == "X")
- {
- Position.X = Convert.ToDouble((byte)field.Data);
- }
- else if (field.Layout.Name == "Y")
- {
- Position.Y = Convert.ToDouble((byte)field.Data);
- }
- else if (field.Layout.Name == "Z")
- {
- Position.Z = Convert.ToDouble((byte)field.Data);
- }
- }
- }
-
- // Send an AgentUpdate packet with the new camera location
- packet = Packets.Sim.AgentUpdate(Client.Protocol, Client.Network.AgentID, 56.0F,
- new LLVector3((float)Position.X, (float)Position.Y, (float)Position.Z));
- Client.Network.SendPacket(packet);
- }
-
- private void InstantMessageHandler(Packet packet, Simulator simulator)
- {
- if (packet.Layout.Name == "ImprovedInstantMessage")
- {
- LLUUID FromAgentID = new LLUUID();
- LLUUID ToAgentID = new LLUUID();
- uint ParentEstateID = 0;
- LLUUID RegionID = new LLUUID();
- LLVector3 Position = new LLVector3();
- byte Offline = 0;
- byte Dialog = 0;
- LLUUID ID = new LLUUID();
- uint Timestamp = 0;
- string AgentName = "";
- string Message = "";
- string Bucket = "";
-
- ArrayList blocks;
-
- blocks = packet.Blocks();
-
- foreach (Block block in blocks)
- {
- foreach (Field field in block.Fields)
- {
- if(field.Layout.Name == "FromAgentID")
- {
- FromAgentID = (LLUUID)field.Data;
- }
- else if(field.Layout.Name == "ToAgentID")
- {
- ToAgentID = (LLUUID)field.Data;
- }
- else if(field.Layout.Name == "ParentEstateID")
- {
- ParentEstateID = (uint)field.Data;
- }
- else if(field.Layout.Name == "RegionID")
- {
- RegionID = (LLUUID)field.Data;
- }
- else if(field.Layout.Name == "Position")
- {
- Position = (LLVector3)field.Data;
- }
- else if(field.Layout.Name == "Offline")
- {
- Offline = (byte)field.Data;
- }
- else if(field.Layout.Name == "Dialog")
- {
- Dialog = (byte)field.Data;
- }
- else if(field.Layout.Name == "ID")
- {
- ID = (LLUUID)field.Data;
- }
- else if(field.Layout.Name == "Timestamp")
- {
- Timestamp = (uint)field.Data;
- }
- else if(field.Layout.Name == "FromAgentName")
- {
- AgentName = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- }
- else if(field.Layout.Name == "Message")
- {
- Message = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- }
- else if(field.Layout.Name == "BinaryBucket")
- {
- Bucket = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- }
- }
- }
-
- if (OnInstantMessage != null)
- {
- OnInstantMessage(FromAgentID,ToAgentID,ParentEstateID,RegionID,Position,
- Offline,Dialog,ID,Timestamp,AgentName,Message,Bucket);
- }
- }
- }
-
- private void ChatHandler(Packet packet, Simulator simulator)
- {
- if (packet.Layout.Name == "ChatFromSimulator")
- {
- string message = "";
- byte audible = 0;
- byte type = 0;
- byte sourcetype = 0;
- string name = "";
- LLUUID id = new LLUUID();
- byte command = 0;
- LLUUID commandID = new LLUUID();
-
- ArrayList blocks;
-
- blocks = packet.Blocks();
-
- foreach (Block block in blocks)
- {
- foreach (Field field in block.Fields)
- {
- if (field.Layout.Name == "ID")
- {
- id = (LLUUID)field.Data;
- }
- else if(field.Layout.Name == "FromName")
- {
- name = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- }
- else if(field.Layout.Name == "SourceType")
- {
- sourcetype = (byte)field.Data;
- }
- else if(field.Layout.Name == "Type")
- {
- type = (byte)field.Data;
- }
- else if(field.Layout.Name == "Audible")
- {
- audible = (byte)field.Data;
- }
- else if(field.Layout.Name == "Message")
- {
- message = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- }
- else if(field.Layout.Name == "Command")
- {
- command = (byte)field.Data;
- }
- else if(field.Layout.Name == "CommandID")
- {
- commandID = (LLUUID)field.Data;
- }
-
- }
- }
-
- //DEBUG
- //Helpers.Log("Chat: Message=" + message + ", Type=" + type, Helpers.LogLevel.Info);
-
- if (OnChat != null)
- {
- OnChat(message, audible, type, sourcetype, name, id, command, commandID);
- }
- }
- }
-
- public void InstantMessage(LLUUID target, string message)
- {
- TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
- uint now = (uint)(t.TotalSeconds);
- string name = FirstName + " " + LastName;
-
- InstantMessage(name, LLUUID.GenerateUUID(), target, message, null);
- }
-
- public void InstantMessage(string fromName, LLUUID sessionID, LLUUID target, string message, LLUUID[] conferenceIDs)
- {
- TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
- uint now = (uint)(t.TotalSeconds);
-
- byte[] binaryBucket;
-
- if (conferenceIDs != null && conferenceIDs.Length > 0)
- {
- binaryBucket = new byte[16 * conferenceIDs.Length];
-
- for (int i = 0; i < conferenceIDs.Length; ++i)
- {
- Array.Copy(conferenceIDs[i].Data, 0, binaryBucket, 16 * i, 16);
- }
- }
- else
- {
- binaryBucket = new byte[0];
- }
-
- // Build the packet
- Packet packet = Packets.Communication.ImprovedInstantMessage(Client.Protocol, target, Client.Network.AgentID, 0,
- Client.CurrentRegion.ID, new LLVector3((float)Position.X, (float)Position.Y, (float)Position.Z),
- 0, 0, sessionID, now, fromName, message, binaryBucket);
-
- // Send the message
- Client.Network.SendPacket(packet);
- }
-
- public void Say(string message, int channel)
- {
- LLUUID CommandID = new LLUUID();
- LLVector3 Position = new LLVector3(0.0F,0.0F,0.0F);
-
- Packet packet = Packets.Communication.ChatFromViewer(Client.Protocol, Client.Avatar.ID, Client.Network.SessionID,
- message, (byte)1, channel, 0, CommandID, 20, Position);
-
- Client.Network.SendPacket(packet);
- }
-
- public void Shout(string message, int channel)
- {
- LLUUID CommandID = new LLUUID();
- LLVector3 Position = new LLVector3(0.0F,0.0F,0.0F);
-
- Packet packet = Packets.Communication.ChatFromViewer(Client.Protocol,Client.Avatar.ID,Client.Network.SessionID,
- message, (byte)2, channel, 0, CommandID, 100, Position);
-
- Client.Network.SendPacket(packet);
- }
-
- public void GiveMoney(LLUUID target, int amount, string description)
- {
- // 5001 - transaction type for av to av money transfers
- GiveMoney(target, amount, description, 5001);
- }
-
- public void GiveMoney(LLUUID target, int amount, string description, int transactiontype)
- {
- Hashtable blocks = new Hashtable();
- Hashtable fields = new Hashtable();
-
- fields["AggregatePermInventory"] = (byte)0;
- fields["AggregatePermNextOwner"] = (byte)0;
- fields["DestID"] = target;
- fields["Amount"] = amount;
- fields["Description"] = description;
- fields["Flags"] = (byte)0;
- fields["SourceID"] = Client.Network.AgentID;
- fields["TransactionType"] = transactiontype;
- blocks[fields] = "MoneyData";
-
- fields = new Hashtable();
- fields["AgentID"] = Client.Network.AgentID;
- fields["SessionID"] = Client.Network.SessionID;
- blocks[fields] = "AgentData";
-
- Packet packet = PacketBuilder.BuildPacket("MoneyTransferRequest", Client.Protocol, blocks,
- Helpers.MSG_RELIABLE);
-
- Client.Network.SendPacket(packet);
- }
-
- public bool Teleport(U64 regionHandle, LLVector3 position)
- {
- return Teleport(regionHandle,position,new LLVector3(position.X + 1.0F, position.Y, position.Z));
- }
-
- public bool Teleport(U64 regionHandle, LLVector3 position, LLVector3 lookAt)
- {
- TeleportStatus = 0;
-// LLVector3 lookAt = new LLVector3(position.X + 1.0F, position.Y, position.Z);
-
- Hashtable blocks = new Hashtable();
- Hashtable fields = new Hashtable();
- fields["RegionHandle"] = regionHandle;
- fields["LookAt"] = lookAt;
- fields["Position"] = position;
- blocks[fields] = "Info";
- fields = new Hashtable();
- fields["AgentID"] = Client.Network.AgentID;
- fields["SessionID"] = Client.Network.SessionID;
- blocks[fields] = "AgentData";
- Packet packet = PacketBuilder.BuildPacket("TeleportLocationRequest", Client.Protocol, blocks,
- Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED);
-
- Helpers.Log("Teleporting to region " + regionHandle.ToString(), Helpers.LogLevel.Info);
-
- // Start the timeout check
- TeleportTimeout = false;
- TeleportTimer.Start();
-
- Client.Network.SendPacket(packet);
-
- while (TeleportStatus == 0 && !TeleportTimeout)
- {
- Client.Tick();
- }
-
- TeleportTimer.Stop();
-
- if (TeleportTimeout)
- {
- if (OnTeleport != null)
- {
- OnTeleport("Teleport timed out.");
- }
- }
- else
- {
- if (OnTeleport != null)
- {
- OnTeleport(TeleportMessage);
- }
- }
-
- return (TeleportStatus == 1);
- }
-
- public bool Teleport(string simName, LLVector3 position)
- {
- return Teleport(simName,position,new LLVector3(position.X + 1.0F, position.Y, position.Z));
- }
-
- public bool Teleport(string simName, LLVector3 position, LLVector3 lookAt)
- {
- Client.Grid.AddSim(simName);
- int attempts = 0;
-
- while(attempts++ < 5)
- {
- if(Client.Grid.Regions.ContainsKey(simName))
- {
- return Teleport(((GridRegion)Client.Grid.Regions[simName]).RegionHandle,position,lookAt);
- }
- else
- {
- System.Threading.Thread.Sleep(1000);
- Client.Grid.AddSim(simName);
- Client.Tick();
- }
- }
- if (OnTeleport != null)
- {
- OnTeleport("Unable to resolve name: " + simName);
- }
- return false;
- }
-
- private void TeleportHandler(Packet packet, Simulator simulator)
- {
- ArrayList blocks;
-
- if (packet.Layout.Name == "TeleportStart")
- {
- TeleportMessage = "Teleport started";
- }
- else if (packet.Layout.Name == "TeleportProgress")
- {
- blocks = packet.Blocks();
-
- foreach (Block block in blocks)
- {
- foreach (Field field in block.Fields)
- {
- if (field.Layout.Name == "Message")
- {
- TeleportMessage = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- return;
- }
- }
- }
- }
- else if (packet.Layout.Name == "TeleportFailed")
- {
- blocks = packet.Blocks();
-
- foreach (Block block in blocks)
- {
- foreach (Field field in block.Fields)
- {
- if (field.Layout.Name == "Reason")
- {
- TeleportMessage = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- TeleportStatus = -1;
- return;
- }
- }
- }
- }
- else if (packet.Layout.Name == "TeleportFinish")
- {
- TeleportMessage = "Teleport finished";
-
- ushort port = 0;
- IPAddress ip = null;
- U64 regionHandle;
-
- blocks = packet.Blocks();
-
- foreach (Block block in blocks)
- {
- foreach (Field field in block.Fields)
- {
- if (field.Layout.Name == "SimPort")
- {
- port = (ushort)field.Data;
- }
- else if (field.Layout.Name == "SimIP")
- {
- ip = (IPAddress)field.Data;
- }
- else if (field.Layout.Name == "RegionHandle")
- {
- regionHandle = (U64)field.Data;
- }
- }
- }
-
- if (Client.Network.Connect(ip, port, Client.Network.CurrentSim.CircuitCode, true))
- {
- // Move the avatar in to this sim
- Packet movePacket = Packets.Sim.CompleteAgentMovement(Client.Protocol, Client.Network.AgentID,
- Client.Network.SessionID, Client.Network.CurrentSim.CircuitCode);
- Client.Network.SendPacket(movePacket);
-
- Helpers.Log("Connected to new sim " + Client.Network.CurrentSim.IPEndPoint.ToString(),
- Helpers.LogLevel.Info);
-
- // Sleep a little while so we can collect parcel information
- System.Threading.Thread.Sleep(1000);
-
- Client.CurrentRegion = Client.Network.CurrentSim.Region;
- TeleportStatus = 1;
- return;
- }
- else
- {
- TeleportStatus = -1;
- return;
- }
- }
- }
-
- private void TeleportTimerEvent(object source, System.Timers.ElapsedEventArgs ea)
- {
- TeleportTimeout = true;
- }
- }
+ public delegate void ChatCallback(string message, byte audible, byte type, byte sourcetype,
+ string name, LLUUID id, byte command, LLUUID commandID);
+
+ public delegate void InstantMessageCallback(LLUUID FromAgentID, LLUUID ToAgentID,
+ uint ParentEstateID, LLUUID RegionID, LLVector3 Position, byte Offline, byte Dialog,
+ LLUUID ID, uint Timestamp, string AgentName, string Message, string Bucket);
+
+ public delegate void FriendNotificationCallback(LLUUID AgentID, bool Online);
+
+ public delegate void TeleportCallback(string message);
+
+ public class Avatar
+ {
+ public LLUUID ID;
+ public string Name;
+ public bool Online;
+ }
+
+ public class MainAvatar
+ {
+ public LLUUID ID;
+ public string FirstName;
+ public string LastName;
+ public string TeleportMessage;
+ public LLVector3d Position;
+ public LLVector3d LookAt;
+ public LLVector3d HomePosition;
+ public LLVector3d HomeLookAt;
+
+ private SecondLife Client;
+ private int TeleportStatus;
+ private Timer TeleportTimer;
+ private bool TeleportTimeout;
+
+ public event ChatCallback OnChat;
+ public event InstantMessageCallback OnInstantMessage;
+ public event FriendNotificationCallback OnFriendNotification;
+ public event TeleportCallback OnTeleport;
+
+ public MainAvatar(SecondLife client)
+ {
+ Client = client;
+ TeleportMessage = "";
+
+ // Create emtpy vectors for now
+ HomeLookAt = HomePosition = LookAt = Position = new LLVector3d();
+
+ // Location callback
+ PacketCallback callback = new PacketCallback(LocationHandler);
+ Client.Network.RegisterCallback("CoarseLocationUpdate", callback);
+
+ // Teleport callbacks
+ callback = new PacketCallback(TeleportHandler);
+ Client.Network.RegisterCallback("TeleportStart", callback);
+ Client.Network.RegisterCallback("TeleportProgress", callback);
+ Client.Network.RegisterCallback("TeleportFailed", callback);
+ Client.Network.RegisterCallback("TeleportFinish", callback);
+
+ // Instant Message callback
+ callback = new PacketCallback(InstantMessageHandler);
+ Client.Network.RegisterCallback("ImprovedInstantMessage", callback);
+
+ // Chat callback
+ callback = new PacketCallback(ChatHandler);
+ Client.Network.RegisterCallback("ChatFromSimulator", callback);
+
+ // Friend notification callback
+ callback = new PacketCallback(FriendNotificationHandler);
+ Client.Network.RegisterCallback("OnlineNotification", callback);
+ Client.Network.RegisterCallback("OfflineNotification", callback);
+
+ TeleportTimer = new Timer(8000);
+ TeleportTimer.Elapsed += new ElapsedEventHandler(TeleportTimerEvent);
+ TeleportTimeout = false;
+ }
+
+ private void FriendNotificationHandler(Packet packet, Simulator simulator)
+ {
+ // If the agent is online...
+ if (packet.Layout.Name == "OnlineNotification")
+ {
+ LLUUID AgentID = new LLUUID();
+
+ ArrayList blocks;
+
+ blocks = packet.Blocks();
+
+ foreach (Block block in blocks)
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "AgentID")
+ {
+ AgentID = (LLUUID)field.Data;
+
+ Client.AddAvatar(AgentID);
+ Client.AvatarsMutex.WaitOne();
+ ((Avatar)Client.Avatars[AgentID]).Online = true;
+ Client.AvatarsMutex.ReleaseMutex();
+
+ if (OnFriendNotification != null)
+ {
+ OnFriendNotification(AgentID, true);
+ }
+ }
+ }
+ }
+
+ return;
+ }
+
+ // If the agent is Offline...
+ if (packet.Layout.Name == "OfflineNotification")
+ {
+ LLUUID AgentID = new LLUUID();
+
+ ArrayList blocks;
+
+ blocks = packet.Blocks();
+
+ foreach (Block block in blocks)
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "AgentID")
+ {
+ AgentID = (LLUUID)field.Data;
+
+ Client.AddAvatar(AgentID);
+ Client.AvatarsMutex.WaitOne();
+ ((Avatar)Client.Avatars[AgentID]).Online = false;
+ Client.AvatarsMutex.ReleaseMutex();
+
+ if (OnFriendNotification != null)
+ {
+ OnFriendNotification(AgentID, false);
+ }
+ }
+ }
+ }
+
+ return;
+ }
+ }
+
+ private void LocationHandler(Packet packet, Simulator simulator)
+ {
+ foreach (Block block in packet.Blocks())
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "X")
+ {
+ Position.X = Convert.ToDouble((byte)field.Data);
+ }
+ else if (field.Layout.Name == "Y")
+ {
+ Position.Y = Convert.ToDouble((byte)field.Data);
+ }
+ else if (field.Layout.Name == "Z")
+ {
+ Position.Z = Convert.ToDouble((byte)field.Data);
+ }
+ }
+ }
+
+ // Send an AgentUpdate packet with the new camera location
+ packet = Packets.Sim.AgentUpdate(Client.Protocol, Client.Network.AgentID, 56.0F,
+ new LLVector3((float)Position.X, (float)Position.Y, (float)Position.Z));
+ Client.Network.SendPacket(packet);
+ }
+
+ private void InstantMessageHandler(Packet packet, Simulator simulator)
+ {
+ if (packet.Layout.Name == "ImprovedInstantMessage")
+ {
+ LLUUID FromAgentID = new LLUUID();
+ LLUUID ToAgentID = new LLUUID();
+ uint ParentEstateID = 0;
+ LLUUID RegionID = new LLUUID();
+ LLVector3 Position = new LLVector3();
+ byte Offline = 0;
+ byte Dialog = 0;
+ LLUUID ID = new LLUUID();
+ uint Timestamp = 0;
+ string AgentName = "";
+ string Message = "";
+ string Bucket = "";
+
+ ArrayList blocks;
+
+ blocks = packet.Blocks();
+
+ foreach (Block block in blocks)
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "FromAgentID")
+ {
+ FromAgentID = (LLUUID)field.Data;
+ }
+ else if (field.Layout.Name == "ToAgentID")
+ {
+ ToAgentID = (LLUUID)field.Data;
+ }
+ else if (field.Layout.Name == "ParentEstateID")
+ {
+ ParentEstateID = (uint)field.Data;
+ }
+ else if (field.Layout.Name == "RegionID")
+ {
+ RegionID = (LLUUID)field.Data;
+ }
+ else if (field.Layout.Name == "Position")
+ {
+ Position = (LLVector3)field.Data;
+ }
+ else if (field.Layout.Name == "Offline")
+ {
+ Offline = (byte)field.Data;
+ }
+ else if (field.Layout.Name == "Dialog")
+ {
+ Dialog = (byte)field.Data;
+ }
+ else if (field.Layout.Name == "ID")
+ {
+ ID = (LLUUID)field.Data;
+ }
+ else if (field.Layout.Name == "Timestamp")
+ {
+ Timestamp = (uint)field.Data;
+ }
+ else if (field.Layout.Name == "FromAgentName")
+ {
+ AgentName = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ }
+ else if (field.Layout.Name == "Message")
+ {
+ Message = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ }
+ else if (field.Layout.Name == "BinaryBucket")
+ {
+ Bucket = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ }
+ }
+ }
+
+ if (OnInstantMessage != null)
+ {
+ OnInstantMessage(FromAgentID, ToAgentID, ParentEstateID, RegionID, Position,
+ Offline, Dialog, ID, Timestamp, AgentName, Message, Bucket);
+ }
+ }
+ }
+
+ private void ChatHandler(Packet packet, Simulator simulator)
+ {
+ if (packet.Layout.Name == "ChatFromSimulator")
+ {
+ string message = "";
+ byte audible = 0;
+ byte type = 0;
+ byte sourcetype = 0;
+ string name = "";
+ LLUUID id = new LLUUID();
+ byte command = 0;
+ LLUUID commandID = new LLUUID();
+
+ ArrayList blocks;
+
+ blocks = packet.Blocks();
+
+ foreach (Block block in blocks)
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "ID")
+ {
+ id = (LLUUID)field.Data;
+ }
+ else if (field.Layout.Name == "FromName")
+ {
+ name = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ }
+ else if (field.Layout.Name == "SourceType")
+ {
+ sourcetype = (byte)field.Data;
+ }
+ else if (field.Layout.Name == "Type")
+ {
+ type = (byte)field.Data;
+ }
+ else if (field.Layout.Name == "Audible")
+ {
+ audible = (byte)field.Data;
+ }
+ else if (field.Layout.Name == "Message")
+ {
+ message = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ }
+ else if (field.Layout.Name == "Command")
+ {
+ command = (byte)field.Data;
+ }
+ else if (field.Layout.Name == "CommandID")
+ {
+ commandID = (LLUUID)field.Data;
+ }
+
+ }
+ }
+
+ if (OnChat != null)
+ {
+ OnChat(message, audible, type, sourcetype, name, id, command, commandID);
+ }
+ }
+ }
+
+ public void InstantMessage(LLUUID target, string message)
+ {
+ TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
+ uint now = (uint)(t.TotalSeconds);
+ string name = FirstName + " " + LastName;
+
+ InstantMessage(name, LLUUID.GenerateUUID(), target, message, null);
+ }
+
+ public void InstantMessage(string fromName, LLUUID sessionID, LLUUID target, string message, LLUUID[] conferenceIDs)
+ {
+ TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
+ uint now = (uint)(t.TotalSeconds);
+
+ byte[] binaryBucket;
+
+ if (conferenceIDs != null && conferenceIDs.Length > 0)
+ {
+ binaryBucket = new byte[16 * conferenceIDs.Length];
+
+ for (int i = 0; i < conferenceIDs.Length; ++i)
+ {
+ Array.Copy(conferenceIDs[i].Data, 0, binaryBucket, 16 * i, 16);
+ }
+ }
+ else
+ {
+ binaryBucket = new byte[0];
+ }
+
+ // Build the packet
+ Packet packet = Packets.Communication.ImprovedInstantMessage(Client.Protocol, target, Client.Network.AgentID, 0,
+ Client.CurrentRegion.ID, new LLVector3((float)Position.X, (float)Position.Y, (float)Position.Z),
+ 0, 0, sessionID, now, fromName, message, binaryBucket);
+
+ // Send the message
+ Client.Network.SendPacket(packet);
+ }
+
+ public void Say(string message, int channel)
+ {
+ LLUUID CommandID = new LLUUID();
+ LLVector3 Position = new LLVector3(0.0F, 0.0F, 0.0F);
+
+ Packet packet = Packets.Communication.ChatFromViewer(Client.Protocol, Client.Avatar.ID, Client.Network.SessionID,
+ message, (byte)1, channel, 0, CommandID, 20, Position);
+
+ Client.Network.SendPacket(packet);
+ }
+
+ public void Shout(string message, int channel)
+ {
+ LLUUID CommandID = new LLUUID();
+ LLVector3 Position = new LLVector3(0.0F, 0.0F, 0.0F);
+
+ Packet packet = Packets.Communication.ChatFromViewer(Client.Protocol, Client.Avatar.ID, Client.Network.SessionID,
+ message, (byte)2, channel, 0, CommandID, 100, Position);
+
+ Client.Network.SendPacket(packet);
+ }
+
+ public void GiveMoney(LLUUID target, int amount, string description)
+ {
+ // 5001 - transaction type for av to av money transfers
+ GiveMoney(target, amount, description, 5001);
+ }
+
+ public void GiveMoney(LLUUID target, int amount, string description, int transactiontype)
+ {
+ Hashtable blocks = new Hashtable();
+ Hashtable fields = new Hashtable();
+
+ fields["AggregatePermInventory"] = (byte)0;
+ fields["AggregatePermNextOwner"] = (byte)0;
+ fields["DestID"] = target;
+ fields["Amount"] = amount;
+ fields["Description"] = description;
+ fields["Flags"] = (byte)0;
+ fields["SourceID"] = Client.Network.AgentID;
+ fields["TransactionType"] = transactiontype;
+ blocks[fields] = "MoneyData";
+
+ fields = new Hashtable();
+ fields["AgentID"] = Client.Network.AgentID;
+ fields["SessionID"] = Client.Network.SessionID;
+ blocks[fields] = "AgentData";
+
+ Packet packet = PacketBuilder.BuildPacket("MoneyTransferRequest", Client.Protocol, blocks,
+ Helpers.MSG_RELIABLE);
+
+ Client.Network.SendPacket(packet);
+ }
+
+ public bool Teleport(U64 regionHandle, LLVector3 position)
+ {
+ return Teleport(regionHandle, position, new LLVector3(position.X + 1.0F, position.Y, position.Z));
+ }
+
+ public bool Teleport(U64 regionHandle, LLVector3 position, LLVector3 lookAt)
+ {
+ TeleportStatus = 0;
+ // LLVector3 lookAt = new LLVector3(position.X + 1.0F, position.Y, position.Z);
+
+ Hashtable blocks = new Hashtable();
+ Hashtable fields = new Hashtable();
+ fields["RegionHandle"] = regionHandle;
+ fields["LookAt"] = lookAt;
+ fields["Position"] = position;
+ blocks[fields] = "Info";
+ fields = new Hashtable();
+ fields["AgentID"] = Client.Network.AgentID;
+ fields["SessionID"] = Client.Network.SessionID;
+ blocks[fields] = "AgentData";
+ Packet packet = PacketBuilder.BuildPacket("TeleportLocationRequest", Client.Protocol, blocks,
+ Helpers.MSG_RELIABLE + Helpers.MSG_ZEROCODED);
+
+ Client.Log("Teleporting to region " + regionHandle.ToString(), Helpers.LogLevel.Info);
+
+ // Start the timeout check
+ TeleportTimeout = false;
+ TeleportTimer.Start();
+
+ Client.Network.SendPacket(packet);
+
+ while (TeleportStatus == 0 && !TeleportTimeout)
+ {
+ Client.Tick();
+ }
+
+ TeleportTimer.Stop();
+
+ if (TeleportTimeout)
+ {
+ if (OnTeleport != null)
+ {
+ OnTeleport("Teleport timed out.");
+ }
+ }
+ else
+ {
+ if (OnTeleport != null)
+ {
+ OnTeleport(TeleportMessage);
+ }
+ }
+
+ return (TeleportStatus == 1);
+ }
+
+ public bool Teleport(string simName, LLVector3 position)
+ {
+ return Teleport(simName, position, new LLVector3(position.X + 1.0F, position.Y, position.Z));
+ }
+
+ public bool Teleport(string simName, LLVector3 position, LLVector3 lookAt)
+ {
+ Client.Grid.AddSim(simName);
+ int attempts = 0;
+
+ while (attempts++ < 5)
+ {
+ if (Client.Grid.Regions.ContainsKey(simName))
+ {
+ return Teleport(((GridRegion)Client.Grid.Regions[simName]).RegionHandle, position, lookAt);
+ }
+ else
+ {
+ System.Threading.Thread.Sleep(1000);
+ Client.Grid.AddSim(simName);
+ Client.Tick();
+ }
+ }
+ if (OnTeleport != null)
+ {
+ OnTeleport("Unable to resolve name: " + simName);
+ }
+ return false;
+ }
+
+ private void TeleportHandler(Packet packet, Simulator simulator)
+ {
+ ArrayList blocks;
+
+ if (packet.Layout.Name == "TeleportStart")
+ {
+ TeleportMessage = "Teleport started";
+ }
+ else if (packet.Layout.Name == "TeleportProgress")
+ {
+ blocks = packet.Blocks();
+
+ foreach (Block block in blocks)
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "Message")
+ {
+ TeleportMessage = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ return;
+ }
+ }
+ }
+ }
+ else if (packet.Layout.Name == "TeleportFailed")
+ {
+ blocks = packet.Blocks();
+
+ foreach (Block block in blocks)
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "Reason")
+ {
+ TeleportMessage = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ TeleportStatus = -1;
+ return;
+ }
+ }
+ }
+ }
+ else if (packet.Layout.Name == "TeleportFinish")
+ {
+ TeleportMessage = "Teleport finished";
+
+ ushort port = 0;
+ IPAddress ip = null;
+ U64 regionHandle;
+
+ blocks = packet.Blocks();
+
+ foreach (Block block in blocks)
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "SimPort")
+ {
+ port = (ushort)field.Data;
+ }
+ else if (field.Layout.Name == "SimIP")
+ {
+ ip = (IPAddress)field.Data;
+ }
+ else if (field.Layout.Name == "RegionHandle")
+ {
+ regionHandle = (U64)field.Data;
+ }
+ }
+ }
+
+ if (Client.Network.Connect(ip, port, Client.Network.CurrentSim.CircuitCode, true))
+ {
+ // Move the avatar in to this sim
+ Packet movePacket = Packets.Sim.CompleteAgentMovement(Client.Protocol, Client.Network.AgentID,
+ Client.Network.SessionID, Client.Network.CurrentSim.CircuitCode);
+ Client.Network.SendPacket(movePacket);
+
+ Client.Log("Connected to new sim " + Client.Network.CurrentSim.IPEndPoint.ToString(),
+ Helpers.LogLevel.Info);
+
+ // Sleep a little while so we can collect parcel information
+ System.Threading.Thread.Sleep(1000);
+
+ Client.CurrentRegion = Client.Network.CurrentSim.Region;
+ TeleportStatus = 1;
+ return;
+ }
+ else
+ {
+ TeleportStatus = -1;
+ return;
+ }
+ }
+ }
+
+ private void TeleportTimerEvent(object source, System.Timers.ElapsedEventArgs ea)
+ {
+ TeleportTimeout = true;
+ }
+ }
}
diff --git a/libsecondlife-cs/GridManager.cs b/libsecondlife-cs/GridManager.cs
index cbec7d43..861f2472 100644
--- a/libsecondlife-cs/GridManager.cs
+++ b/libsecondlife-cs/GridManager.cs
@@ -97,7 +97,7 @@ namespace libsecondlife
else
{
/* TODO: Put some better handling inplace here with some retry code */
- Helpers.Log("Error returned sim that didnt exist",Helpers.LogLevel.Warning);
+ Client.Log("Error returned sim that didnt exist",Helpers.LogLevel.Warning);
return new GridRegion();
}
}
diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs
index 370841e6..a570bd19 100644
--- a/libsecondlife-cs/NetworkManager.cs
+++ b/libsecondlife-cs/NetworkManager.cs
@@ -58,6 +58,7 @@ namespace libsecondlife
public class Simulator
{
+ private SecondLife Client;
private ProtocolManager Protocol;
private NetworkManager Network;
private Hashtable Callbacks;
@@ -99,6 +100,7 @@ namespace libsecondlife
private void Initialize(SecondLife client, Hashtable callbacks, uint circuit,
IPAddress ip, int port)
{
+ Client = client;
Protocol = client.Protocol;
Network = client.Network;
Callbacks = callbacks;
@@ -118,7 +120,7 @@ namespace libsecondlife
NeedAckMutex = new Mutex(false, "NeedAckMutex");
InboxMutex = new Mutex(false, "InboxMutex");
- Helpers.Log("Connecting to " + ip.ToString() + ":" + port, Helpers.LogLevel.Info);
+ Client.Log("Connecting to " + ip.ToString() + ":" + port, Helpers.LogLevel.Info);
try
{
@@ -155,7 +157,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
+ Client.Log(e.ToString(), Helpers.LogLevel.Error);
}
}
@@ -174,7 +176,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
+ Client.Log(e.ToString(), Helpers.LogLevel.Error);
}
}
@@ -185,7 +187,7 @@ namespace libsecondlife
if (!connected && packet.Layout.Name != "UseCircuitCode")
{
- Helpers.Log("Trying to send a " + packet.Layout.Name + " packet when the socket is closed",
+ Client.Log("Trying to send a " + packet.Layout.Name + " packet when the socket is closed",
Helpers.LogLevel.Warning);
throw new NotConnectedException();
@@ -256,7 +258,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
+ Client.Log(e.ToString(), Helpers.LogLevel.Error);
}
}
@@ -276,7 +278,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
+ Client.Log(e.ToString(), Helpers.LogLevel.Error);
}
}
@@ -299,7 +301,7 @@ namespace libsecondlife
// Grab the ACKs that are appended to this packet
byte numAcks = RecvBuffer[numBytes - 1];
- Helpers.Log("Found " + numAcks + " appended acks", Helpers.LogLevel.Info);
+ Client.Log("Found " + numAcks + " appended acks", Helpers.LogLevel.Info);
NeedAckMutex.WaitOne();
for (int i = 1; i <= numAcks; ++i)
@@ -341,9 +343,15 @@ namespace libsecondlife
// Start listening again since we're done with RecvBuffer
Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null);
-
RecvBufferMutex.ReleaseMutex();
+ if (packet.Layout.Name == "")
+ {
+ // TODO: Add a packet dump function to Packet and dump the raw data here
+ Client.Log("Received an unrecognized packet", Helpers.LogLevel.Warning);
+ return;
+ }
+
// Track the sequence number for this packet if it's marked as reliable
if ((packet.Data[0] & Helpers.MSG_RELIABLE) != 0)
{
@@ -355,7 +363,7 @@ namespace libsecondlife
InboxMutex.WaitOne();
if (Inbox.Contains(packet.Sequence))
{
- Helpers.Log("Received a duplicate " + packet.Layout.Name + ", sequence=" +
+ Client.Log("Received a duplicate " + packet.Layout.Name + ", sequence=" +
packet.Sequence + ", resent=" +
(((packet.Data[0] & Helpers.MSG_RESENT) != 0) ? "Yes" : "No"),
Helpers.LogLevel.Info);
@@ -373,7 +381,7 @@ namespace libsecondlife
if (packet.Layout.Name == null)
{
- Helpers.Log("Received an unrecognized packet", Helpers.LogLevel.Warning);
+ Client.Log("Received an unrecognized packet", Helpers.LogLevel.Warning);
return;
}
else if (packet.Layout.Name == "PacketAck")
@@ -432,7 +440,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
+ Client.Log(e.ToString(), Helpers.LogLevel.Error);
}
}
}
@@ -483,7 +491,7 @@ namespace libsecondlife
{
if (!Callbacks.ContainsKey(packet))
{
- Helpers.Log("Trying to unregister a callback for packet " + packet +
+ Client.Log("Trying to unregister a callback for packet " + packet +
" when no callbacks are setup for that packet", Helpers.LogLevel.Info);
return;
}
@@ -496,7 +504,7 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Trying to unregister a non-existant callback for packet " + packet,
+ Client.Log("Trying to unregister a non-existant callback for packet " + packet,
Helpers.LogLevel.Info);
}
}
@@ -509,7 +517,7 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Trying to send a packet when there is no current simulator", Helpers.LogLevel.Error);
+ Client.Log("Trying to send a packet when there is no current simulator", Helpers.LogLevel.Error);
}
}
@@ -578,7 +586,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
+ Client.Log(e.ToString(), Helpers.LogLevel.Error);
LoginError = e.Message;
LoginValues = null;
return false;
@@ -586,7 +594,7 @@ namespace libsecondlife
if (result.IsFault)
{
- Helpers.Log("Fault " + result.FaultCode + ": " + result.FaultString, Helpers.LogLevel.Error);
+ Client.Log("Fault " + result.FaultCode + ": " + result.FaultString, Helpers.LogLevel.Error);
LoginError = "Fault " + result.FaultCode + ": " + result.FaultString;
LoginValues = null;
return false;
@@ -722,7 +730,7 @@ namespace libsecondlife
/*
if (circuit == CurrentCircuit)
{
- Helpers.Log("Disconnecting simulator " + simulator.IPEndPoint.ToString(), Helpers.LogLevel.Info);
+ Client.Log("Disconnecting simulator " + simulator.IPEndPoint.ToString(), Helpers.LogLevel.Info);
circuit.CloseCircuit();
@@ -731,12 +739,12 @@ namespace libsecondlife
if (Circuits.Count > 0)
{
CurrentCircuit = (Circuit)Circuits[0];
- Helpers.Log("Switched current simulator to " + CurrentCircuit.ipEndPoint.ToString(),
+ Client.Log("Switched current simulator to " + CurrentCircuit.ipEndPoint.ToString(),
Helpers.LogLevel.Info);
}
else
{
- Helpers.Log("Last circuit disconnected, no open connections left", Helpers.LogLevel.Info);
+ Client.Log("Last circuit disconnected, no open connections left", Helpers.LogLevel.Info);
CurrentCircuit = null;
}
CircuitsMutex.ReleaseMutex();
@@ -745,7 +753,7 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Disconnecting circuit " + circuit.ipEndPoint.ToString(), Helpers.LogLevel.Info);
+ Client.Log("Disconnecting circuit " + circuit.ipEndPoint.ToString(), Helpers.LogLevel.Info);
circuit.CloseCircuit();
CircuitsMutex.WaitOne();
@@ -754,7 +762,7 @@ namespace libsecondlife
return;
}
- //Helpers.Log("Disconnect called with invalid circuit code " + circuitCode, Helpers.LogLevel.Warning);
+ //Client.Log("Disconnect called with invalid circuit code " + circuitCode, Helpers.LogLevel.Warning);
*/
}
@@ -790,7 +798,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log("Logout error: " + e.ToString(), Helpers.LogLevel.Error);
+ Client.Log("Logout error: " + e.ToString(), Helpers.LogLevel.Error);
}
}
@@ -897,7 +905,7 @@ namespace libsecondlife
}
}
- Helpers.Log("Received a region handshake for " + simulator.Region.Name, Helpers.LogLevel.Info);
+ Client.Log("Received a region handshake for " + simulator.Region.Name, Helpers.LogLevel.Info);
// Send a RegionHandshakeReply
Packet replyPacket = new Packet("RegionHandshakeReply", Protocol, 12);
@@ -905,7 +913,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Warning);
+ Client.Log(e.ToString(), Helpers.LogLevel.Warning);
}
}
@@ -927,7 +935,7 @@ namespace libsecondlife
byteArray = (byte[])field.Data;
if (byteArray.Length != 1024)
{
- Helpers.Log("Received a parcel overlay packet with " + byteArray.Length + " bytes",
+ Client.Log("Received a parcel overlay packet with " + byteArray.Length + " bytes",
Helpers.LogLevel.Error);
}
}
@@ -942,7 +950,7 @@ namespace libsecondlife
if (simulator.Region.ParcelOverlaysReceived > 3)
{
simulator.Region.ParcelOverlaysReceived = 0;
- Helpers.Log("Finished building the " + simulator.Region.Name + " parcel overlay",
+ Client.Log("Finished building the " + simulator.Region.Name + " parcel overlay",
Helpers.LogLevel.Info);
// The int i = 0; is just there so I could break on it and check the
@@ -953,7 +961,7 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Parcel overlay with sequence ID of " + sequenceID + " received from " +
+ Client.Log("Parcel overlay with sequence ID of " + sequenceID + " received from " +
simulator.Region.Name, Helpers.LogLevel.Error);
}
}
diff --git a/libsecondlife-cs/Packet.cs b/libsecondlife-cs/Packet.cs
index 361164c6..02242857 100644
--- a/libsecondlife-cs/Packet.cs
+++ b/libsecondlife-cs/Packet.cs
@@ -138,8 +138,13 @@ namespace libsecondlife
if (Layout == null)
{
- Helpers.Log("Attempting to build a packet with invalid command \"" + command + "\"",
- Helpers.LogLevel.Error);
+ //Client.Log("Attempting to build a packet with invalid command \"" + command + "\"",
+ // Helpers.LogLevel.Error);
+
+ // Create an empty Layout
+ Layout = new MapPacket();
+ Layout.Blocks = new ArrayList();
+ return;
}
switch (Layout.Frequency)
@@ -181,8 +186,6 @@ namespace libsecondlife
if (Layout == null)
{
- Helpers.Log("Received a packet with an unknown command ID:\n" + libsecondlife.Utils.ByteArrayStuff.ByteArrayToString((byte[])data), Helpers.LogLevel.Warning);
-
// Create an empty MapPacket
Layout = new MapPacket();
Layout.Blocks = new ArrayList();
@@ -229,9 +232,10 @@ namespace libsecondlife
pos++;
}
else
-
{
- Helpers.Log("Blocks(): end of packet in 1-byte variable block count for " + Layout.Name + "." + blockMap.Name + " (" + pos + "/" + length + ")", Helpers.LogLevel.Warning);
+ // FIXME: Figure out a sane way to log from this function
+ Console.WriteLine("WARNING: Blocks(): end of packet in 1-byte variable block count for " +
+ Layout.Name + "." + blockMap.Name + " (" + pos + "/" + length + ")");
goto Done;
}
}
@@ -261,7 +265,8 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Blocks(): end of packet in 1-byte variable field count for " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")", Helpers.LogLevel.Warning);
+ Console.WriteLine("WARNING: Blocks(): end of packet in 1-byte variable field count for " +
+ Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")");
goto BlockDone;
}
}
@@ -275,7 +280,8 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Blocks(): end of packet in 2-byte variable field count for " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")", Helpers.LogLevel.Warning);
+ Console.WriteLine("WARNING: Blocks(): end of packet in 2-byte variable field count for " +
+ Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")");
goto BlockDone;
}
}
@@ -295,7 +301,9 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Blocks(): end of packet in " + fieldSize + "-byte variable field " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")", Helpers.LogLevel.Warning);
+ Console.WriteLine("WARNING: Blocks(): end of packet in " + fieldSize +
+ "-byte variable field " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name +
+ " (" + pos + "/" + length + ")");
goto BlockDone;
}
}
@@ -317,7 +325,8 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Blocks(): end of packet in " + fieldSize + "-byte fixed field " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")", Helpers.LogLevel.Warning);
+ Console.WriteLine("WARNING: Blocks(): end of packet in " + fieldSize + "-byte fixed field " +
+ Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")");
goto BlockDone;
}
}
@@ -340,7 +349,9 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Blocks(): end of packet in " + fieldSize + "-byte " + fieldMap.Type + " field " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name + " (" + pos + "/" + length + ")", Helpers.LogLevel.Warning);
+ Console.WriteLine("WARNING: Blocks(): end of packet in " + fieldSize + "-byte " +
+ fieldMap.Type + " field " + Layout.Name + "." + blockMap.Name + "." + fieldMap.Name +
+ " (" + pos + "/" + length + ")");
goto BlockDone;
}
}
@@ -523,8 +534,7 @@ namespace libsecondlife
if (blockCount > 255)
{
- Helpers.Log("Trying to put more than 255 blocks in a variable block position, " +
- "this will not end well", Helpers.LogLevel.Error);
+ throw new Exception("Trying to put more than 255 blocks in a variable block");
}
// Prepend the blocks with a count
@@ -545,7 +555,7 @@ namespace libsecondlife
if ((string)blocksEnum.Value == blockMap.Name)
{
// Found a match of this block
- if (blockMap.Count == -1 || blockCount < blockMap.Count)
+ if ((blockMap.Count == -1 && blockCount < 255) || blockCount < blockMap.Count)
{
blockCount++;
@@ -554,11 +564,9 @@ namespace libsecondlife
{
fields = (Hashtable)blocksEnum.Key;
}
- catch (Exception)
+ catch (Exception e)
{
- Helpers.Log("Something other than a field Hashtable was passed to BuildPacket " +
- "inside of the block Hashtable", Helpers.LogLevel.Warning);
- continue;
+ throw new Exception("A block Hashtable did not contain a fields Hashtable", e);
}
#endregion TryBlockTypecast
@@ -569,187 +577,152 @@ namespace libsecondlife
object field = fields[fieldMap.Name];
#region AddField
- try
+ switch (fieldMap.Type)
{
- switch (fieldMap.Type)
- {
- case FieldType.U8:
- byteArray[length++] = (byte)field;
- break;
- case FieldType.U16:
- ushort fieldUShort = (ushort)field;
- byteArray[length++] = (byte)(fieldUShort % 256);
- fieldUShort >>= 8;
- byteArray[length++] = (byte)(fieldUShort % 256);
- break;
- case FieldType.U32:
- uint fieldUInt = (uint)field;
- byteArray[length++] = (byte)(fieldUInt % 256);
- fieldUInt >>= 8;
- byteArray[length++] = (byte)(fieldUInt % 256);
- fieldUInt >>= 8;
- byteArray[length++] = (byte)(fieldUInt % 256);
- fieldUInt >>= 8;
- byteArray[length++] = (byte)(fieldUInt % 256);
- break;
- case FieldType.U64:
- // FIXME: Apply endianness patch
- Array.Copy(((U64)field).GetBytes(), 0, byteArray, length, 8);
- length += 8;
- break;
- case FieldType.S8:
- byteArray[length++] = (byte)((sbyte)field);
- break;
- case FieldType.S16:
- // FIXME: Apply endianness patch
- Array.Copy(BitConverter.GetBytes((short)field), 0, byteArray, length, 2);
- length += 2;
- break;
- case FieldType.S32:
- // FIXME: Apply endianness patch
- Array.Copy(BitConverter.GetBytes((int)field), 0, byteArray, length, 4);
- length += 4;
- break;
- case FieldType.S64:
- // FIXME: Apply endianness patch
- Array.Copy(BitConverter.GetBytes((long)field), 0, byteArray, length, 8);
- length += 8;
- break;
- case FieldType.F32:
- Array.Copy(BitConverter.GetBytes((float)field), 0, byteArray, length, 4);
- length += 4;
- break;
- case FieldType.F64:
- Array.Copy(BitConverter.GetBytes((double)field), 0, byteArray, length, 8);
- length += 8;
- break;
- case FieldType.LLUUID:
- Array.Copy(((LLUUID)field).Data, 0, byteArray, length, 16);
- length += 16;
- break;
- case FieldType.BOOL:
- byteArray[length] = (byte)((bool)field == true ? 1 : 0);
+ case FieldType.U8:
+ byteArray[length++] = (byte)field;
+ break;
+ case FieldType.U16:
+ ushort fieldUShort = (ushort)field;
+ byteArray[length++] = (byte)(fieldUShort % 256);
+ fieldUShort >>= 8;
+ byteArray[length++] = (byte)(fieldUShort % 256);
+ break;
+ case FieldType.U32:
+ uint fieldUInt = (uint)field;
+ byteArray[length++] = (byte)(fieldUInt % 256);
+ fieldUInt >>= 8;
+ byteArray[length++] = (byte)(fieldUInt % 256);
+ fieldUInt >>= 8;
+ byteArray[length++] = (byte)(fieldUInt % 256);
+ fieldUInt >>= 8;
+ byteArray[length++] = (byte)(fieldUInt % 256);
+ break;
+ case FieldType.U64:
+ // FIXME: Apply endianness patch
+ Array.Copy(((U64)field).GetBytes(), 0, byteArray, length, 8);
+ length += 8;
+ break;
+ case FieldType.S8:
+ byteArray[length++] = (byte)((sbyte)field);
+ break;
+ case FieldType.S16:
+ // FIXME: Apply endianness patch
+ Array.Copy(BitConverter.GetBytes((short)field), 0, byteArray, length, 2);
+ length += 2;
+ break;
+ case FieldType.S32:
+ // FIXME: Apply endianness patch
+ Array.Copy(BitConverter.GetBytes((int)field), 0, byteArray, length, 4);
+ length += 4;
+ break;
+ case FieldType.S64:
+ // FIXME: Apply endianness patch
+ Array.Copy(BitConverter.GetBytes((long)field), 0, byteArray, length, 8);
+ length += 8;
+ break;
+ case FieldType.F32:
+ Array.Copy(BitConverter.GetBytes((float)field), 0, byteArray, length, 4);
+ length += 4;
+ break;
+ case FieldType.F64:
+ Array.Copy(BitConverter.GetBytes((double)field), 0, byteArray, length, 8);
+ length += 8;
+ break;
+ case FieldType.LLUUID:
+ Array.Copy(((LLUUID)field).Data, 0, byteArray, length, 16);
+ length += 16;
+ break;
+ case FieldType.BOOL:
+ byteArray[length] = (byte)((bool)field == true ? 1 : 0);
+ length++;
+ break;
+ case FieldType.LLVector3:
+ Array.Copy(((LLVector3)field).GetBytes(), 0, byteArray, length, 12);
+ length += 12;
+ break;
+ case FieldType.LLVector3d:
+ Array.Copy(((LLVector3d)field).GetBytes(), 0, byteArray, length, 24);
+ length += 24;
+ break;
+ case FieldType.LLVector4:
+ Array.Copy(((LLVector4)field).GetBytes(), 0, byteArray, length, 16);
+ length += 16;
+ break;
+ case FieldType.LLQuaternion:
+ Array.Copy(((LLQuaternion)field).GetBytes(), 0, byteArray, length, 16);
+ length += 16;
+ break;
+ case FieldType.IPADDR:
+ Array.Copy(((IPAddress)field).GetAddressBytes(), 0, byteArray, length, 4);
+ length += 4;
+ break;
+ case FieldType.IPPORT:
+ ushort fieldIPPort = (ushort)field;
+ byteArray[length + 1] = (byte)(fieldIPPort % 256);
+ fieldIPPort >>= 8;
+ byteArray[length] = (byte)(fieldIPPort % 256);
+ length += 2;
+ break;
+ case FieldType.Variable:
+ if (field.GetType().IsArray)
+ {
+ // Assume this is a byte array
+ fieldLength = ((byte[])field).Length;
+ }
+ else
+ {
+ // Assume this is a string, add 1 for the null terminator
+ fieldLength = ((string)field).Length + 1;
+ }
+
+ if (fieldMap.Count == 1)
+ {
+ if (fieldLength > 255)
+ {
+ throw new Exception("Variable byte field longer than 255 characters");
+ }
+
+ byteArray[length] = (byte)(fieldLength);
length++;
- break;
- case FieldType.LLVector3:
- Array.Copy(((LLVector3)field).GetBytes(), 0, byteArray, length, 12);
- length += 12;
- break;
- case FieldType.LLVector3d:
- Array.Copy(((LLVector3d)field).GetBytes(), 0, byteArray, length, 24);
- length += 24;
- break;
- case FieldType.LLVector4:
- Array.Copy(((LLVector4)field).GetBytes(), 0, byteArray, length, 16);
- length += 16;
- break;
- case FieldType.LLQuaternion:
- Array.Copy(((LLQuaternion)field).GetBytes(), 0, byteArray, length, 16);
- length += 16;
- break;
- case FieldType.IPADDR:
- Array.Copy(((IPAddress)field).GetAddressBytes(), 0, byteArray, length, 4);
- length += 4;
- break;
- case FieldType.IPPORT:
- ushort fieldIPPort = (ushort)field;
- byteArray[length + 1] = (byte)(fieldIPPort % 256);
- fieldIPPort >>= 8;
- byteArray[length] = (byte)(fieldIPPort % 256);
- length += 2;
- break;
- case FieldType.Variable:
- if (fieldMap.Count == 1)
+ }
+ else if (fieldMap.Count == 2)
+ {
+ if (fieldLength > 1024)
{
- if (fieldLength > 255)
- {
- Helpers.Log("Truncating variable (byte) field to 255 " +
- "characters. fieldLength=" + fieldLength +
- ", fieldMap.Name=" + fieldMap.Name + ", packetMap.Name=" + packetMap.Name,
- Helpers.LogLevel.Warning);
-
- fieldLength = 255;
- }
- }
- else if (fieldMap.Count == 2)
- {
- if (fieldLength > 1024)
- {
- Helpers.Log("Truncating variable (byte) field to 1024 " +
- "characters", Helpers.LogLevel.Warning);
-
- fieldLength = 1024;
- }
- }
- else
- {
- Helpers.Log("Variable field with an unknown count", Helpers.LogLevel.Warning);
+ throw new Exception("Variable byte field longer than 1024 characters");
}
- if (field.GetType().IsArray)
- {
- // Assume this is a byte array
- fieldLength = ((byte[])field).Length;
- }
- else
- {
- // Assume this is a string, add 1 for the null terminator
- fieldLength = ((string)field).Length + 1;
- }
+ byteArray[length++] = (byte)(fieldLength % 256);
+ byteArray[length++] = (byte)(fieldLength / 256);
+ }
+ else
+ {
+ throw new Exception("Variable field with an unknown count, protocol map error");
+ }
+
+ if (field.GetType().IsArray)
+ {
+ // Assume this is a byte array
+ Array.Copy((byte[])field, 0, byteArray, length, fieldLength);
+ }
+ else
+ {
+ // Assume this is a string, add 1 for the null terminator
+ byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes((string)field);
+ Array.Copy(stringBytes, 0, byteArray, length, stringBytes.Length);
+ fieldLength = stringBytes.Length + 1;
+ }
- if (fieldMap.Count == 2)
- {
- byteArray[length++] = (byte)(fieldLength % 256);
- byteArray[length++] = (byte)(fieldLength / 256);
- }
- else
- {
- if (fieldMap.Count != 1)
- {
- Helpers.Log("Variable field " + fieldMap.Name + " has a count of " +
- + fieldMap.Count + ", ignoring and assuming 1",
- Helpers.LogLevel.Warning);
- }
+ length += fieldLength;
- byteArray[length] = (byte)(fieldLength);
- length++;
- }
-
- if (field.GetType().IsArray)
- {
- // Assume this is a byte array
- Array.Copy((byte[])field, 0, byteArray, length, fieldLength);
- }
- else
- {
- // Assume this is a string, add 1 for the null terminator
- byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes((string)field);
- Array.Copy(stringBytes, 0, byteArray, length, stringBytes.Length);
- fieldLength = stringBytes.Length + 1;
- }
-
- length += fieldLength;
-
- break;
- case FieldType.Fixed:
- Array.Copy((byte[])field, 0, byteArray, length, fieldMap.Count);
- length += fieldMap.Count;
- break;
- default:
- Helpers.Log("Unhandled field type " + fieldMap.Type + " during " +
- "packet construction", Helpers.LogLevel.Error);
- break;
- }
- }
- catch (Exception err)
- {
- Helpers.Log("PacketBuilder.BuildPacket(): " + err.ToString(), Helpers.LogLevel.Error);
- //Data type " + field.GetType().ToString() + " for field " +
- // fieldMap.Name + " doesn't match expected type " + fieldMap.Type.ToString(),
- // );
- // This will fail for fixed or variable type packets, but it's a
- // last ditch effort
- length += (int)protocol.TypeSizes[fieldMap.Type];
+ break;
+ case FieldType.Fixed:
+ Array.Copy((byte[])field, 0, byteArray, length, fieldMap.Count);
+ length += fieldMap.Count;
+ break;
+ default:
+ throw new Exception("Unhandled FieldType");
}
#endregion AddField
}
@@ -768,9 +741,7 @@ namespace libsecondlife
{
if (fieldMap.Count != 1)
{
- Helpers.Log("Variable field " + fieldMap.Name + " has a count of " +
- + fieldMap.Count + ", ignoring and assuming 1",
- Helpers.LogLevel.Warning);
+ throw new Exception("Variable length field has an invalid Count");
}
length++;
@@ -790,8 +761,7 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Trying to build a " + packetMap.Name + " packet with too many " +
- blockMap.Name + " blocks", Helpers.LogLevel.Warning);
+ throw new Exception("Too many blocks");
}
}
}
diff --git a/libsecondlife-cs/Parcel.cs b/libsecondlife-cs/Parcel.cs
index 8bc130c4..0f5971b2 100644
--- a/libsecondlife-cs/Parcel.cs
+++ b/libsecondlife-cs/Parcel.cs
@@ -456,7 +456,7 @@ namespace libsecondlife
else if(field.Layout.Name == "LandingType")
LandingType = (byte)field.Data;
// else
- // Helpers.Log("Unknown field type '" + field.Layout.Name + "' in ParcelProperties",Helpers.LogLevel.Warning);
+ // Client.Log("Unknown field type '" + field.Layout.Name + "' in ParcelProperties",Helpers.LogLevel.Warning);
}
}
@@ -597,7 +597,7 @@ namespace libsecondlife
if (!parcelID.Equals(ParcelInfoParcel.ID))
{
- Helpers.Log("Received a ParcelInfoReply for " + parcelID.ToString() +
+ Client.Log("Received a ParcelInfoReply for " + parcelID.ToString() +
", looking for " + ParcelInfoParcel.ID.ToString(), Helpers.LogLevel.Warning);
// Build and resend the ParcelInfoRequest packet
@@ -682,7 +682,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
+ Client.Log(e.ToString(), Helpers.LogLevel.Error);
}
Finished = true;
@@ -786,7 +786,7 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Parcel with no ID found in DirLandReply, skipping", Helpers.LogLevel.Warning);
+ Client.Log("Parcel with no ID found in DirLandReply, skipping", Helpers.LogLevel.Warning);
}
}
diff --git a/libsecondlife-cs/ProtocolManager.cs b/libsecondlife-cs/ProtocolManager.cs
index 43dd25ec..a9de3f0f 100644
--- a/libsecondlife-cs/ProtocolManager.cs
+++ b/libsecondlife-cs/ProtocolManager.cs
@@ -39,9 +39,9 @@ namespace libsecondlife
public class MapField : IComparable
{
- public int KeywordPosition;
- public string Name;
- public FieldType Type;
+ public int KeywordPosition;
+ public string Name;
+ public FieldType Type;
public int Count;
public int CompareTo(object obj)
@@ -68,9 +68,9 @@ namespace libsecondlife
public class MapBlock : IComparable
{
- public int KeywordPosition;
- public string Name;
- public int Count;
+ public int KeywordPosition;
+ public string Name;
+ public int Count;
public ArrayList Fields;
public int CompareTo(object obj)
@@ -112,10 +112,14 @@ namespace libsecondlife
public MapPacket[] LowMaps;
public MapPacket[] MediumMaps;
public MapPacket[] HighMaps;
- int i = 0;
- public ProtocolManager(string keywordFile, string mapFile)
+ private SecondLife Client;
+ private int i = 0;
+
+ public ProtocolManager(string keywordFile, string mapFile, SecondLife client)
{
+ Client = client;
+
// Initialize the map arrays
LowMaps = new MapPacket[65536];
MediumMaps = new MapPacket[256];
@@ -194,13 +198,13 @@ namespace libsecondlife
throw new Exception("Cannot find map for command \"" + command + "\"");
}
- public MapPacket Command(byte[] data)
- {
+ public MapPacket Command(byte[] data)
+ {
ushort command;
if (data.Length < 5)
{
- return null;
+ return null;
}
if (data[4] == 0xFF)
@@ -209,22 +213,22 @@ namespace libsecondlife
{
// Low frequency
command = (ushort)(data[6] * 256 + data[7]);
- return Command(command, PacketFrequency.Low);
+ return Command(command, PacketFrequency.Low);
}
else
{
// Medium frequency
command = (ushort)data[5];
- return Command(command, PacketFrequency.Medium);
+ return Command(command, PacketFrequency.Medium);
}
}
else
{
// High frequency
command = (ushort)data[4];
- return Command(command, PacketFrequency.High);
- }
- }
+ return Command(command, PacketFrequency.High);
+ }
+ }
public MapPacket Command(ushort command, PacketFrequency frequency)
{
@@ -294,7 +298,7 @@ namespace libsecondlife
}
catch(Exception e)
{
- Helpers.Log("Error opening \"" + keywordFile + "\": " + e.Message, Helpers.LogLevel.Error);
+ Client.Log("Error opening \"" + keywordFile + "\": " + e.Message, Helpers.LogLevel.Error);
throw new Exception("Keyword file error", e);
}
@@ -320,7 +324,6 @@ namespace libsecondlife
}
catch(Exception e)
{
- Helpers.Log("Error opening \"" + mapFile + "\": " + e.Message, Helpers.LogLevel.Error);
throw new Exception("Map file error", e);
}
@@ -330,7 +333,6 @@ namespace libsecondlife
}
catch(Exception e)
{
- Helpers.Log("Error opening \"" + outputFile + "\": " + e.Message, Helpers.LogLevel.Error);
throw new Exception("Map file error", e);
}
@@ -363,7 +365,6 @@ namespace libsecondlife
}
catch(Exception e)
{
- Helpers.Log("Error opening \"" + mapFile + "\": " + e.Message, Helpers.LogLevel.Error);
throw new Exception("Map file error", e);
}
@@ -490,7 +491,7 @@ namespace libsecondlife
}
else
{
- Helpers.Log("!!!", Helpers.LogLevel.Error);
+ Client.Log("Unknown packet frequency", Helpers.LogLevel.Error);
}
}
@@ -561,7 +562,7 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Unknown block frequency!", Helpers.LogLevel.Error);
+ Client.Log("Unknown block frequency", Helpers.LogLevel.Error);
}
#endregion
@@ -577,7 +578,7 @@ namespace libsecondlife
}
catch (Exception e)
{
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
+ throw e;
}
}
@@ -589,9 +590,9 @@ namespace libsecondlife
}
else
{
- Helpers.Log("Couldn't find keyword: " + keyword, Helpers.LogLevel.Warning);
+ Client.Log("Couldn't find keyword: " + keyword, Helpers.LogLevel.Warning);
return -1;
}
}
}
-}
+}
diff --git a/libsecondlife-cs/Region.cs b/libsecondlife-cs/Region.cs
index e6d97144..31d76b30 100644
--- a/libsecondlife-cs/Region.cs
+++ b/libsecondlife-cs/Region.cs
@@ -28,227 +28,227 @@ using System;
namespace libsecondlife
{
- public delegate void ParcelCompleteCallback(Region region);
+ public delegate void ParcelCompleteCallback(Region region);
- ///
- /// Represents a region (also known as a sim) in Second Life.
- ///
- public class Region
- {
- public LLUUID ID;
- public U64 Handle;
- public string Name;
- public byte[] ParcelOverlay;
- public int ParcelOverlaysReceived;
+ ///
+ /// Represents a region (also known as a sim) in Second Life.
+ ///
+ public class Region
+ {
+ public LLUUID ID;
+ public U64 Handle;
+ public string Name;
+ public byte[] ParcelOverlay;
+ public int ParcelOverlaysReceived;
- public int[,] ParcelMarked; // 64x64 Array of parcels which have been successfully downloaded. (and their LocalID's, 0 = Null)
- public bool ParcelDownloading; // Flag to indicate whether we are downloading a sim's parcels.
- public bool ParcelDwell; // Flag to indicate whether to get Dwell values automatically (NOT USED YET).
- // Call .GetDwell() instead.
+ public int[,] ParcelMarked; // 64x64 Array of parcels which have been successfully downloaded. (and their LocalID's, 0 = Null)
+ public bool ParcelDownloading; // Flag to indicate whether we are downloading a sim's parcels.
+ public bool ParcelDwell; // Flag to indicate whether to get Dwell values automatically (NOT USED YET).
+ // Call .GetDwell() instead.
- public System.Collections.Hashtable Parcels;
- public System.Threading.Mutex ParcelsMutex;
+ public System.Collections.Hashtable Parcels;
+ public System.Threading.Mutex ParcelsMutex;
- public float TerrainHeightRange00;
- public float TerrainHeightRange01;
- public float TerrainHeightRange10;
- public float TerrainHeightRange11;
- public float TerrainStartHeight00;
- public float TerrainStartHeight01;
- public float TerrainStartHeight10;
- public float TerrainStartHeight11;
- public float WaterHeight;
+ public float TerrainHeightRange00;
+ public float TerrainHeightRange01;
+ public float TerrainHeightRange10;
+ public float TerrainHeightRange11;
+ public float TerrainStartHeight00;
+ public float TerrainStartHeight01;
+ public float TerrainStartHeight10;
+ public float TerrainStartHeight11;
+ public float WaterHeight;
- public LLUUID SimOwner;
+ public LLUUID SimOwner;
- public LLUUID TerrainBase0;
- public LLUUID TerrainBase1;
- public LLUUID TerrainBase2;
- public LLUUID TerrainBase3;
- public LLUUID TerrainDetail0;
- public LLUUID TerrainDetail1;
- public LLUUID TerrainDetail2;
- public LLUUID TerrainDetail3;
+ public LLUUID TerrainBase0;
+ public LLUUID TerrainBase1;
+ public LLUUID TerrainBase2;
+ public LLUUID TerrainBase3;
+ public LLUUID TerrainDetail0;
+ public LLUUID TerrainDetail1;
+ public LLUUID TerrainDetail2;
+ public LLUUID TerrainDetail3;
- public bool IsEstateManager;
- public EstateTools Estate;
+ public bool IsEstateManager;
+ public EstateTools Estate;
- private SecondLife Client;
+ private SecondLife Client;
- public event ParcelCompleteCallback OnParcelCompletion;
+ public event ParcelCompleteCallback OnParcelCompletion;
- public Region(SecondLife client)
- {
- Estate = new EstateTools(client);
- Client = client;
- ID = new LLUUID();
- Handle = new U64();
- Name = "";
- ParcelOverlay = new byte[4096];
- ParcelOverlaysReceived = 0;
+ public Region(SecondLife client)
+ {
+ Estate = new EstateTools(client);
+ Client = client;
+ ID = new LLUUID();
+ Handle = new U64();
+ Name = "";
+ ParcelOverlay = new byte[4096];
+ ParcelOverlaysReceived = 0;
- ParcelMarked = new int[64,64];
- ParcelDownloading = false;
- ParcelDwell = false;
+ ParcelMarked = new int[64, 64];
+ ParcelDownloading = false;
+ ParcelDwell = false;
- Parcels = new System.Collections.Hashtable();
- ParcelsMutex = new System.Threading.Mutex(false,"ParcelsMutex");
+ Parcels = new System.Collections.Hashtable();
+ ParcelsMutex = new System.Threading.Mutex(false, "ParcelsMutex");
- SimOwner = new LLUUID();
+ SimOwner = new LLUUID();
- TerrainBase0 = new LLUUID();
- TerrainBase1 = new LLUUID();
- TerrainBase2 = new LLUUID();
- TerrainBase3 = new LLUUID();
- TerrainDetail0 = new LLUUID();
- TerrainDetail1 = new LLUUID();
- TerrainDetail2 = new LLUUID();
- TerrainDetail3 = new LLUUID();
+ TerrainBase0 = new LLUUID();
+ TerrainBase1 = new LLUUID();
+ TerrainBase2 = new LLUUID();
+ TerrainBase3 = new LLUUID();
+ TerrainDetail0 = new LLUUID();
+ TerrainDetail1 = new LLUUID();
+ TerrainDetail2 = new LLUUID();
+ TerrainDetail3 = new LLUUID();
- IsEstateManager = false;
- }
+ IsEstateManager = false;
+ }
- public Region(SecondLife client, LLUUID id, U64 handle, string name, float[] heightList,
- LLUUID simOwner, LLUUID[] terrainImages, bool isEstateManager)
- {
- Client = client;
- Estate = new EstateTools(client);
- ID = id;
- Handle = handle;
- Name = name;
- ParcelOverlay = new byte[4096];
- ParcelMarked = new int[64,64];
- ParcelDownloading = false;
- ParcelDwell = false;
+ public Region(SecondLife client, LLUUID id, U64 handle, string name, float[] heightList,
+ LLUUID simOwner, LLUUID[] terrainImages, bool isEstateManager)
+ {
+ Client = client;
+ Estate = new EstateTools(client);
+ ID = id;
+ Handle = handle;
+ Name = name;
+ ParcelOverlay = new byte[4096];
+ ParcelMarked = new int[64, 64];
+ ParcelDownloading = false;
+ ParcelDwell = false;
- TerrainHeightRange00 = heightList[0];
- TerrainHeightRange01 = heightList[1];
- TerrainHeightRange10 = heightList[2];
- TerrainHeightRange11 = heightList[3];
- TerrainStartHeight00 = heightList[4];
- TerrainStartHeight01 = heightList[5];
- TerrainStartHeight10 = heightList[6];
- TerrainStartHeight11 = heightList[7];
- WaterHeight = heightList[8];
+ TerrainHeightRange00 = heightList[0];
+ TerrainHeightRange01 = heightList[1];
+ TerrainHeightRange10 = heightList[2];
+ TerrainHeightRange11 = heightList[3];
+ TerrainStartHeight00 = heightList[4];
+ TerrainStartHeight01 = heightList[5];
+ TerrainStartHeight10 = heightList[6];
+ TerrainStartHeight11 = heightList[7];
+ WaterHeight = heightList[8];
- SimOwner = simOwner;
+ SimOwner = simOwner;
- TerrainBase0 = terrainImages[0];
- TerrainBase1 = terrainImages[1];
- TerrainBase2 = terrainImages[2];
- TerrainBase3 = terrainImages[3];
- TerrainDetail0 = terrainImages[4];
- TerrainDetail1 = terrainImages[5];
- TerrainDetail2 = terrainImages[6];
- TerrainDetail3 = terrainImages[7];
+ TerrainBase0 = terrainImages[0];
+ TerrainBase1 = terrainImages[1];
+ TerrainBase2 = terrainImages[2];
+ TerrainBase3 = terrainImages[3];
+ TerrainDetail0 = terrainImages[4];
+ TerrainDetail1 = terrainImages[5];
+ TerrainDetail2 = terrainImages[6];
+ TerrainDetail3 = terrainImages[7];
- IsEstateManager = isEstateManager;
- }
+ IsEstateManager = isEstateManager;
+ }
- public void ParcelSubdivide(float west, float south, float east, float north)
- {
- Client.Network.SendPacket(
- Packets.Parcel.ParcelDivide(Client.Protocol,Client.Avatar.ID,
- west,south,east,north));
- }
+ public void ParcelSubdivide(float west, float south, float east, float north)
+ {
+ Client.Network.SendPacket(
+ Packets.Parcel.ParcelDivide(Client.Protocol, Client.Avatar.ID,
+ west, south, east, north));
+ }
- public void ParcelJoin(float west, float south, float east, float north)
- {
- Client.Network.SendPacket(
- Packets.Parcel.ParcelJoin(Client.Protocol,Client.Avatar.ID,
- west,south,east,north));
- }
+ public void ParcelJoin(float west, float south, float east, float north)
+ {
+ Client.Network.SendPacket(
+ Packets.Parcel.ParcelJoin(Client.Protocol, Client.Avatar.ID,
+ west, south, east, north));
+ }
- public void RezObject(PrimObject prim, LLVector3 position, LLVector3 avatarPosition)
- {
- byte[] textureEntry = new byte[40];
- Array.Copy(prim.Texture.Data, textureEntry, 16);
- textureEntry[35] = 0xe0; // No clue
+ public void RezObject(PrimObject prim, LLVector3 position, LLVector3 avatarPosition)
+ {
+ byte[] textureEntry = new byte[40];
+ Array.Copy(prim.Texture.Data, textureEntry, 16);
+ textureEntry[35] = 0xe0; // No clue
- Packet objectAdd = libsecondlife.Packets.Object.ObjectAdd(Client.Protocol, Client.Network.AgentID,
- LLUUID.GenerateUUID(), avatarPosition,
- position, prim, textureEntry);
- Client.Network.SendPacket(objectAdd);
- }
+ Packet objectAdd = libsecondlife.Packets.Object.ObjectAdd(Client.Protocol, Client.Network.AgentID,
+ LLUUID.GenerateUUID(), avatarPosition,
+ position, prim, textureEntry);
+ Client.Network.SendPacket(objectAdd);
+ }
- public void FillParcels()
- {
- // Begins filling parcels
- ParcelDownloading = true;
+ public void FillParcels()
+ {
+ // Begins filling parcels
+ ParcelDownloading = true;
- // TODO: Replace Client.Network with Region.Simulator, or similar?
- Client.Network.SendPacket(libsecondlife.Packets.Parcel.ParcelPropertiesRequest(Client.Protocol,Client.Avatar.ID, -10000,
- 0.0f,0.0f,4.0f,4.0f, false));
- }
+ // TODO: Replace Client.Network with Region.Simulator, or similar?
+ Client.Network.SendPacket(libsecondlife.Packets.Parcel.ParcelPropertiesRequest(Client.Protocol, Client.Avatar.ID, -10000,
+ 0.0f, 0.0f, 4.0f, 4.0f, false));
+ }
- public void ResetParcelDownload()
- {
- Parcels = new System.Collections.Hashtable();
- ParcelMarked = new int[64,64];
- }
+ public void ResetParcelDownload()
+ {
+ Parcels = new System.Collections.Hashtable();
+ ParcelMarked = new int[64, 64];
+ }
- public void FilledParcels()
- {
- if(OnParcelCompletion != null)
- {
- OnParcelCompletion(this);
- }
- }
+ public void FilledParcels()
+ {
+ if (OnParcelCompletion != null)
+ {
+ OnParcelCompletion(this);
+ }
+ }
- public override int GetHashCode()
- {
- return ID.GetHashCode();
- }
+ public override int GetHashCode()
+ {
+ return ID.GetHashCode();
+ }
- public override bool Equals(object o)
- {
- if (!(o is Region))
- {
- return false;
- }
+ public override bool Equals(object o)
+ {
+ if (!(o is Region))
+ {
+ return false;
+ }
- Region region = (Region)o;
+ Region region = (Region)o;
- return (region.ID == ID);
- }
+ return (region.ID == ID);
+ }
- public static bool operator==(Region lhs, Region rhs)
- {
- try
- {
- return (lhs.ID == rhs.ID);
- }
- catch (NullReferenceException)
- {
- byte test;
- bool lhsnull = false;
- bool rhsnull = false;
+ public static bool operator ==(Region lhs, Region rhs)
+ {
+ try
+ {
+ return (lhs.ID == rhs.ID);
+ }
+ catch (NullReferenceException)
+ {
+ byte test;
+ bool lhsnull = false;
+ bool rhsnull = false;
- try
- {
- test = lhs.ID.Data[0];
- }
- catch (NullReferenceException)
- {
- lhsnull = true;
- }
+ try
+ {
+ test = lhs.ID.Data[0];
+ }
+ catch (NullReferenceException)
+ {
+ lhsnull = true;
+ }
- try
- {
- test = rhs.ID.Data[0];
- }
- catch (NullReferenceException)
- {
- rhsnull = true;
- }
+ try
+ {
+ test = rhs.ID.Data[0];
+ }
+ catch (NullReferenceException)
+ {
+ rhsnull = true;
+ }
- return (lhsnull == rhsnull);
- }
- }
+ return (lhsnull == rhsnull);
+ }
+ }
- public static bool operator!=(Region lhs, Region rhs)
- {
- return !(lhs == rhs);
- }
- }
+ public static bool operator !=(Region lhs, Region rhs)
+ {
+ return !(lhs == rhs);
+ }
+ }
}
diff --git a/libsecondlife-cs/SecondLife.cs b/libsecondlife-cs/SecondLife.cs
index aa966d92..d312f450 100644
--- a/libsecondlife-cs/SecondLife.cs
+++ b/libsecondlife-cs/SecondLife.cs
@@ -30,344 +30,358 @@ using System.Threading;
namespace libsecondlife
{
- ///
- /// Main class to expose Second Life functionality to clients. All of the
- /// classes are accessible through this class.
- ///
- public class SecondLife
- {
- public ProtocolManager Protocol;
- public NetworkManager Network;
- public ParcelManager Parcels;
- public MainAvatar Avatar;
- public Hashtable Avatars;
- public Mutex AvatarsMutex;
- public Inventory Inventory;
- public Region CurrentRegion;
- public GridManager Grid;
+ ///
+ /// Main class to expose Second Life functionality to clients. All of the
+ /// classes are accessible through this class.
+ ///
+ public class SecondLife
+ {
+ public ProtocolManager Protocol;
+ public NetworkManager Network;
+ public ParcelManager Parcels;
+ public MainAvatar Avatar;
+ public Hashtable Avatars;
+ public Mutex AvatarsMutex;
+ public Inventory Inventory;
+ public Region CurrentRegion;
+ public GridManager Grid;
+ public bool Debug;
- public SecondLife(string keywordFile, string mapFile)
- {
- Protocol = new ProtocolManager(keywordFile, mapFile);
- Network = new NetworkManager(this, Protocol);
- Parcels = new ParcelManager(this);
- Avatar = new MainAvatar(this);
- Avatars = new Hashtable();
- AvatarsMutex = new Mutex(false, "AvatarsMutex");
- Inventory = new Inventory(this);
- Grid = new GridManager(this);
- CurrentRegion = null;
- }
+ public SecondLife(string keywordFile, string mapFile)
+ {
+ Protocol = new ProtocolManager(keywordFile, mapFile, this);
+ Network = new NetworkManager(this, Protocol);
+ Parcels = new ParcelManager(this);
+ Avatar = new MainAvatar(this);
+ Avatars = new Hashtable();
+ AvatarsMutex = new Mutex(false, "AvatarsMutex");
+ Inventory = new Inventory(this);
+ Grid = new GridManager(this);
+ CurrentRegion = null;
+ Debug = true;
- public override string ToString()
- {
- return Avatar.FirstName + " " + Avatar.LastName;
- }
+ Network.RegisterCallback("UUIDNameReply", new PacketCallback(GetAgentNameHandler));
+ }
- public void Tick()
- {
- System.Threading.Thread.Sleep(0);
- }
+ public override string ToString()
+ {
+ return Avatar.FirstName + " " + Avatar.LastName;
+ }
- public void AddAvatar(LLUUID AgentID)
- {
- // Quick sanity check
- if(Avatars.ContainsKey(AgentID))
- {
- return;
- }
+ ///
+ /// A simple sleep function that will allow pending threads to run
+ ///
+ public void Tick()
+ {
+ System.Threading.Thread.Sleep(0);
+ }
- GetAgentDetails(AgentID);
+ ///
+ /// Send a log message to the debugging output system
+ ///
+ /// The log message
+ /// From the LogLevel enum, either Info, Warning, or Error
+ public void Log(string message, Helpers.LogLevel level)
+ {
+ if (Debug)
+ {
+ Console.WriteLine(level.ToString() + ": " + message);
+ }
+ }
- AvatarsMutex.WaitOne();
- Avatars[AgentID] = new Avatar();
- AvatarsMutex.ReleaseMutex();
+ ///
+ ///
+ ///
+ ///
+ public void AddAvatar(LLUUID AgentID)
+ {
+ // Quick sanity check
+ if (Avatars.ContainsKey(AgentID))
+ {
+ return;
+ }
- return;
- }
+ GetAgentDetails(AgentID);
- private void GetAgentDetails(LLUUID AgentID)
- {
- PacketCallback callback = new PacketCallback(GetAgentNameHandler);
- Network.RegisterCallback("UUIDNameReply", callback);
+ AvatarsMutex.WaitOne();
+ Avatars[AgentID] = new Avatar();
+ AvatarsMutex.ReleaseMutex();
- Packet packet = Packets.Communication.UUIDNameRequest(Protocol, AgentID);
- Network.SendPacket(packet);
- }
+ return;
+ }
- private void GetAgentNameHandler(Packet packet, Simulator simulator)
- {
- if (packet.Layout.Name == "UUIDNameReply")
- {
- LLUUID ID = new LLUUID();
- string Firstname = "";
- string Lastname = "";
+ ///
+ ///
+ ///
+ ///
+ private void GetAgentDetails(LLUUID AgentID)
+ {
+ Packet packet = Packets.Communication.UUIDNameRequest(Protocol, AgentID);
+ Network.SendPacket(packet);
- ArrayList blocks;
+ // TODO: Shouldn't this function block?
+ }
- blocks = packet.Blocks();
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void GetAgentNameHandler(Packet packet, Simulator simulator)
+ {
+ if (packet.Layout.Name == "UUIDNameReply")
+ {
+ LLUUID ID = new LLUUID();
+ string Firstname = "";
+ string Lastname = "";
- foreach (Block block in blocks)
- {
- foreach (Field field in block.Fields)
- {
- if(field.Layout.Name == "ID")
- {
- ID = (LLUUID)field.Data;
- }
- else if(field.Layout.Name == "FirstName")
- {
- Firstname = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- }
- else if(field.Layout.Name == "LastName")
- {
- Lastname = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
- }
- }
- }
- AvatarsMutex.WaitOne();
- ((Avatar)Avatars[ID]).Name = Firstname + " " + Lastname;
- AvatarsMutex.ReleaseMutex();
- }
- }
- }
+ ArrayList blocks;
- ///
- /// Static helper functions and global variables
- ///
- public class Helpers
- {
- public readonly static string VERSION = "libsecondlife-cs 0.0.5";
+ blocks = packet.Blocks();
- public const byte MSG_APPENDED_ACKS = 0x10;
- public const byte MSG_RESENT = 0x20;
- public const byte MSG_RELIABLE = 0x40;
- public const byte MSG_ZEROCODED = 0x80;
- public const ushort MSG_FREQ_HIGH = 0x0000;
- public const ushort MSG_FREQ_MED = 0xFF00;
- public const ushort MSG_FREQ_LOW = 0xFFFF;
+ foreach (Block block in blocks)
+ {
+ foreach (Field field in block.Fields)
+ {
+ if (field.Layout.Name == "ID")
+ {
+ ID = (LLUUID)field.Data;
+ }
+ else if (field.Layout.Name == "FirstName")
+ {
+ Firstname = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ }
+ else if (field.Layout.Name == "LastName")
+ {
+ Lastname = System.Text.Encoding.UTF8.GetString((byte[])field.Data).Replace("\0", "");
+ }
+ }
+ }
+ AvatarsMutex.WaitOne();
+ ((Avatar)Avatars[ID]).Name = Firstname + " " + Lastname;
+ AvatarsMutex.ReleaseMutex();
+ }
+ }
+ }
- public enum LogLevel
- {
- Info,
- Warning,
- Error
- };
+ ///
+ /// Static helper functions and global variables
+ ///
+ public class Helpers
+ {
+ public readonly static string VERSION = "libsecondlife-cs 0.0.6";
- ///
- /// Send a log message to the debugging output system
- ///
- /// The log message
- /// From the LogLevel enum, either Info, Warning, or Error
- public static void Log(string message, LogLevel level)
- {
- Console.WriteLine(level.ToString() + ": " + message);
- }
+ public const byte MSG_APPENDED_ACKS = 0x10;
+ public const byte MSG_RESENT = 0x20;
+ public const byte MSG_RELIABLE = 0x40;
+ public const byte MSG_ZEROCODED = 0x80;
+ public const ushort MSG_FREQ_HIGH = 0x0000;
+ public const ushort MSG_FREQ_MED = 0xFF00;
+ public const ushort MSG_FREQ_LOW = 0xFFFF;
- ///
- /// Converting a variable length field (byte array) to a string
- ///
- /// The Data member of the Field class you are converting
- public static string FieldToString(object data)
- {
- byte[] byteArray;
+ public enum LogLevel
+ {
+ Info,
+ Warning,
+ Error
+ };
- try
- {
- byteArray = (byte[])data;
- }
- catch (Exception e)
- {
- Helpers.Log(e.ToString(), Helpers.LogLevel.Warning);
- return "";
- }
+ ///
+ /// Converting a variable length field (byte array) to a string
+ ///
+ /// The Data member of the Field class you are converting
+ public static string FieldToString(object data)
+ {
+ byte[] byteArray;
- return System.Text.Encoding.ASCII.GetString(byteArray).Replace("\0", "");
- }
-
- ///
- /// Takes a quantized value and its quantization range and returns a float
- /// representation of the continuous value. For example, a value of 32767
- /// and a range of -128.0 to 128.0 would return approx. -0.0019531548028
- ///
- /// The 16-bit quantized value
- /// The lower quantization range
- /// The upper quantization range
- ///
- public static float Dequantize(uint value, float lower, float upper)
- {
- decimal QV = (decimal)value;
- decimal range = (decimal)(upper - lower);
- decimal QF = (range) / 65535.0m;
- return (float)(QV * QF - (0.5m * range));
- }
-
- ///
- /// Decode a zerocoded byte array. Used to decompress packets marked
- /// with the zerocoded flag. Any time a zero is encountered, the
- /// next byte is a count of how many zeroes to expand. One zero is
- /// encoded with 0x00 0x01, two zeroes is 0x00 0x02, three zeroes is
- /// 0x00 0x03, etc. The first four bytes are copied directly to the
- /// output buffer.
- ///
- /// The byte array to decode
- /// The length of the byte array to decode
- /// The output byte array to decode to
- /// The length of the output buffer
- public static int ZeroDecode(byte[] src, int srclen, byte[] dest)
- {
- uint zerolen = 0;
+ try
+ {
+ byteArray = (byte[])data;
+ }
+ catch (Exception)
+ {
+ return "[object]";
+ }
- try
- {
- Array.Copy(src, 0, dest, 0, 4);
- zerolen += 4;
+ return System.Text.Encoding.ASCII.GetString(byteArray).Replace("\0", "");
+ }
- int bodylen;
- if ((src[0] & MSG_APPENDED_ACKS) == 0)
- {
- bodylen = srclen;
- }
- else
- {
- bodylen = srclen - src[srclen - 1] * 4 - 1;
- }
+ ///
+ /// Takes a quantized value and its quantization range and returns a float
+ /// representation of the continuous value. For example, a value of 32767
+ /// and a range of -128.0 to 128.0 would return approx. -0.0019531548028
+ ///
+ /// The 16-bit quantized value
+ /// The lower quantization range
+ /// The upper quantization range
+ ///
+ public static float Dequantize(uint value, float lower, float upper)
+ {
+ decimal QV = (decimal)value;
+ decimal range = (decimal)(upper - lower);
+ decimal QF = (range) / 65535.0m;
+ return (float)(QV * QF - (0.5m * range));
+ }
- uint i;
- for (i = zerolen; i < bodylen; i++)
- {
- if (src[i] == 0x00)
- {
- for (byte j = 0; j < src[i + 1]; j++)
- {
- dest[zerolen++] = 0x00;
- }
+ ///
+ /// Decode a zerocoded byte array. Used to decompress packets marked
+ /// with the zerocoded flag. Any time a zero is encountered, the
+ /// next byte is a count of how many zeroes to expand. One zero is
+ /// encoded with 0x00 0x01, two zeroes is 0x00 0x02, three zeroes is
+ /// 0x00 0x03, etc. The first four bytes are copied directly to the
+ /// output buffer.
+ ///
+ /// The byte array to decode
+ /// The length of the byte array to decode
+ /// The output byte array to decode to
+ /// The length of the output buffer
+ public static int ZeroDecode(byte[] src, int srclen, byte[] dest)
+ {
+ uint zerolen = 0;
- i++;
- }
- else
- {
- dest[zerolen++] = src[i];
- }
- }
+ Array.Copy(src, 0, dest, 0, 4);
+ zerolen += 4;
- // HACK: Fix truncated zerocoded messages
- for (uint j = zerolen; j < zerolen + 16; j++)
- {
- dest[j] = 0;
- }
- zerolen += 16;
+ int bodylen;
+ if ((src[0] & MSG_APPENDED_ACKS) == 0)
+ {
+ bodylen = srclen;
+ }
+ else
+ {
+ bodylen = srclen - src[srclen - 1] * 4 - 1;
+ }
- // copy appended ACKs
- for (; i < srclen; i++)
- {
- dest[zerolen++] = src[i];
- }
- }
- catch (Exception e)
- {
- Helpers.Log(e.ToString(), Helpers.LogLevel.Error);
- }
+ uint i;
+ for (i = zerolen; i < bodylen; i++)
+ {
+ if (src[i] == 0x00)
+ {
+ for (byte j = 0; j < src[i + 1]; j++)
+ {
+ dest[zerolen++] = 0x00;
+ }
- return (int)zerolen;
- }
-
- ///
- /// Decode enough of a byte array to get the packet ID. Data before and
- /// after the packet ID is undefined.
- ///
- /// The byte array to decode
- /// The output byte array to encode to
- public static void ZeroDecodeCommand(byte[] src, byte[] dest)
- {
- for (int srcPos = 4, destPos = 4; destPos < 8; ++srcPos)
- {
- if (src[srcPos] == 0x00)
- {
- for (byte j = 0; j < src[srcPos + 1]; ++j)
- {
- dest[destPos++] = 0x00;
- }
+ i++;
+ }
+ else
+ {
+ dest[zerolen++] = src[i];
+ }
+ }
- ++srcPos;
- }
- else
- {
- dest[destPos++] = src[srcPos];
- }
- }
- }
+ // HACK: Fix truncated zerocoded messages
+ for (uint j = zerolen; j < zerolen + 16; j++)
+ {
+ dest[j] = 0;
+ }
+ zerolen += 16;
- ///
- /// Encode a byte array with zerocoding. Used to compress packets marked
- /// with the zerocoded flag. Any zeroes in the array are compressed down
- /// to a single zero byte followed by a count of how many zeroes to expand
- /// out. A single zero becomes 0x00 0x01, two zeroes becomes 0x00 0x02,
- /// three zeroes becomes 0x00 0x03, etc. The first four bytes are copied
- /// directly to the output buffer.
- ///
- /// The byte array to encode
- /// The length of the byte array to encode
- /// The output byte array to encode to
- /// The length of the output buffer
- public static int ZeroEncode(byte[] src, int srclen, byte[] dest)
- {
- uint zerolen = 0;
- byte zerocount = 0;
+ // copy appended ACKs
+ for (; i < srclen; i++)
+ {
+ dest[zerolen++] = src[i];
+ }
- Array.Copy(src, 0, dest, 0, 4);
- zerolen += 4;
+ return (int)zerolen;
+ }
- int bodylen;
- if ((src[0] & MSG_APPENDED_ACKS) == 0)
- {
- bodylen = srclen;
- }
- else
- {
- bodylen = srclen - src[srclen - 1] * 4 - 1;
- }
+ ///
+ /// Decode enough of a byte array to get the packet ID. Data before and
+ /// after the packet ID is undefined.
+ ///
+ /// The byte array to decode
+ /// The output byte array to encode to
+ public static void ZeroDecodeCommand(byte[] src, byte[] dest)
+ {
+ for (int srcPos = 4, destPos = 4; destPos < 8; ++srcPos)
+ {
+ if (src[srcPos] == 0x00)
+ {
+ for (byte j = 0; j < src[srcPos + 1]; ++j)
+ {
+ dest[destPos++] = 0x00;
+ }
- uint i;
- for (i = zerolen; i < bodylen; i++)
- {
- if (src[i] == 0x00)
- {
- zerocount++;
+ ++srcPos;
+ }
+ else
+ {
+ dest[destPos++] = src[srcPos];
+ }
+ }
+ }
- if (zerocount == 0)
- {
- dest[zerolen++] = 0x00;
- dest[zerolen++] = 0xff;
- zerocount++;
- }
- }
- else
- {
- if (zerocount != 0)
- {
- dest[zerolen++] = 0x00;
- dest[zerolen++] = (byte)zerocount;
- zerocount = 0;
- }
+ ///
+ /// Encode a byte array with zerocoding. Used to compress packets marked
+ /// with the zerocoded flag. Any zeroes in the array are compressed down
+ /// to a single zero byte followed by a count of how many zeroes to expand
+ /// out. A single zero becomes 0x00 0x01, two zeroes becomes 0x00 0x02,
+ /// three zeroes becomes 0x00 0x03, etc. The first four bytes are copied
+ /// directly to the output buffer.
+ ///
+ /// The byte array to encode
+ /// The length of the byte array to encode
+ /// The output byte array to encode to
+ /// The length of the output buffer
+ public static int ZeroEncode(byte[] src, int srclen, byte[] dest)
+ {
+ uint zerolen = 0;
+ byte zerocount = 0;
- dest[zerolen++] = src[i];
- }
- }
+ Array.Copy(src, 0, dest, 0, 4);
+ zerolen += 4;
- if (zerocount != 0)
- {
- dest[zerolen++] = 0x00;
- dest[zerolen++] = (byte)zerocount;
- }
+ int bodylen;
+ if ((src[0] & MSG_APPENDED_ACKS) == 0)
+ {
+ bodylen = srclen;
+ }
+ else
+ {
+ bodylen = srclen - src[srclen - 1] * 4 - 1;
+ }
- // copy appended ACKs
- for (; i < srclen; i++)
- {
- dest[zerolen++] = src[i];
- }
+ uint i;
+ for (i = zerolen; i < bodylen; i++)
+ {
+ if (src[i] == 0x00)
+ {
+ zerocount++;
- return (int)zerolen;
- }
- }
+ if (zerocount == 0)
+ {
+ dest[zerolen++] = 0x00;
+ dest[zerolen++] = 0xff;
+ zerocount++;
+ }
+ }
+ else
+ {
+ if (zerocount != 0)
+ {
+ dest[zerolen++] = 0x00;
+ dest[zerolen++] = (byte)zerocount;
+ zerocount = 0;
+ }
+
+ dest[zerolen++] = src[i];
+ }
+ }
+
+ if (zerocount != 0)
+ {
+ dest[zerolen++] = 0x00;
+ dest[zerolen++] = (byte)zerocount;
+ }
+
+ // copy appended ACKs
+ for (; i < srclen; i++)
+ {
+ dest[zerolen++] = src[i];
+ }
+
+ return (int)zerolen;
+ }
+ }
}