diff --git a/libsecondlife-cs/Avatar.cs b/libsecondlife-cs/Avatar.cs
index 4ce22f7f..d93890c6 100644
--- a/libsecondlife-cs/Avatar.cs
+++ b/libsecondlife-cs/Avatar.cs
@@ -129,8 +129,8 @@ namespace libsecondlife
/// Avatar interests including spoken languages, skills, and "want to"
/// choices
public Interests ProfileInterests = new Interests();
- /// Region the avatar is in
- public Region CurrentRegion = null;
+ /// Simulator the avatar is in
+ public Simulator CurrentSim = null;
#endregion Public Members
diff --git a/libsecondlife-cs/MainAvatar.cs b/libsecondlife-cs/MainAvatar.cs
index 6e3265da..05379d6f 100644
--- a/libsecondlife-cs/MainAvatar.cs
+++ b/libsecondlife-cs/MainAvatar.cs
@@ -1032,7 +1032,7 @@ namespace libsecondlife
public void AutoPilotLocal(int localX, int localY, float z)
{
uint x, y;
- Helpers.LongToUInts(Client.Network.CurrentSim.Region.Handle, out x, out y);
+ Helpers.LongToUInts(Client.Network.CurrentSim.Handle, out x, out y);
AutoPilot((ulong)(x + localX), (ulong)(y + localY), z);
}
@@ -1448,7 +1448,7 @@ namespace libsecondlife
this.Position = movement.Data.Position;
this.LookAt = movement.Data.LookAt;
- simulator.Region.Handle = movement.Data.RegionHandle;
+ simulator.Handle = movement.Data.RegionHandle;
}
///
diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs
index 0f655ccc..abe2cc07 100644
--- a/libsecondlife-cs/NetworkManager.cs
+++ b/libsecondlife-cs/NetworkManager.cs
@@ -62,8 +62,8 @@ namespace libsecondlife
/// Reference to the SecondLife client this system is connected to
public SecondLife Client;
- /// Reference to the region this system is connected to
- public Region Region;
+ /// Reference to the simulator this system is connected to
+ public Simulator Simulator;
internal bool Dead = false;
@@ -76,13 +76,14 @@ namespace libsecondlife
/// Default constructor
///
///
- ///
///
///
- public Caps(SecondLife client, Region region, string seedcaps, List callbacks)
+ public Caps(SecondLife client, Simulator simulator, string seedcaps, List callbacks)
{
- Client = client; Region = region;
- this.Seedcaps = seedcaps; Callbacks = callbacks;
+ Client = client;
+ Simulator = simulator;
+ Seedcaps = seedcaps;
+ Callbacks = callbacks;
ArrayList req = new ArrayList();
req.Add("MapLayer");
req.Add("MapLayerGod");
@@ -107,7 +108,7 @@ namespace libsecondlife
}
else
{
- Client.Log("Disabling caps for " + Region.ToString(), Helpers.LogLevel.Info);
+ Client.Log("Disabling caps for " + Simulator.ToString(), Helpers.LogLevel.Info);
Dead = true;
}
}
@@ -156,7 +157,7 @@ namespace libsecondlife
}
else
{
- Client.Log("Disabling caps for " + Region.ToString(), Helpers.LogLevel.Info);
+ Client.Log("Disabling caps for " + Simulator.ToString(), Helpers.LogLevel.Info);
Dead = true;
}
}
@@ -211,566 +212,6 @@ namespace libsecondlife
}
}
- ///
- /// Simulator is a wrapper for a network connection to a simulator and the
- /// Region class representing the block of land in the metaverse
- ///
- public class Simulator
- {
- /// A public reference to the client that this Simulator object
- /// is attached to
- public SecondLife Client;
- /// The Region class that this Simulator wraps
- public Region Region;
- /// Current time dilation of this simulator
- public float Dilation = 0.0f;
-
- ///
- /// The ID number associated with this particular connection to the
- /// simulator, used to emulate TCP connections. This is used
- /// internally for packets that have a CircuitCode field
- ///
- public uint CircuitCode
- {
- get { return circuitCode; }
- set { circuitCode = value; }
- }
- ///
- /// The IP address and port of the server
- ///
- public IPEndPoint IPEndPoint
- {
- get { return ipEndPoint; }
- }
- ///
- /// A boolean representing whether there is a working connection to the
- /// simulator or not
- ///
- public bool Connected
- {
- get { return connected; }
- }
-
- /// Used internally to track sim disconnections
- internal bool DisconnectCandidate = false;
-
- private NetworkManager Network;
- private Dictionary> Callbacks;
- private uint Sequence = 0;
- private object SequenceLock = new object();
- private byte[] RecvBuffer = new byte[4096];
- private byte[] ZeroBuffer = new byte[8192];
- private byte[] ZeroOutBuffer = new byte[4096];
- private Socket Connection = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
- private AsyncCallback ReceivedData;
- // Packets we sent out that need ACKs from the simulator
- private Dictionary NeedAck = new Dictionary();
- // Sequence numbers of packets we've received from the simulator
- private Queue Inbox;
- // ACKs that are queued up to be sent to the simulator
- private Dictionary PendingAcks = new Dictionary();
- private bool connected = false;
- private uint circuitCode;
- private IPEndPoint ipEndPoint;
- private EndPoint endPoint;
- private System.Timers.Timer AckTimer;
- private ManualResetEvent ConnectedEvent = new ManualResetEvent(false);
-
-
- ///
- /// Constructor for Simulator
- ///
- ///
- ///
- ///
- ///
- ///
- public Simulator(SecondLife client, Dictionary> callbacks,
- uint circuit, IPAddress ip, int port)
- {
- Client = client;
- Network = client.Network;
- Callbacks = callbacks;
- Region = new Region(client);
- circuitCode = circuit;
- Inbox = new Queue(Client.Settings.INBOX_SIZE);
- AckTimer = new System.Timers.Timer(Client.Settings.NETWORK_TICK_LENGTH);
- AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
-
- // Initialize the callback for receiving a new packet
- ReceivedData = new AsyncCallback(OnReceivedData);
-
- Client.Log("Connecting to " + ip.ToString() + ":" + port, Helpers.LogLevel.Info);
-
- try
- {
- // Create an endpoint that we will be communicating with (need it in two
- // types due to .NET weirdness)
- ipEndPoint = new IPEndPoint(ip, port);
- endPoint = (EndPoint)ipEndPoint;
-
- // Associate this simulator's socket with the given ip/port and start listening
- Connection.Connect(endPoint);
- Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null);
-
- // Send the UseCircuitCode packet to initiate the connection
- UseCircuitCodePacket use = new UseCircuitCodePacket();
- use.CircuitCode.Code = circuitCode;
- use.CircuitCode.ID = Network.AgentID;
- use.CircuitCode.SessionID = Network.SessionID;
-
- // Start the ACK timer
- AckTimer.Start();
-
- // Send the initial packet out
- SendPacket(use, true);
-
- ConnectedEvent.Reset();
- ConnectedEvent.WaitOne(Client.Settings.SIMULATOR_TIMEOUT, false);
- }
- catch (Exception e)
- {
- Client.Log(e.ToString(), Helpers.LogLevel.Error);
- }
- }
-
- ///
- /// Disconnect a Simulator
- ///
- public void Disconnect()
- {
- if (connected)
- {
- connected = false;
- AckTimer.Stop();
-
- // Send the CloseCircuit notice
- CloseCircuitPacket close = new CloseCircuitPacket();
-
- if (Connection.Connected)
- {
- try
- {
- Connection.Send(close.ToBytes());
- }
- catch (SocketException)
- {
- // There's a high probability of this failing if the network is
- // disconnecting, so don't even bother logging the error
- }
- }
-
- try
- {
- // Shut the socket communication down
- Connection.Shutdown(SocketShutdown.Both);
- }
- catch (SocketException)
- {
- }
- }
- }
-
- ///
- /// Sends a packet
- ///
- /// Packet to be sent
- /// Increment sequence number?
- public void SendPacket(Packet packet, bool incrementSequence)
- {
- byte[] buffer;
- int bytes;
-
- if (!connected && packet.Type != PacketType.UseCircuitCode)
- {
- Client.Log("Trying to send a " + packet.Type.ToString() + " packet when the socket is closed",
- Helpers.LogLevel.Info);
-
- return;
- }
-
- if (packet.Header.AckList.Length > 0)
- {
- // Scrub any appended ACKs since all of the ACK handling is done here
- packet.Header.AckList = new uint[0];
- }
- packet.Header.AppendedAcks = false;
-
- // Keep track of when this packet was sent out
- packet.TickCount = Environment.TickCount;
-
- if (incrementSequence)
- {
- // Set the sequence number
- lock (SequenceLock)
- {
- if (Sequence > Client.Settings.MAX_SEQUENCE)
- Sequence = 1;
- else
- Sequence++;
- packet.Header.Sequence = Sequence;
- }
-
- if (packet.Header.Reliable)
- {
- lock (NeedAck)
- {
- if (!NeedAck.ContainsKey(packet.Header.Sequence))
- {
- NeedAck.Add(packet.Header.Sequence, packet);
- }
- else
- {
- Client.Log("Attempted to add a duplicate sequence number (" +
- packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
- packet.Type.ToString(), Helpers.LogLevel.Warning);
- }
- }
-
- // Don't append ACKs to resent packets, in case that's what was causing the
- // delivery to fail
- if (!packet.Header.Resent)
- {
- // Append any ACKs that need to be sent out to this packet
- lock (PendingAcks)
- {
- if (PendingAcks.Count > 0 && PendingAcks.Count < Client.Settings.MAX_APPENDED_ACKS &&
- packet.Type != PacketType.PacketAck &&
- packet.Type != PacketType.LogoutRequest)
- {
- packet.Header.AckList = new uint[PendingAcks.Count];
-
- int i = 0;
-
- foreach (uint ack in PendingAcks.Values)
- {
- packet.Header.AckList[i] = ack;
- i++;
- }
-
- PendingAcks.Clear();
- packet.Header.AppendedAcks = true;
- }
- }
- }
- }
- }
-
- // Serialize the packet
- buffer = packet.ToBytes();
- bytes = buffer.Length;
-
- try
- {
- // Zerocode if needed
- if (packet.Header.Zerocoded)
- {
- lock (ZeroOutBuffer)
- {
- bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer);
- Connection.Send(ZeroOutBuffer, bytes, SocketFlags.None);
- }
- }
- else
- {
- Connection.Send(buffer, bytes, SocketFlags.None);
- }
- }
- catch (SocketException)
- {
- Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket",
- Helpers.LogLevel.Warning);
-
- Disconnect();
- }
- }
-
- ///
- /// Send a raw byte array payload as a packet
- ///
- /// The packet payload
- /// Whether the second, third, and fourth bytes
- /// should be modified to the current stream sequence number
- public void SendPacket(byte[] payload, bool setSequence)
- {
- if (connected)
- {
- try
- {
- if (setSequence && payload.Length > 3)
- {
- lock (SequenceLock)
- {
- payload[1] = (byte)(Sequence >> 16);
- payload[2] = (byte)(Sequence >> 8);
- payload[3] = (byte)(Sequence % 256);
- Sequence++;
- }
- }
-
- Connection.Send(payload, payload.Length, SocketFlags.None);
- }
- catch (SocketException e)
- {
- Client.Log(e.ToString(), Helpers.LogLevel.Error);
- }
- }
- else
- {
- Client.Log("Attempted to send a " + payload.Length + " byte payload when " +
- "we are disconnected", Helpers.LogLevel.Warning);
- }
- }
-
- ///
- /// Returns Simulator Name as a String
- ///
- ///
- public override string ToString()
- {
- return Region.Name + " (" + ipEndPoint.ToString() + ")";
- }
-
- ///
- /// Sends out pending acknowledgements
- ///
- private void SendAcks()
- {
- lock (PendingAcks)
- {
- if (connected && PendingAcks.Count > 0)
- {
- if (PendingAcks.Count > 250)
- {
- // FIXME: Handle the odd case where we have too many pending ACKs queued up
- Client.Log("Too many ACKs queued up!", Helpers.LogLevel.Error);
- return;
- }
-
- int i = 0;
- PacketAckPacket acks = new PacketAckPacket();
- acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
-
- foreach (uint ack in PendingAcks.Values)
- {
- acks.Packets[i] = new PacketAckPacket.PacketsBlock();
- acks.Packets[i].ID = ack;
- i++;
- }
-
- acks.Header.Reliable = false;
- SendPacket(acks, true);
-
- PendingAcks.Clear();
- }
- }
- }
- ///
- /// Resend unacknowledged packets
- ///
- private void ResendUnacked()
- {
- if (connected)
- {
- int now = Environment.TickCount;
-
- lock (NeedAck)
- {
- foreach (Packet packet in NeedAck.Values)
- {
- if (now - packet.TickCount > Client.Settings.RESEND_TIMEOUT)
- {
- Client.Log("Resending " + packet.Type.ToString() + " packet (" + packet.Header.Sequence +
- "), " + (now - packet.TickCount) + "ms have passed", Helpers.LogLevel.Info);
-
- packet.Header.Resent = true;
- SendPacket(packet, false);
- }
- }
- }
- }
- }
- ///
- /// Callback handler for incomming data
- ///
- ///
- private void OnReceivedData(IAsyncResult result)
- {
- Packet packet = null;
- int numBytes;
-
- // If we're receiving data the sim connection is open
- connected = true;
- ConnectedEvent.Set();
-
- // Update the disconnect flag so this sim doesn't time out
- DisconnectCandidate = false;
-
- lock (RecvBuffer)
- {
- // Retrieve the incoming packet
- try
- {
- numBytes = Connection.EndReceiveFrom(result, ref endPoint);
-
- int packetEnd = numBytes - 1;
- packet = Packet.BuildPacket(RecvBuffer, ref packetEnd, ZeroBuffer);
-
- Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null);
- }
- catch (SocketException)
- {
- Client.Log(endPoint.ToString() + " socket is closed, shutting down " + this.Region.Name,
- Helpers.LogLevel.Info);
-
- connected = false;
- Network.DisconnectSim(this);
- return;
- }
- }
-
- // Fail-safe check
- if (packet == null)
- {
- Client.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning);
- return;
- }
-
- // Track the sequence number for this packet if it's marked as reliable
- if (packet.Header.Reliable)
- {
- if (PendingAcks.Count > Client.Settings.MAX_PENDING_ACKS)
- {
- SendAcks();
- }
-
- // Check if we already received this packet
- if (Inbox.Contains(packet.Header.Sequence))
- {
- Client.Log("Received a duplicate " + packet.Type.ToString() + ", sequence=" +
- packet.Header.Sequence + ", resent=" + ((packet.Header.Resent) ? "Yes" : "No") +
- ", Inbox.Count=" + Inbox.Count + ", NeedAck.Count=" + NeedAck.Count,
- Helpers.LogLevel.Info);
-
- // Send an ACK for this packet immediately
- //SendAck(packet.Header.Sequence);
-
- // TESTING: Try just queuing up ACKs for resent packets instead of immediately triggering an ACK
- lock (PendingAcks)
- {
- uint sequence = (uint)packet.Header.Sequence;
- if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
- }
-
- // Avoid firing a callback twice for the same packet
- return;
- }
- else
- {
- lock (PendingAcks)
- {
- uint sequence = (uint)packet.Header.Sequence;
- if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
- }
- }
- }
-
- // Add this packet to our inbox
- lock (Inbox)
- {
- while (Inbox.Count >= Client.Settings.INBOX_SIZE)
- {
- Inbox.Dequeue();
- Inbox.Dequeue();
- }
- Inbox.Enqueue(packet.Header.Sequence);
- }
-
- // Handle appended ACKs
- if (packet.Header.AppendedAcks)
- {
- lock (NeedAck)
- {
- foreach (uint ack in packet.Header.AckList)
- {
- NeedAck.Remove(ack);
- }
- }
- }
-
- // Handle PacketAck packets
- if (packet.Type == PacketType.PacketAck)
- {
- PacketAckPacket ackPacket = (PacketAckPacket)packet;
-
- lock (NeedAck)
- {
- foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
- {
- NeedAck.Remove(block.ID);
- }
- }
- }
-
-
- // Fire the registered packet events
- #region FireCallbacks
- if (Callbacks.ContainsKey(packet.Type))
- {
- List callbackArray = Callbacks[packet.Type];
-
- // Fire any registered callbacks
- foreach (NetworkManager.PacketCallback callback in callbackArray)
- {
- if (callback != null)
- {
- try
- {
- callback(packet, this);
- }
- catch (Exception e)
- {
- Client.Log("Caught an exception in a packet callback: " + e.ToString(),
- Helpers.LogLevel.Error);
- }
- }
- }
- }
-
- if (Callbacks.ContainsKey(PacketType.Default))
- {
- List callbackArray = Callbacks[PacketType.Default];
-
- // Fire any registered callbacks
- foreach (NetworkManager.PacketCallback callback in callbackArray)
- {
- if (callback != null)
- {
- try
- {
- callback(packet, this);
- }
- catch (Exception e)
- {
- Client.Log("Caught an exception in a packet callback: " + e.ToString(),
- Helpers.LogLevel.Error);
- }
- }
- }
- }
- #endregion FireCallbacks
- }
-
- private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
- {
- if (connected)
- {
- SendAcks();
- ResendUnacked();
- }
- }
- }
-
///
/// NetworkManager is responsible for managing the network layer of
/// libsecondlife. It tracks all the server connections, serializes
@@ -879,8 +320,10 @@ namespace libsecondlife
///
public bool Connected { get { return connected; } }
+ ///
+ internal Dictionary> Callbacks = new Dictionary>();
+
private SecondLife Client;
- private Dictionary> Callbacks = new Dictionary>();
private List Simulators = new List();
private System.Timers.Timer DisconnectTimer;
private System.Timers.Timer LogoutTimer;
@@ -985,7 +428,7 @@ namespace libsecondlife
/// Simulator to send the packet to
public void SendPacket(Packet packet, Simulator simulator)
{
- if (simulator != null && simulator.Connected)
+ if (simulator != null)
simulator.SendPacket(packet, true);
}
@@ -997,7 +440,7 @@ namespace libsecondlife
/// bytes of the payload to the current sequence number
public void SendPacket(byte[] payload, bool setSequence)
{
- if (connected && CurrentSim != null)
+ if (CurrentSim != null)
CurrentSim.SendPacket(payload, setSequence);
}
@@ -1010,7 +453,7 @@ namespace libsecondlife
/// bytes of the payload to the current sequence number
public void SendPacket(byte[] payload, Simulator simulator, bool setSequence)
{
- if (connected && simulator != null)
+ if (simulator != null)
simulator.SendPacket(payload, setSequence);
}
@@ -1150,6 +593,7 @@ namespace libsecondlife
/// Reference to the SecondLife class that called the event
public delegate void ConnectedCallback(object sender);
+
///
/// Event raised when the client was able to connected successfully.
///
@@ -1417,70 +861,26 @@ namespace libsecondlife
Client.Self.HomeLookAt = lookatVector;
// Get Inventory Root Folder
- Client.Log("Pulling root folder UUID from login data.", Helpers.LogLevel.Debug);
ArrayList alInventoryRoot = (ArrayList)LoginValues["inventory-root"];
Hashtable htInventoryRoot = (Hashtable)alInventoryRoot[0];
Client.Self.InventoryRootFolderUUID = new LLUUID((string)htInventoryRoot["folder_id"]);
-
// Connect to the sim given in the login reply
- Simulator simulator = new Simulator(Client, this.Callbacks, (uint)(int)LoginValues["circuit_code"],
- IPAddress.Parse((string)LoginValues["sim_ip"]), (int)LoginValues["sim_port"]);
- if (!simulator.Connected)
+ if (Connect(IPAddress.Parse((string)LoginValues["sim_ip"]), (ushort)(int)LoginValues["sim_port"],
+ (uint)(int)LoginValues["circuit_code"], true, (string)LoginValues["seed_capability"]) == null)
{
LoginError = "Unable to connect to the simulator";
return false;
}
- Simulator oldSim = CurrentSim;
- CurrentSim = simulator;
-
- // Simulator is successfully connected, add it to the list and set it as default
- Simulators.Add(simulator);
-
- // Mark that we are now officially connected to the grid
- connected = true;
-
- // Start a timer that checks if we've been disconnected
- DisconnectTimer.Start();
-
- if (LoginValues.ContainsKey("seed_capability") && (string)LoginValues["seed_capability"] != "")
- {
- CurrentCaps = new Caps(Client, simulator.Region, (string)LoginValues["seed_capability"], EventQueueCallbacks);
- }
-
- // Move our agent in to the sim to complete the connection
- Client.Self.CompleteAgentMovement(simulator);
-
// Send a couple packets that are useful right after login
SendInitialPackets();
// Fire an event for connecting to the grid
if (OnConnected != null)
{
- try
- {
- OnConnected(this.Client);
- }
- catch (Exception e)
- {
- Client.Log("Caught an exception in the OnConnected() callback: " + e.ToString(),
- Helpers.LogLevel.Error);
- }
- }
-
- // Fire an event that the current simulator has changed
- if (OnCurrentSimChanged != null)
- {
- try
- {
- OnCurrentSimChanged(oldSim);
- }
- catch (Exception e)
- {
- Client.Log("Caught an exception in OnCurrentSimChanged(): " + e.ToString(),
- Helpers.LogLevel.Error);
- }
+ try { OnConnected(this.Client); }
+ catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
}
return true;
@@ -1503,7 +903,7 @@ namespace libsecondlife
/// A Simulator object on success, otherwise null
public Simulator Connect(IPAddress ip, ushort port, uint circuitCode, bool setDefault, string seedcaps)
{
- Simulator simulator = new Simulator(Client, this.Callbacks, circuitCode, ip, (int)port);
+ Simulator simulator = new Simulator(Client, circuitCode, ip, (int)port, setDefault);
if (!simulator.Connected)
{
@@ -1511,10 +911,7 @@ namespace libsecondlife
return null;
}
- lock (Simulators)
- {
- Simulators.Add(simulator);
- }
+ lock (Simulators) Simulators.Add(simulator);
// Mark that we are connected to the grid (in case we weren't before)
connected = true;
@@ -1526,11 +923,18 @@ namespace libsecondlife
{
Simulator oldSim = CurrentSim;
CurrentSim = simulator;
+
if (CurrentCaps != null) CurrentCaps.Disconnect();
CurrentCaps = null;
- if (seedcaps != null && seedcaps != "")
- CurrentCaps = new Caps(Client, simulator.Region, seedcaps, EventQueueCallbacks);
- if (OnCurrentSimChanged != null && simulator != oldSim) OnCurrentSimChanged(oldSim);
+
+ if (seedcaps != null && seedcaps.Length > 0)
+ CurrentCaps = new Caps(Client, simulator, seedcaps, EventQueueCallbacks);
+
+ if (OnCurrentSimChanged != null && simulator != oldSim)
+ {
+ try { OnCurrentSimChanged(oldSim); }
+ catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
+ }
}
return simulator;
@@ -1617,10 +1021,7 @@ namespace libsecondlife
}
}
- lock (Simulators)
- {
- Simulators.Remove(sim);
- }
+ lock (Simulators) Simulators.Remove(sim);
}
else
{
@@ -1723,7 +1124,7 @@ namespace libsecondlife
// Request the economy data
SendPacket(new EconomyDataRequestPacket());
- // FIXME: A movement class should be handling this
+ // Send an AgentUpdate packet to truly move our avatar in to the sim
MainAvatar.AgentUpdateFlags controlFlags = MainAvatar.AgentUpdateFlags.AGENT_CONTROL_FINISH_ANIM;
LLVector3 position = new LLVector3(128, 128, 32);
LLVector3 forwardAxis = new LLVector3(0, 0.999999f, 0);
@@ -1758,7 +1159,7 @@ namespace libsecondlife
if (CurrentSim.DisconnectCandidate)
{
Client.Log("Network timeout for the current simulator (" +
- CurrentSim.Region.Name + "), logging out", Helpers.LogLevel.Warning);
+ CurrentSim.ToString() + "), logging out", Helpers.LogLevel.Warning);
DisconnectTimer.Stop();
connected = false;
@@ -1815,7 +1216,7 @@ namespace libsecondlife
{
// This sim hasn't received any network traffic since the
// timer last elapsed, consider it disconnected
- Client.Log("Network timeout for simulator " + sim.Region.Name +
+ Client.Log("Network timeout for simulator " + sim.ToString() +
", disconnecting", Helpers.LogLevel.Warning);
DisconnectSim(sim);
@@ -1868,11 +1269,43 @@ namespace libsecondlife
// TODO: We can use OldestUnacked to correct transmission errors
- SendPacket((Packet)ping, simulator);
+ SendPacket(ping, simulator);
}
private void RegionHandshakeHandler(Packet packet, Simulator simulator)
{
+ RegionHandshakePacket handshake = (RegionHandshakePacket)packet;
+
+ simulator.ID = handshake.RegionInfo.CacheID;
+
+ // TODO: What do we need these for? RegionFlags probably contains good stuff
+ //handshake.RegionInfo.BillableFactor;
+ //handshake.RegionInfo.RegionFlags;
+ //handshake.RegionInfo.SimAccess;
+
+ simulator.IsEstateManager = handshake.RegionInfo.IsEstateManager;
+ simulator.Name = Helpers.FieldToString(handshake.RegionInfo.SimName);
+ simulator.SimOwner = handshake.RegionInfo.SimOwner;
+ simulator.TerrainBase0 = handshake.RegionInfo.TerrainBase0;
+ simulator.TerrainBase1 = handshake.RegionInfo.TerrainBase1;
+ simulator.TerrainBase2 = handshake.RegionInfo.TerrainBase2;
+ simulator.TerrainBase3 = handshake.RegionInfo.TerrainBase3;
+ simulator.TerrainDetail0 = handshake.RegionInfo.TerrainDetail0;
+ simulator.TerrainDetail1 = handshake.RegionInfo.TerrainDetail1;
+ simulator.TerrainDetail2 = handshake.RegionInfo.TerrainDetail2;
+ simulator.TerrainDetail3 = handshake.RegionInfo.TerrainDetail3;
+ simulator.TerrainHeightRange00 = handshake.RegionInfo.TerrainHeightRange00;
+ simulator.TerrainHeightRange01 = handshake.RegionInfo.TerrainHeightRange01;
+ simulator.TerrainHeightRange10 = handshake.RegionInfo.TerrainHeightRange10;
+ simulator.TerrainHeightRange11 = handshake.RegionInfo.TerrainHeightRange11;
+ simulator.TerrainStartHeight00 = handshake.RegionInfo.TerrainStartHeight00;
+ simulator.TerrainStartHeight01 = handshake.RegionInfo.TerrainStartHeight01;
+ simulator.TerrainStartHeight10 = handshake.RegionInfo.TerrainStartHeight10;
+ simulator.TerrainStartHeight11 = handshake.RegionInfo.TerrainStartHeight11;
+ simulator.WaterHeight = handshake.RegionInfo.WaterHeight;
+
+ Client.Log("Received a region handshake for " + simulator.ToString(), Helpers.LogLevel.Info);
+
// Send a RegionHandshakeReply
RegionHandshakeReplyPacket reply = new RegionHandshakeReplyPacket();
reply.AgentData.AgentID = AgentID;
@@ -1880,37 +1313,9 @@ namespace libsecondlife
reply.RegionInfo.Flags = 0;
SendPacket(reply, simulator);
- RegionHandshakePacket handshake = (RegionHandshakePacket)packet;
-
- simulator.Region.ID = handshake.RegionInfo.CacheID;
-
- // TODO: What do we need these for? RegionFlags probably contains good stuff
- //handshake.RegionInfo.BillableFactor;
- //handshake.RegionInfo.RegionFlags;
- //handshake.RegionInfo.SimAccess;
-
- simulator.Region.IsEstateManager = handshake.RegionInfo.IsEstateManager;
- simulator.Region.Name = Helpers.FieldToString(handshake.RegionInfo.SimName);
- simulator.Region.SimOwner = handshake.RegionInfo.SimOwner;
- simulator.Region.TerrainBase0 = handshake.RegionInfo.TerrainBase0;
- simulator.Region.TerrainBase1 = handshake.RegionInfo.TerrainBase1;
- simulator.Region.TerrainBase2 = handshake.RegionInfo.TerrainBase2;
- simulator.Region.TerrainBase3 = handshake.RegionInfo.TerrainBase3;
- simulator.Region.TerrainDetail0 = handshake.RegionInfo.TerrainDetail0;
- simulator.Region.TerrainDetail1 = handshake.RegionInfo.TerrainDetail1;
- simulator.Region.TerrainDetail2 = handshake.RegionInfo.TerrainDetail2;
- simulator.Region.TerrainDetail3 = handshake.RegionInfo.TerrainDetail3;
- simulator.Region.TerrainHeightRange00 = handshake.RegionInfo.TerrainHeightRange00;
- simulator.Region.TerrainHeightRange01 = handshake.RegionInfo.TerrainHeightRange01;
- simulator.Region.TerrainHeightRange10 = handshake.RegionInfo.TerrainHeightRange10;
- simulator.Region.TerrainHeightRange11 = handshake.RegionInfo.TerrainHeightRange11;
- simulator.Region.TerrainStartHeight00 = handshake.RegionInfo.TerrainStartHeight00;
- simulator.Region.TerrainStartHeight01 = handshake.RegionInfo.TerrainStartHeight01;
- simulator.Region.TerrainStartHeight10 = handshake.RegionInfo.TerrainStartHeight10;
- simulator.Region.TerrainStartHeight11 = handshake.RegionInfo.TerrainStartHeight11;
- simulator.Region.WaterHeight = handshake.RegionInfo.WaterHeight;
-
- Client.Log("Received a region handshake for " + simulator.Region.Name, Helpers.LogLevel.Info);
+ // We're officially connected to this sim
+ simulator.connected = true;
+ simulator.ConnectedEvent.Set();
}
private void ParcelOverlayHandler(Packet packet, Simulator simulator)
@@ -1919,11 +1324,11 @@ namespace libsecondlife
if (overlay.ParcelData.SequenceID >= 0 && overlay.ParcelData.SequenceID <= 3)
{
- Array.Copy(overlay.ParcelData.Data, 0, simulator.Region.ParcelOverlay,
+ Array.Copy(overlay.ParcelData.Data, 0, simulator.ParcelOverlay,
overlay.ParcelData.SequenceID * 1024, 1024);
- simulator.Region.ParcelOverlaysReceived++;
+ simulator.ParcelOverlaysReceived++;
- if (simulator.Region.ParcelOverlaysReceived > 3)
+ if (simulator.ParcelOverlaysReceived > 3)
{
// TODO: ParcelOverlaysReceived should become internal, and reset to zero every
// time it hits four. Also need a callback here
@@ -1932,7 +1337,7 @@ namespace libsecondlife
else
{
Client.Log("Parcel overlay with sequence ID of " + overlay.ParcelData.SequenceID +
- " received from " + simulator.Region.Name, Helpers.LogLevel.Warning);
+ " received from " + simulator.ToString(), Helpers.LogLevel.Warning);
}
}
diff --git a/libsecondlife-cs/ObjectManager.cs b/libsecondlife-cs/ObjectManager.cs
index fef43588..ac1781a2 100644
--- a/libsecondlife-cs/ObjectManager.cs
+++ b/libsecondlife-cs/ObjectManager.cs
@@ -1290,7 +1290,7 @@ namespace libsecondlife
// Set this avatar online and in a region
avatar.Online = true;
- avatar.CurrentRegion = simulator.Region;
+ avatar.CurrentSim = simulator;
// Textures
avatar.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length);
diff --git a/libsecondlife-cs/Region.cs b/libsecondlife-cs/Region.cs
deleted file mode 100644
index be5a35fe..00000000
--- a/libsecondlife-cs/Region.cs
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (c) 2006, Second Life Reverse Engineering Team
- * All rights reserved.
- *
- * - Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * - Neither the name of the Second Life Reverse Engineering Team nor the names
- * of its contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Collections.Generic;
-using libsecondlife.Packets;
-
-namespace libsecondlife
-{
- ///
- /// Represents a region (also known as a sim) in Second Life.
- ///
- public class Region
- {
- ///
- public LLUUID ID = LLUUID.Zero;
- ///
- public ulong Handle;
- ///
- public string Name = "";
- ///
- public byte[] ParcelOverlay = new byte[4096];
- ///
- public int ParcelOverlaysReceived;
- ///
- 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 = LLUUID.Zero;
- ///
- public LLUUID TerrainBase0 = LLUUID.Zero;
- ///
- public LLUUID TerrainBase1 = LLUUID.Zero;
- ///
- public LLUUID TerrainBase2 = LLUUID.Zero;
- ///
- public LLUUID TerrainBase3 = LLUUID.Zero;
- ///
- public LLUUID TerrainDetail0 = LLUUID.Zero;
- ///
- public LLUUID TerrainDetail1 = LLUUID.Zero;
- ///
- public LLUUID TerrainDetail2 = LLUUID.Zero;
- ///
- public LLUUID TerrainDetail3 = LLUUID.Zero;
- ///
- public bool IsEstateManager;
- ///
- public EstateTools Estate;
-
- ///
- /// This may cause your code to block while the GridRegion data is fetched for the first time
- private GridRegion _GridRegionData = null;
- public GridRegion GridRegionData
- {
- get
- {
- if (_GridRegionData == null)
- {
- if ((Name != null) && (!Name.Equals("")))
- {
- _GridRegionData = Client.Grid.GetGridRegion(Client.Network.CurrentSim.Region.Name);
- }
- }
- return _GridRegionData;
- }
- }
-
- private SecondLife Client;
-
- ///
- ///
- ///
- ///
- public Region(SecondLife client)
- {
- Estate = new EstateTools(client);
- Client = client;
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public Region(SecondLife client, LLUUID id, ulong 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];
-
- 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;
-
- 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;
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public void ParcelSubdivide(float west, float south, float east, float north)
- {
- ParcelDividePacket divide = new ParcelDividePacket();
- divide.AgentData.AgentID = Client.Network.AgentID;
- divide.AgentData.SessionID = Client.Network.SessionID;
- divide.ParcelData.East = east;
- divide.ParcelData.North = north;
- divide.ParcelData.South = south;
- divide.ParcelData.West = west;
-
- // FIXME: Region needs a reference to it's parent Simulator
- //Client.Network.SendPacket((Packet)divide, this.Simulator);
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public void ParcelJoin(float west, float south, float east, float north)
- {
- ParcelJoinPacket join = new ParcelJoinPacket();
- join.AgentData.AgentID = Client.Network.AgentID;
- join.AgentData.SessionID = Client.Network.SessionID;
- join.ParcelData.East = east;
- join.ParcelData.North = north;
- join.ParcelData.South = south;
- join.ParcelData.West = west;
-
- // FIXME: Region needs a reference to it's parent Simulator
- //Client.Network.SendPacket((Packet)join, this.Simulator);
- }
-
- ///
- ///
- ///
- ///
- public override int GetHashCode()
- {
- return ID.GetHashCode();
- }
- }
-}
diff --git a/libsecondlife-cs/Simulator.cs b/libsecondlife-cs/Simulator.cs
new file mode 100644
index 00000000..184daee4
--- /dev/null
+++ b/libsecondlife-cs/Simulator.cs
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2007, Second Life Reverse Engineering Team
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the Second Life Reverse Engineering Team nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Net;
+using System.Net.Sockets;
+using libsecondlife.Packets;
+
+namespace libsecondlife
+{
+ ///
+ /// Simulator is a wrapper for a network connection to a simulator and the
+ /// Region class representing the block of land in the metaverse
+ ///
+ public class Simulator
+ {
+ /// A public reference to the client that this Simulator object
+ /// is attached to
+ public SecondLife Client;
+ ///
+ public LLUUID ID = LLUUID.Zero;
+ ///
+ public ulong Handle;
+ ///
+ public string Name = String.Empty;
+ ///
+ public byte[] ParcelOverlay = new byte[4096];
+ ///
+ public int ParcelOverlaysReceived;
+ ///
+ 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 = LLUUID.Zero;
+ ///
+ public LLUUID TerrainBase0 = LLUUID.Zero;
+ ///
+ public LLUUID TerrainBase1 = LLUUID.Zero;
+ ///
+ public LLUUID TerrainBase2 = LLUUID.Zero;
+ ///
+ public LLUUID TerrainBase3 = LLUUID.Zero;
+ ///
+ public LLUUID TerrainDetail0 = LLUUID.Zero;
+ ///
+ public LLUUID TerrainDetail1 = LLUUID.Zero;
+ ///
+ public LLUUID TerrainDetail2 = LLUUID.Zero;
+ ///
+ public LLUUID TerrainDetail3 = LLUUID.Zero;
+ ///
+ public bool IsEstateManager;
+ ///
+ public EstateTools Estate;
+ /// Current time dilation of this simulator
+ public float Dilation;
+
+ ///
+ /// The ID number associated with this particular connection to the
+ /// simulator, used to emulate TCP connections. This is used
+ /// internally for packets that have a CircuitCode field
+ ///
+ public uint CircuitCode
+ {
+ get { return circuitCode; }
+ set { circuitCode = value; }
+ }
+ /// The IP address and port of the server
+ public IPEndPoint IPEndPoint { get { return ipEndPoint; } }
+ /// Whether there is a working connection to the simulator or
+ /// not
+ public bool Connected { get { return connected; } }
+
+ /// Used internally to track sim disconnections
+ internal bool DisconnectCandidate = false;
+ ///
+ internal ManualResetEvent ConnectedEvent = new ManualResetEvent(false);
+ ///
+ internal bool connected;
+
+ private NetworkManager Network;
+ private uint Sequence = 0;
+ private object SequenceLock = new object();
+ private byte[] RecvBuffer = new byte[4096];
+ private byte[] ZeroBuffer = new byte[8192];
+ private byte[] ZeroOutBuffer = new byte[4096];
+ private Socket Connection = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+ private AsyncCallback ReceivedData;
+ // Packets we sent out that need ACKs from the simulator
+ private Dictionary NeedAck = new Dictionary();
+ // Sequence numbers of packets we've received from the simulator
+ private Queue Inbox;
+ // ACKs that are queued up to be sent to the simulator
+ private Dictionary PendingAcks = new Dictionary();
+ private uint circuitCode;
+ private IPEndPoint ipEndPoint;
+ private EndPoint endPoint;
+ private System.Timers.Timer AckTimer;
+
+
+ ///
+ /// Default constructor
+ ///
+ /// Reference to the SecondLife client
+ /// Integer to uniquely identify the connection to this simulator
+ /// IP address of the simulator
+ /// Port on the simulator to connect to
+ /// Whether to move our agent in to this sim or not
+ public Simulator(SecondLife client, uint circuit, IPAddress ip, int port, bool moveToSim)
+ {
+ Client = client;
+ Estate = new EstateTools(Client);
+ Network = client.Network;
+ circuitCode = circuit;
+ Inbox = new Queue(Client.Settings.INBOX_SIZE);
+ AckTimer = new System.Timers.Timer(Client.Settings.NETWORK_TICK_LENGTH);
+ AckTimer.Elapsed += new System.Timers.ElapsedEventHandler(AckTimer_Elapsed);
+
+ // Initialize the callback for receiving a new packet
+ ReceivedData = new AsyncCallback(OnReceivedData);
+
+ Client.Log("Connecting to " + ip.ToString() + ":" + port, Helpers.LogLevel.Info);
+
+ try
+ {
+ // Create an endpoint that we will be communicating with (need it in two
+ // types due to .NET weirdness)
+ ipEndPoint = new IPEndPoint(ip, port);
+ endPoint = (EndPoint)ipEndPoint;
+
+ // Associate this simulator's socket with the given ip/port and start listening
+ Connection.Connect(endPoint);
+ Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null);
+
+ // Send the UseCircuitCode packet to initiate the connection
+ UseCircuitCodePacket use = new UseCircuitCodePacket();
+ use.CircuitCode.Code = circuitCode;
+ use.CircuitCode.ID = Network.AgentID;
+ use.CircuitCode.SessionID = Network.SessionID;
+
+ // Start the ACK timer
+ AckTimer.Start();
+
+ // Send the initial packet out
+ SendPacket(use, true);
+
+ // Move our agent in to the sim to complete the connection
+ if (moveToSim) Client.Self.CompleteAgentMovement(this);
+
+ ConnectedEvent.Reset();
+ ConnectedEvent.WaitOne(Client.Settings.SIMULATOR_TIMEOUT, false);
+ }
+ catch (Exception e)
+ {
+ Client.Log(e.ToString(), Helpers.LogLevel.Error);
+ }
+ }
+
+ ///
+ /// Disconnect a Simulator
+ ///
+ public void Disconnect()
+ {
+ if (connected)
+ {
+ connected = false;
+ AckTimer.Stop();
+
+ // Send the CloseCircuit notice
+ CloseCircuitPacket close = new CloseCircuitPacket();
+
+ if (Connection.Connected)
+ {
+ try
+ {
+ Connection.Send(close.ToBytes());
+ }
+ catch (SocketException)
+ {
+ // There's a high probability of this failing if the network is
+ // disconnecting, so don't even bother logging the error
+ }
+ }
+
+ try
+ {
+ // Shut the socket communication down
+ Connection.Shutdown(SocketShutdown.Both);
+ }
+ catch (SocketException)
+ {
+ }
+ }
+ }
+
+ ///
+ /// Sends a packet
+ ///
+ /// Packet to be sent
+ /// Increment sequence number?
+ public void SendPacket(Packet packet, bool incrementSequence)
+ {
+ byte[] buffer;
+ int bytes;
+
+ if (packet.Header.AckList.Length > 0)
+ {
+ // Scrub any appended ACKs since all of the ACK handling is done here
+ packet.Header.AckList = new uint[0];
+ }
+ packet.Header.AppendedAcks = false;
+
+ // Keep track of when this packet was sent out
+ packet.TickCount = Environment.TickCount;
+
+ if (incrementSequence)
+ {
+ // Set the sequence number
+ lock (SequenceLock)
+ {
+ if (Sequence > Client.Settings.MAX_SEQUENCE)
+ Sequence = 1;
+ else
+ Sequence++;
+ packet.Header.Sequence = Sequence;
+ }
+
+ if (packet.Header.Reliable)
+ {
+ lock (NeedAck)
+ {
+ if (!NeedAck.ContainsKey(packet.Header.Sequence))
+ {
+ NeedAck.Add(packet.Header.Sequence, packet);
+ }
+ else
+ {
+ Client.Log("Attempted to add a duplicate sequence number (" +
+ packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
+ packet.Type.ToString(), Helpers.LogLevel.Warning);
+ }
+ }
+
+ // Don't append ACKs to resent packets, in case that's what was causing the
+ // delivery to fail
+ if (!packet.Header.Resent)
+ {
+ // Append any ACKs that need to be sent out to this packet
+ lock (PendingAcks)
+ {
+ if (PendingAcks.Count > 0 && PendingAcks.Count < Client.Settings.MAX_APPENDED_ACKS &&
+ packet.Type != PacketType.PacketAck &&
+ packet.Type != PacketType.LogoutRequest)
+ {
+ packet.Header.AckList = new uint[PendingAcks.Count];
+
+ int i = 0;
+
+ foreach (uint ack in PendingAcks.Values)
+ {
+ packet.Header.AckList[i] = ack;
+ i++;
+ }
+
+ PendingAcks.Clear();
+ packet.Header.AppendedAcks = true;
+ }
+ }
+ }
+ }
+ }
+
+ // Serialize the packet
+ buffer = packet.ToBytes();
+ bytes = buffer.Length;
+
+ try
+ {
+ // Zerocode if needed
+ if (packet.Header.Zerocoded)
+ {
+ lock (ZeroOutBuffer)
+ {
+ bytes = Helpers.ZeroEncode(buffer, bytes, ZeroOutBuffer);
+ Connection.Send(ZeroOutBuffer, bytes, SocketFlags.None);
+ }
+ }
+ else
+ {
+ Connection.Send(buffer, bytes, SocketFlags.None);
+ }
+ }
+ catch (SocketException)
+ {
+ Client.Log("Tried to send a " + packet.Type.ToString() + " on a closed socket, shutting down " +
+ this.ToString(), Helpers.LogLevel.Info);
+
+ Network.DisconnectSim(this);
+ return;
+ }
+ }
+
+ ///
+ /// Send a raw byte array payload as a packet
+ ///
+ /// The packet payload
+ /// Whether the second, third, and fourth bytes
+ /// should be modified to the current stream sequence number
+ public void SendPacket(byte[] payload, bool setSequence)
+ {
+ try
+ {
+ if (setSequence && payload.Length > 3)
+ {
+ lock (SequenceLock)
+ {
+ payload[1] = (byte)(Sequence >> 16);
+ payload[2] = (byte)(Sequence >> 8);
+ payload[3] = (byte)(Sequence % 256);
+ Sequence++;
+ }
+ }
+
+ Connection.Send(payload, payload.Length, SocketFlags.None);
+ }
+ catch (SocketException)
+ {
+ Client.Log("Tried to send a " + payload.Length + " byte payload on a closed socket, shutting down " +
+ this.ToString(), Helpers.LogLevel.Info);
+
+ Network.DisconnectSim(this);
+ return;
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void ParcelSubdivide(float west, float south, float east, float north)
+ {
+ ParcelDividePacket divide = new ParcelDividePacket();
+ divide.AgentData.AgentID = Client.Network.AgentID;
+ divide.AgentData.SessionID = Client.Network.SessionID;
+ divide.ParcelData.East = east;
+ divide.ParcelData.North = north;
+ divide.ParcelData.South = south;
+ divide.ParcelData.West = west;
+
+ SendPacket(divide, true);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void ParcelJoin(float west, float south, float east, float north)
+ {
+ ParcelJoinPacket join = new ParcelJoinPacket();
+ join.AgentData.AgentID = Client.Network.AgentID;
+ join.AgentData.SessionID = Client.Network.SessionID;
+ join.ParcelData.East = east;
+ join.ParcelData.North = north;
+ join.ParcelData.South = south;
+ join.ParcelData.West = west;
+
+ SendPacket(join, true);
+ }
+
+ ///
+ /// Returns Simulator Name as a String
+ ///
+ ///
+ public override string ToString()
+ {
+ if (Name.Length > 0)
+ return Name + " (" + ipEndPoint.ToString() + ")";
+ else
+ return "(" + ipEndPoint.ToString() + ")";
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public override int GetHashCode()
+ {
+ return ID.GetHashCode();
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ Simulator sim = obj as Simulator;
+ if (sim == null)
+ return false;
+ return ID.Equals(sim.ID);
+ }
+
+ ///
+ /// Sends out pending acknowledgements
+ ///
+ private void SendAcks()
+ {
+ lock (PendingAcks)
+ {
+ if (PendingAcks.Count > 0)
+ {
+ if (PendingAcks.Count > 250)
+ {
+ // FIXME: Handle the odd case where we have too many pending ACKs queued up
+ Client.Log("Too many ACKs queued up!", Helpers.LogLevel.Error);
+ return;
+ }
+
+ int i = 0;
+ PacketAckPacket acks = new PacketAckPacket();
+ acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
+
+ foreach (uint ack in PendingAcks.Values)
+ {
+ acks.Packets[i] = new PacketAckPacket.PacketsBlock();
+ acks.Packets[i].ID = ack;
+ i++;
+ }
+
+ acks.Header.Reliable = false;
+ SendPacket(acks, true);
+
+ PendingAcks.Clear();
+ }
+ }
+ }
+ ///
+ /// Resend unacknowledged packets
+ ///
+ private void ResendUnacked()
+ {
+ if (connected)
+ {
+ int now = Environment.TickCount;
+
+ lock (NeedAck)
+ {
+ foreach (Packet packet in NeedAck.Values)
+ {
+ if (now - packet.TickCount > Client.Settings.RESEND_TIMEOUT)
+ {
+ Client.Log("Resending " + packet.Type.ToString() + " packet (" + packet.Header.Sequence +
+ "), " + (now - packet.TickCount) + "ms have passed", Helpers.LogLevel.Info);
+
+ packet.Header.Resent = true;
+ SendPacket(packet, false);
+ }
+ }
+ }
+ }
+ }
+ ///
+ /// Callback handler for incomming data
+ ///
+ ///
+ private void OnReceivedData(IAsyncResult result)
+ {
+ Packet packet = null;
+ int numBytes;
+
+ // Update the disconnect flag so this sim doesn't time out
+ DisconnectCandidate = false;
+
+ lock (RecvBuffer)
+ {
+ // Retrieve the incoming packet
+ try
+ {
+ numBytes = Connection.EndReceiveFrom(result, ref endPoint);
+
+ int packetEnd = numBytes - 1;
+ packet = Packet.BuildPacket(RecvBuffer, ref packetEnd, ZeroBuffer);
+
+ Connection.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref endPoint, ReceivedData, null);
+ }
+ catch (SocketException)
+ {
+ Client.Log(endPoint.ToString() + " socket is closed, shutting down " + this.ToString(),
+ Helpers.LogLevel.Info);
+ Network.DisconnectSim(this);
+ return;
+ }
+ }
+
+ // Fail-safe check
+ if (packet == null)
+ {
+ Client.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning);
+ return;
+ }
+
+ // Track the sequence number for this packet if it's marked as reliable
+ if (packet.Header.Reliable)
+ {
+ if (PendingAcks.Count > Client.Settings.MAX_PENDING_ACKS)
+ {
+ SendAcks();
+ }
+
+ // Check if we already received this packet
+ if (Inbox.Contains(packet.Header.Sequence))
+ {
+ Client.Log("Received a duplicate " + packet.Type.ToString() + ", sequence=" +
+ packet.Header.Sequence + ", resent=" + ((packet.Header.Resent) ? "Yes" : "No") +
+ ", Inbox.Count=" + Inbox.Count + ", NeedAck.Count=" + NeedAck.Count,
+ Helpers.LogLevel.Info);
+
+ // Send an ACK for this packet immediately
+ //SendAck(packet.Header.Sequence);
+
+ // TESTING: Try just queuing up ACKs for resent packets instead of immediately triggering an ACK
+ lock (PendingAcks)
+ {
+ uint sequence = (uint)packet.Header.Sequence;
+ if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
+ }
+
+ // Avoid firing a callback twice for the same packet
+ return;
+ }
+ else
+ {
+ lock (PendingAcks)
+ {
+ uint sequence = (uint)packet.Header.Sequence;
+ if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
+ }
+ }
+ }
+
+ // Add this packet to our inbox
+ lock (Inbox)
+ {
+ while (Inbox.Count >= Client.Settings.INBOX_SIZE)
+ {
+ Inbox.Dequeue();
+ Inbox.Dequeue();
+ }
+ Inbox.Enqueue(packet.Header.Sequence);
+ }
+
+ // Handle appended ACKs
+ if (packet.Header.AppendedAcks)
+ {
+ lock (NeedAck)
+ {
+ foreach (uint ack in packet.Header.AckList)
+ {
+ NeedAck.Remove(ack);
+ }
+ }
+ }
+
+ // Handle PacketAck packets
+ if (packet.Type == PacketType.PacketAck)
+ {
+ PacketAckPacket ackPacket = (PacketAckPacket)packet;
+
+ lock (NeedAck)
+ {
+ foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
+ {
+ NeedAck.Remove(block.ID);
+ }
+ }
+ }
+
+
+ // Fire the registered packet events
+ #region FireCallbacks
+ if (Network.Callbacks.ContainsKey(packet.Type))
+ {
+ List callbackArray = Network.Callbacks[packet.Type];
+
+ // Fire any registered callbacks
+ foreach (NetworkManager.PacketCallback callback in callbackArray)
+ {
+ if (callback != null)
+ {
+ try
+ {
+ callback(packet, this);
+ }
+ catch (Exception e)
+ {
+ Client.Log("Caught an exception in a packet callback: " + e.ToString(),
+ Helpers.LogLevel.Error);
+ }
+ }
+ }
+ }
+
+ if (Network.Callbacks.ContainsKey(PacketType.Default))
+ {
+ List callbackArray = Network.Callbacks[PacketType.Default];
+
+ // Fire any registered callbacks
+ foreach (NetworkManager.PacketCallback callback in callbackArray)
+ {
+ if (callback != null)
+ {
+ try
+ {
+ callback(packet, this);
+ }
+ catch (Exception e)
+ {
+ Client.Log("Caught an exception in a packet callback: " + e.ToString(),
+ Helpers.LogLevel.Error);
+ }
+ }
+ }
+ }
+ #endregion FireCallbacks
+ }
+
+ private void AckTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs ea)
+ {
+ SendAcks();
+ ResendUnacked();
+ }
+ }
+}
diff --git a/libsecondlife-cs/examples/AnimationSample/AnimationSample.cs b/libsecondlife-cs/examples/AnimationSample/AnimationSample.cs
index e512cf00..1340bf68 100644
--- a/libsecondlife-cs/examples/AnimationSample/AnimationSample.cs
+++ b/libsecondlife-cs/examples/AnimationSample/AnimationSample.cs
@@ -51,15 +51,18 @@ namespace AnimationSample
private void btnLogin_Click(object sender, EventArgs e)
{
// Login
- if (!client.Network.Login(txtFirst.Text, txtLast.Text, txtPassword.Text, "animationsample", "jessemalthus@gmail.com"))
+ if (!client.Network.Login(txtFirst.Text, txtLast.Text, txtPassword.Text, "animationsample",
+ "jessemalthus@gmail.com"))
{
// Login failed
- MessageBox.Show("We're sorry, but login failed. Error: \n " + client.Network.LoginError);
+ MessageBox.Show("We're sorry, but login failed. Error: " + Environment.NewLine +
+ client.Network.LoginError);
}
else
{
- MessageBox.Show("Login succeded. You're at " + client.Self.Position + " on " + client.Network.CurrentSim.Region.Name);
+ MessageBox.Show("Login succeded. You're at " + client.Self.Position + " on " +
+ client.Network.CurrentSim.ToString());
}
}
}
diff --git a/libsecondlife-cs/examples/Heightmap/frmHeightmap.cs b/libsecondlife-cs/examples/Heightmap/frmHeightmap.cs
index 9d9ad03c..e68754ca 100644
--- a/libsecondlife-cs/examples/Heightmap/frmHeightmap.cs
+++ b/libsecondlife-cs/examples/Heightmap/frmHeightmap.cs
@@ -116,7 +116,7 @@ namespace Heightmap
int lesserVal = (int)((float)colorVal * 0.75f);
Color color;
- if (height >= simulator.Region.WaterHeight)
+ if (height >= simulator.WaterHeight)
color = Color.FromArgb(lesserVal, colorVal, lesserVal);
else
color = Color.FromArgb(lesserVal, lesserVal, colorVal);
diff --git a/libsecondlife-cs/examples/Teleport/Teleport.cs b/libsecondlife-cs/examples/Teleport/Teleport.cs
index ef79f26f..d79f91e6 100644
--- a/libsecondlife-cs/examples/Teleport/Teleport.cs
+++ b/libsecondlife-cs/examples/Teleport/Teleport.cs
@@ -40,15 +40,9 @@ namespace Teleport
if (success)
{
- // Get the current sim name
- while (app.Client.Network.CurrentSim.Region.Name == "")
- {
- System.Threading.Thread.Sleep(100);
- }
+ Console.WriteLine("Starting in " + app.Client.Network.CurrentSim.ToString());
- Console.WriteLine("Starting in " + app.Client.Network.CurrentSim.Region.Name);
-
- if (sim.ToLower() == app.Client.Network.CurrentSim.Region.Name.ToLower())
+ if (sim.ToLower() == app.Client.Network.CurrentSim.Name.ToLower())
{
Console.WriteLine("TODO: Add the ability to teleport somewhere in the local region. " +
"Exiting for now, please specify a region other than the current one");
diff --git a/libsecondlife-cs/examples/TestClient/ClientManager.cs b/libsecondlife-cs/examples/TestClient/ClientManager.cs
index 454e5069..01aac4d7 100644
--- a/libsecondlife-cs/examples/TestClient/ClientManager.cs
+++ b/libsecondlife-cs/examples/TestClient/ClientManager.cs
@@ -86,22 +86,30 @@ namespace libsecondlife.TestClient
client.SimPrims = SimPrims;
client.Master = account.Master;
-
- bool check = false;
- if ( this.startpos.sim != null ) {
- if ( this.startpos.x == 0 || this.startpos.y == 0 || this.startpos.z == 0 ) {
+
+ if (this.startpos.sim != null)
+ {
+ if (this.startpos.x == 0 || this.startpos.y == 0 || this.startpos.z == 0)
+ {
this.startpos.x = 128;
this.startpos.y = 128;
this.startpos.z = 1;
}
- string startLoc = NetworkManager.StartLocation(this.startpos.sim, this.startpos.x, this.startpos.y, this.startpos.z);
+
+ string startLoc = NetworkManager.StartLocation(this.startpos.sim, this.startpos.x, this.startpos.y,
+ this.startpos.z);
Console.WriteLine(startLoc);
- client.Network.Login(account.FirstName, account.LastName, account.Password, "TestClient", startLoc, contactPerson, false);
- } else {
- client.Network.Login(account.FirstName, account.LastName, account.Password, "TestClient", contactPerson);
+ client.Network.Login(account.FirstName, account.LastName, account.Password, "TestClient", startLoc,
+ contactPerson, false);
}
- if ( ! check ) {
- Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " + client.Network.LoginError);
+ else
+ {
+ if (!client.Network.Login(account.FirstName, account.LastName, account.Password, "TestClient",
+ contactPerson))
+ {
+ Console.WriteLine("Failed to login " + account.FirstName + " " + account.LastName + ": " +
+ client.Network.LoginError);
+ }
}
if (client.Network.Connected)
diff --git a/libsecondlife-cs/examples/TestClient/Commands/Movement/JumpCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/Movement/JumpCommand.cs
index c56dd1ce..6cead83b 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/Movement/JumpCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/Movement/JumpCommand.cs
@@ -24,7 +24,7 @@ namespace libsecondlife.TestClient
Client.Self.Teleport
(
- Client.Network.CurrentSim.Region.Name,
+ Client.Network.CurrentSim.Name,
new LLVector3(Client.Self.Position.X, Client.Self.Position.Y, Client.Self.Position.Z + height)
);
diff --git a/libsecondlife-cs/examples/TestClient/Commands/Movement/LocationCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/Movement/LocationCommand.cs
index ac7d24f1..1758a482 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/Movement/LocationCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/Movement/LocationCommand.cs
@@ -16,7 +16,8 @@ namespace libsecondlife.TestClient
public override string Execute(string[] args, LLUUID fromAgentID)
{
- return "CurrentSim: '" + Client.Network.CurrentSim.Region.Name + "' Position: " + Client.Self.Position.ToString();
+ return "CurrentSim: '" + Client.Network.CurrentSim.ToString() + "' Position: " +
+ Client.Self.Position.ToString();
}
}
}
diff --git a/libsecondlife-cs/examples/TestClient/Commands/ResearchCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/ResearchCommand.cs
index d5e03590..e7858bec 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/ResearchCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/ResearchCommand.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Threading;
+using System.Text;
+using System.IO;
using libsecondlife;
-//using libsecondlife.Utilities.Assets;
-//using libsecondlife.Utilities.Appearance;
+using libsecondlife.Utilities.Assets;
+using libsecondlife.Utilities.Appearance;
using libsecondlife.Packets;
namespace libsecondlife.TestClient
@@ -11,20 +13,71 @@ namespace libsecondlife.TestClient
public class ResearchCommand : Command
{
private ManualResetEvent AssetReceived = new ManualResetEvent(false);
- //AssetManager manager;
+ AssetManager manager;
//AppearanceManager appearance;
+ List Downloaded = new List();
public ResearchCommand(TestClient testClient)
{
Name = "research";
Description = "Does important research for the betterment of mankind";
- //manager = new AssetManager(testClient);
+ testClient.Objects.OnNewAvatar += new ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
+
+ manager = new AssetManager(testClient);
+ manager.OnImageReceived += new AssetManager.ImageReceivedCallback(manager_OnImageReceived);
//manager.OnAssetReceived += new AssetManager.AssetReceivedCallback(manager_OnAssetReceived);
//appearance = new AppearanceManager(testClient, manager);
//appearance.OnAgentWearables += new AppearanceManager.AgentWearablesCallback(appearance_OnAgentWearables);
}
+ void manager_OnImageReceived(ImageDownload image)
+ {
+ if (image.Success)
+ {
+ File.WriteAllBytes(image.ID.ToStringHyphenated() + ".j2c", image.AssetData);
+ Console.WriteLine("Downloaded " + image.ID.ToStringHyphenated());
+ }
+ else
+ {
+ Console.WriteLine("Failed to download " + image.ID.ToStringHyphenated() + ", NotFound=" + image.NotFound);
+ }
+ }
+
+ void Objects_OnNewAvatar(Simulator simulator, Avatar avatar, ulong regionHandle, ushort timeDilation)
+ {
+ StringBuilder output = new StringBuilder("Avatar ");
+ output.Append(avatar.ID.ToStringHyphenated());
+ output.Append(" is wearing: ");
+
+ foreach (KeyValuePair texture in avatar.Textures.FaceTextures)
+ {
+ AppearanceManager.TextureIndex textureName = (AppearanceManager.TextureIndex)texture.Key;
+
+ switch (textureName)
+ {
+ case AppearanceManager.TextureIndex.HeadBaked:
+ case AppearanceManager.TextureIndex.LowerBaked:
+ case AppearanceManager.TextureIndex.UpperBaked:
+ case AppearanceManager.TextureIndex.SkirtBaked:
+ if (!Downloaded.Contains(texture.Value.TextureID) &&
+ texture.Value.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE)
+ {
+ Downloaded.Add(texture.Value.TextureID);
+ //manager.RequestImage(texture.Value.TextureID, ImageType.Baked, 120000.0f, 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ output.Append(textureName.ToString());
+ output.Append(" ");
+ }
+
+ //Console.WriteLine(output.ToString());
+ }
+
public override string Execute(string[] args, LLUUID fromAgentID)
{
//Dictionary wearables = new Dictionary();
diff --git a/libsecondlife-cs/examples/TestClient/Commands/WhoCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/WhoCommand.cs
index 21d0d036..3edb649a 100644
--- a/libsecondlife-cs/examples/TestClient/Commands/WhoCommand.cs
+++ b/libsecondlife-cs/examples/TestClient/Commands/WhoCommand.cs
@@ -19,7 +19,8 @@ namespace libsecondlife.TestClient
StringBuilder result = new StringBuilder();
foreach (Avatar av in Client.AvatarList.Values)
{
- result.AppendFormat("\n{0} {1} {2}/{3} ID: {4}", av.Name, av.GroupName, av.CurrentRegion != null ? av.CurrentRegion.Name : String.Empty, av.Position, av.ID);
+ result.AppendFormat("\n{0} {1} {2}/{3} ID: {4}", av.Name, av.GroupName,
+ (av.CurrentSim != null ? av.CurrentSim.Name : String.Empty), av.Position, av.ID);
}
return result.ToString();
diff --git a/libsecondlife-cs/libsecondlife.Tests/NetworkTests.cs b/libsecondlife-cs/libsecondlife.Tests/NetworkTests.cs
index f3445df8..423f2acd 100644
--- a/libsecondlife-cs/libsecondlife.Tests/NetworkTests.cs
+++ b/libsecondlife-cs/libsecondlife.Tests/NetworkTests.cs
@@ -17,23 +17,20 @@ namespace libsecondlife.Tests
ulong AhernRegionHandle = 1096213093149184;
ulong MorrisRegionHandle = 1096213093149183;
bool DetectedObject = false;
- bool DoneTeleporting = false;
- MainAvatar.TeleportStatus tpStatus = MainAvatar.TeleportStatus.None;
- string tpMessage = "";
LLUUID LookupKey1 = new LLUUID("25472683cb324516904a6cd0ecabf128");
- string LookupName1 = "Bot Ringo";
+ //string LookupName1 = "Bot Ringo";
public NetworkTests()
{
Client = new SecondLife();
- string startLoc = NetworkManager.StartLocation("hooper", 128, 128, 32);
-
// Register callbacks
Client.Network.RegisterCallback(PacketType.ObjectUpdate, new NetworkManager.PacketCallback(ObjectUpdateHandler));
- Client.Self.OnTeleport += new MainAvatar.TeleportCallback(OnTeleportHandler);
+ //Client.Self.OnTeleport += new MainAvatar.TeleportCallback(OnTeleportHandler);
+ // Connect to the grid
+ string startLoc = NetworkManager.StartLocation("Ahern", 128, 128, 32);
Client.Network.Login("Testing", "Anvil", "testinganvil", "Unit Test Framework", startLoc,
"contact@libsecondlife.org", false);
}
@@ -49,16 +46,9 @@ namespace libsecondlife.Tests
Assert.IsTrue(Client.Network.Connected, "Client is not connected to the grid: " + Client.Network.LoginError);
int start = Environment.TickCount;
- while (Client.Network.CurrentSim.Region.Name == "")
- {
- if (Environment.TickCount - start > 5000)
- {
- Assert.Fail("Timeout waiting for a RegionHandshake packet");
- }
- }
- //Assert.AreEqual("ahern", Client.Network.CurrentSim.Region.Name.ToLower(), "Logged in to sim " +
- // Client.Network.CurrentSim.Region.Name + " instead of Ahern");
+ Assert.AreEqual("ahern", Client.Network.CurrentSim.Name.ToLower(), "Logged in to sim " +
+ Client.Network.CurrentSim.Name + " instead of Ahern");
}
[Test]
@@ -92,96 +82,27 @@ namespace libsecondlife.Tests
CurrentRegionHandle + " when we were expecting " + AhernRegionHandle + ", possible endian issue");
}
- [Test]
- public void NameLookup()
- {
- AvatarTracker tracker = new AvatarTracker(Client);
-
- string name = tracker.GetAvatarName(LookupKey1);
-
- Assert.IsTrue(name == LookupName1, "AvatarTracker.GetAvatarName() returned " + name +
- " instead of " + LookupName1);
- }
-
[Test]
public void Teleport()
{
- DoneTeleporting = false;
- tpStatus = MainAvatar.TeleportStatus.None;
-
- Client.Self.Teleport(MorrisRegionHandle, new LLVector3(128, 128, 32));
-
- int start = Environment.TickCount;
-
- while (!DoneTeleporting)
- {
- System.Threading.Thread.Sleep(100);
-
- if (Environment.TickCount - start > 10000)
- {
- Assert.Fail("Timeout waiting for the first teleport to finish");
- return;
- }
- }
-
- Assert.IsTrue(tpStatus == MainAvatar.TeleportStatus.Finished,
- "Teleport status is " + tpStatus.ToString() + ", message=" + tpMessage);
-
- // Wait for the region information to come in
- start = Environment.TickCount;
- while (Client.Network.CurrentSim.Region.Name == "")
- {
- if (Environment.TickCount - start > 5000)
- {
- Assert.Fail("Timeout waiting for a RegionHandshake packet");
- }
- }
+ Assert.IsTrue(Client.Self.Teleport(MorrisRegionHandle, new LLVector3(128, 128, 32)),
+ "Teleport to Morris failed");
// Assert that we really did make it to our scheduled destination
- Assert.AreEqual("morris", Client.Network.CurrentSim.Region.Name.ToLower(),
- "Expected to teleport to Morris, ended up in " + Client.Network.CurrentSim.Region.Name +
+ Assert.AreEqual("morris", Client.Network.CurrentSim.Name.ToLower(),
+ "Expected to teleport to Morris, ended up in " + Client.Network.CurrentSim.Name +
". Possibly region full or offline?");
///////////////////////////////////////////////////////////////////
-
// TODO: Add a local region teleport
-
///////////////////////////////////////////////////////////////////
- DoneTeleporting = false;
- tpStatus = MainAvatar.TeleportStatus.None;
-
- Client.Self.Teleport(AhernRegionHandle, new LLVector3(128, 128, 32));
-
- start = Environment.TickCount;
-
- while (!DoneTeleporting)
- {
- System.Threading.Thread.Sleep(100);
-
- if (Environment.TickCount - start > 10000)
- {
- Assert.Fail("Timeout waiting for the second teleport to finish");
- return;
- }
- }
-
- Assert.IsTrue(tpStatus == MainAvatar.TeleportStatus.Finished, "Teleport status is " +
- tpStatus.ToString() + ", message=" + tpMessage);
-
- // Wait for the region information to come in
- start = Environment.TickCount;
- while (Client.Network.CurrentSim.Region.Name == "")
- {
- if (Environment.TickCount - start > 5000)
- {
- Assert.Fail("Timeout waiting for a RegionHandshake packet");
- }
- }
+ Assert.IsTrue(Client.Self.Teleport(AhernRegionHandle, new LLVector3(128, 128, 32)),
+ "Teleport to Ahern failed");
// Assert that we really did make it to our scheduled destination
- Assert.AreEqual("ahern", Client.Network.CurrentSim.Region.Name.ToLower(),
- "Expected to teleport to Ahern, ended up in " + Client.Network.CurrentSim.Region.Name +
+ Assert.AreEqual("ahern", Client.Network.CurrentSim.Name.ToLower(),
+ "Expected to teleport to Ahern, ended up in " + Client.Network.CurrentSim.Name +
". Possibly region full or offline?");
}
@@ -193,33 +114,9 @@ namespace libsecondlife.Tests
CurrentRegionHandle = update.RegionData.RegionHandle;
}
- private void OnTeleportHandler(string message, MainAvatar.TeleportStatus status)
- {
- switch (status)
- {
- case MainAvatar.TeleportStatus.None:
- break;
- case MainAvatar.TeleportStatus.Start:
- break;
- case MainAvatar.TeleportStatus.Progress:
- break;
- case MainAvatar.TeleportStatus.Failed:
- DoneTeleporting = true;
- break;
- case MainAvatar.TeleportStatus.Finished:
- DoneTeleporting = true;
- break;
- }
-
- tpMessage = message;
- tpStatus = status;
- }
-
[TearDown]
public void Shutdown()
{
- //Client.Network.Logout();
- //Client = null;
}
}
}
diff --git a/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs b/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs
index 11d47209..031d52ef 100644
--- a/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs
+++ b/libsecondlife-cs/libsecondlife.Utilities/Utilities.cs
@@ -95,8 +95,8 @@ namespace libsecondlife.Utilities
{
if (SimHandle != 0)
{
- if (Client.Network.CurrentSim.Region.Handle != 0 &&
- Client.Network.CurrentSim.Region.Handle != SimHandle)
+ if (Client.Network.CurrentSim.Handle != 0 &&
+ Client.Network.CurrentSim.Handle != SimHandle)
{
// Attempt to move to our target sim
Client.Self.Teleport(SimHandle, Position);
@@ -177,7 +177,7 @@ namespace libsecondlife.Utilities
{
foreach (Avatar avatar in avatars.Values)
{
- if (avatar.CurrentRegion == Client.Network.CurrentSim.Region)
+ if (avatar.CurrentSim == Client.Network.CurrentSim)
local[avatar.ID] = avatar;
}
}
diff --git a/libsecondlife-cs/libsecondlife.csproj b/libsecondlife-cs/libsecondlife.csproj
index 8780d5b0..81bbf8c5 100644
--- a/libsecondlife-cs/libsecondlife.csproj
+++ b/libsecondlife-cs/libsecondlife.csproj
@@ -164,14 +164,12 @@
Code
-
- Code
-
Code
+
Code