corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Collections.Generic;
29 using System.Threading;
30 using System.Net;
31 using System.Net.Sockets;
32 using OpenMetaverse.Packets;
33  
34 namespace OpenMetaverse
35 {
36 #region Enums
37  
38 /// <summary>
39 /// Simulator (region) properties
40 /// </summary>
41 [Flags]
42 public enum RegionFlags : ulong
43 {
44 /// <summary>No flags set</summary>
45 None = 0,
46 /// <summary>Agents can take damage and be killed</summary>
47 AllowDamage = 1 << 0,
48 /// <summary>Landmarks can be created here</summary>
49 AllowLandmark = 1 << 1,
50 /// <summary>Home position can be set in this sim</summary>
51 AllowSetHome = 1 << 2,
52 /// <summary>Home position is reset when an agent teleports away</summary>
53 ResetHomeOnTeleport = 1 << 3,
54 /// <summary>Sun does not move</summary>
55 SunFixed = 1 << 4,
56 /// <summary>No object, land, etc. taxes</summary>
57 TaxFree = 1 << 5,
58 /// <summary>Disable heightmap alterations (agents can still plant
59 /// foliage)</summary>
60 BlockTerraform = 1 << 6,
61 /// <summary>Land cannot be released, sold, or purchased</summary>
62 BlockLandResell = 1 << 7,
63 /// <summary>All content is wiped nightly</summary>
64 Sandbox = 1 << 8,
65 /// <summary>Unknown: Related to the availability of an overview world map tile.(Think mainland images when zoomed out.)</summary>
66 NullLayer = 1 << 9,
67 /// <summary>Unknown: Related to region debug flags. Possibly to skip processing of agent interaction with world. </summary>
68 SkipAgentAction = 1 << 10,
69 /// <summary>Region does not update agent prim interest lists. Internal debugging option.</summary>
70 SkipUpdateInterestList = 1 << 11,
71 /// <summary>No collision detection for non-agent objects</summary>
72 SkipCollisions = 1 << 12,
73 /// <summary>No scripts are ran</summary>
74 SkipScripts = 1 << 13,
75 /// <summary>All physics processing is turned off</summary>
76 SkipPhysics = 1 << 14,
77 /// <summary>Region can be seen from other regions on world map. (Legacy world map option?) </summary>
78 ExternallyVisible = 1 << 15,
79 /// <summary>Region can be seen from mainland on world map. (Legacy world map option?) </summary>
80 MainlandVisible = 1 << 16,
81 /// <summary>Agents not explicitly on the access list can visit the region. </summary>
82 PublicAllowed = 1 << 17,
83 /// <summary>Traffic calculations are not run across entire region, overrides parcel settings. </summary>
84 BlockDwell = 1 << 18,
85 /// <summary>Flight is disabled (not currently enforced by the sim)</summary>
86 NoFly = 1 << 19,
87 /// <summary>Allow direct (p2p) teleporting</summary>
88 AllowDirectTeleport = 1 << 20,
89 /// <summary>Estate owner has temporarily disabled scripting</summary>
90 EstateSkipScripts = 1 << 21,
91 /// <summary>Restricts the usage of the LSL llPushObject function, applies to whole region.</summary>
92 RestrictPushObject = 1 << 22,
93 /// <summary>Deny agents with no payment info on file</summary>
94 DenyAnonymous = 1 << 23,
95 /// <summary>Deny agents with payment info on file</summary>
96 DenyIdentified = 1 << 24,
97 /// <summary>Deny agents who have made a monetary transaction</summary>
98 DenyTransacted = 1 << 25,
99 /// <summary>Parcels within the region may be joined or divided by anyone, not just estate owners/managers. </summary>
100 AllowParcelChanges = 1 << 26,
101 /// <summary>Abuse reports sent from within this region are sent to the estate owner defined email. </summary>
102 AbuseEmailToEstateOwner = 1 << 27,
103 /// <summary>Region is Voice Enabled</summary>
104 AllowVoice = 1 << 28,
105 /// <summary>Removes the ability from parcel owners to set their parcels to show in search.</summary>
106 BlockParcelSearch = 1 << 29,
107 /// <summary>Deny agents who have not been age verified from entering the region.</summary>
108 DenyAgeUnverified = 1 << 30
109  
110 }
111  
112 /// <summary>
113 /// Region protocol flags
114 /// </summary>
115 [Flags]
116 public enum RegionProtocols : ulong
117 {
118 /// <summary>Nothing special</summary>
119 None = 0,
120 /// <summary>Region supports Server side Appearance</summary>
121 AgentAppearanceService = 1 << 0,
122 /// <summary>Viewer supports Server side Appearance</summary>
123 SelfAppearanceSupport = 1 << 2
124 }
125  
126 /// <summary>
127 /// Access level for a simulator
128 /// </summary>
129 public enum SimAccess : byte
130 {
131 /// <summary>Unknown or invalid access level</summary>
132 Unknown = 0,
133 /// <summary>Trial accounts allowed</summary>
134 Trial = 7,
135 /// <summary>PG rating</summary>
136 PG = 13,
137 /// <summary>Mature rating</summary>
138 Mature = 21,
139 /// <summary>Adult rating</summary>
140 Adult = 42,
141 /// <summary>Simulator is offline</summary>
142 Down = 254,
143 /// <summary>Simulator does not exist</summary>
144 NonExistent = 255
145 }
146  
147 #endregion Enums
148  
149 /// <summary>
150 ///
151 /// </summary>
152 public class Simulator : UDPBase, IDisposable
153 {
154 #region Structs
155 /// <summary>
156 /// Simulator Statistics
157 /// </summary>
158 public struct SimStats
159 {
160 /// <summary>Total number of packets sent by this simulator to this agent</summary>
161 public long SentPackets;
162 /// <summary>Total number of packets received by this simulator to this agent</summary>
163 public long RecvPackets;
164 /// <summary>Total number of bytes sent by this simulator to this agent</summary>
165 public long SentBytes;
166 /// <summary>Total number of bytes received by this simulator to this agent</summary>
167 public long RecvBytes;
168 /// <summary>Time in seconds agent has been connected to simulator</summary>
169 public int ConnectTime;
170 /// <summary>Total number of packets that have been resent</summary>
171 public int ResentPackets;
172 /// <summary>Total number of resent packets recieved</summary>
173 public int ReceivedResends;
174 /// <summary>Total number of pings sent to this simulator by this agent</summary>
175 public int SentPings;
176 /// <summary>Total number of ping replies sent to this agent by this simulator</summary>
177 public int ReceivedPongs;
178 /// <summary>
179 /// Incoming bytes per second
180 /// </summary>
181 /// <remarks>It would be nice to have this claculated on the fly, but
182 /// this is far, far easier</remarks>
183 public int IncomingBPS;
184 /// <summary>
185 /// Outgoing bytes per second
186 /// </summary>
187 /// <remarks>It would be nice to have this claculated on the fly, but
188 /// this is far, far easier</remarks>
189 public int OutgoingBPS;
190 /// <summary>Time last ping was sent</summary>
191 public int LastPingSent;
192 /// <summary>ID of last Ping sent</summary>
193 public byte LastPingID;
194 /// <summary></summary>
195 public int LastLag;
196 /// <summary></summary>
197 public int MissedPings;
198 /// <summary>Current time dilation of this simulator</summary>
199 public float Dilation;
200 /// <summary>Current Frames per second of simulator</summary>
201 public int FPS;
202 /// <summary>Current Physics frames per second of simulator</summary>
203 public float PhysicsFPS;
204 /// <summary></summary>
205 public float AgentUpdates;
206 /// <summary></summary>
207 public float FrameTime;
208 /// <summary></summary>
209 public float NetTime;
210 /// <summary></summary>
211 public float PhysicsTime;
212 /// <summary></summary>
213 public float ImageTime;
214 /// <summary></summary>
215 public float ScriptTime;
216 /// <summary></summary>
217 public float AgentTime;
218 /// <summary></summary>
219 public float OtherTime;
220 /// <summary>Total number of objects Simulator is simulating</summary>
221 public int Objects;
222 /// <summary>Total number of Active (Scripted) objects running</summary>
223 public int ScriptedObjects;
224 /// <summary>Number of agents currently in this simulator</summary>
225 public int Agents;
226 /// <summary>Number of agents in neighbor simulators</summary>
227 public int ChildAgents;
228 /// <summary>Number of Active scripts running in this simulator</summary>
229 public int ActiveScripts;
230 /// <summary></summary>
231 public int LSLIPS;
232 /// <summary></summary>
233 public int INPPS;
234 /// <summary></summary>
235 public int OUTPPS;
236 /// <summary>Number of downloads pending</summary>
237 public int PendingDownloads;
238 /// <summary>Number of uploads pending</summary>
239 public int PendingUploads;
240 /// <summary></summary>
241 public int VirtualSize;
242 /// <summary></summary>
243 public int ResidentSize;
244 /// <summary>Number of local uploads pending</summary>
245 public int PendingLocalUploads;
246 /// <summary>Unacknowledged bytes in queue</summary>
247 public int UnackedBytes;
248 }
249  
250 #endregion Structs
251  
252 #region Public Members
253 /// <summary>A public reference to the client that this Simulator object
254 /// is attached to</summary>
255 public GridClient Client;
256 /// <summary>A Unique Cache identifier for this simulator</summary>
257 public UUID ID = UUID.Zero;
258 /// <summary>The capabilities for this simulator</summary>
259 public Caps Caps = null;
260 /// <summary></summary>
261 public ulong Handle;
262 /// <summary>The current version of software this simulator is running</summary>
263 public string SimVersion = String.Empty;
264 /// <summary></summary>
265 public string Name = String.Empty;
266 /// <summary>A 64x64 grid of parcel coloring values. The values stored
267 /// in this array are of the <seealso cref="ParcelArrayType"/> type</summary>
268 public byte[] ParcelOverlay = new byte[4096];
269 /// <summary></summary>
270 public int ParcelOverlaysReceived;
271 /// <summary></summary>
272 public float TerrainHeightRange00;
273 /// <summary></summary>
274 public float TerrainHeightRange01;
275 /// <summary></summary>
276 public float TerrainHeightRange10;
277 /// <summary></summary>
278 public float TerrainHeightRange11;
279 /// <summary></summary>
280 public float TerrainStartHeight00;
281 /// <summary></summary>
282 public float TerrainStartHeight01;
283 /// <summary></summary>
284 public float TerrainStartHeight10;
285 /// <summary></summary>
286 public float TerrainStartHeight11;
287 /// <summary></summary>
288 public float WaterHeight;
289 /// <summary></summary>
290 public UUID SimOwner = UUID.Zero;
291 /// <summary></summary>
292 public UUID TerrainBase0 = UUID.Zero;
293 /// <summary></summary>
294 public UUID TerrainBase1 = UUID.Zero;
295 /// <summary></summary>
296 public UUID TerrainBase2 = UUID.Zero;
297 /// <summary></summary>
298 public UUID TerrainBase3 = UUID.Zero;
299 /// <summary></summary>
300 public UUID TerrainDetail0 = UUID.Zero;
301 /// <summary></summary>
302 public UUID TerrainDetail1 = UUID.Zero;
303 /// <summary></summary>
304 public UUID TerrainDetail2 = UUID.Zero;
305 /// <summary></summary>
306 public UUID TerrainDetail3 = UUID.Zero;
307 /// <summary>true if your agent has Estate Manager rights on this region</summary>
308 public bool IsEstateManager;
309 /// <summary></summary>
310 public RegionFlags Flags;
311 /// <summary></summary>
312 public SimAccess Access;
313 /// <summary></summary>
314 public float BillableFactor;
315 /// <summary>Statistics information for this simulator and the
316 /// connection to the simulator, calculated by the simulator itself
317 /// and the library</summary>
318 public SimStats Stats;
319 /// <summary>The regions Unique ID</summary>
320 public UUID RegionID = UUID.Zero;
321 /// <summary>The physical data center the simulator is located</summary>
322 /// <remarks>Known values are:
323 /// <list type="table">
324 /// <item>Dallas</item>
325 /// <item>Chandler</item>
326 /// <item>SF</item>
327 /// </list>
328 /// </remarks>
329 public string ColoLocation;
330 /// <summary>The CPU Class of the simulator</summary>
331 /// <remarks>Most full mainland/estate sims appear to be 5,
332 /// Homesteads and Openspace appear to be 501</remarks>
333 public int CPUClass;
334 /// <summary>The number of regions sharing the same CPU as this one</summary>
335 /// <remarks>"Full Sims" appear to be 1, Homesteads appear to be 4</remarks>
336 public int CPURatio;
337 /// <summary>The billing product name</summary>
338 /// <remarks>Known values are:
339 /// <list type="table">
340 /// <item>Mainland / Full Region (Sku: 023)</item>
341 /// <item>Estate / Full Region (Sku: 024)</item>
342 /// <item>Estate / Openspace (Sku: 027)</item>
343 /// <item>Estate / Homestead (Sku: 029)</item>
344 /// <item>Mainland / Homestead (Sku: 129) (Linden Owned)</item>
345 /// <item>Mainland / Linden Homes (Sku: 131)</item>
346 /// </list>
347 /// </remarks>
348 public string ProductName;
349 /// <summary>The billing product SKU</summary>
350 /// <remarks>Known values are:
351 /// <list type="table">
352 /// <item>023 Mainland / Full Region</item>
353 /// <item>024 Estate / Full Region</item>
354 /// <item>027 Estate / Openspace</item>
355 /// <item>029 Estate / Homestead</item>
356 /// <item>129 Mainland / Homestead (Linden Owned)</item>
357 /// <item>131 Linden Homes / Full Region</item>
358 /// </list>
359 /// </remarks>
360 public string ProductSku;
361  
362 /// <summary>
363 /// Flags indicating which protocols this region supports
364 /// </summary>
365 public RegionProtocols Protocols;
366  
367  
368 /// <summary>The current sequence number for packets sent to this
369 /// simulator. Must be Interlocked before modifying. Only
370 /// useful for applications manipulating sequence numbers</summary>
371 public int Sequence;
372  
373 /// <summary>
374 /// A thread-safe dictionary containing avatars in a simulator
375 /// </summary>
376 public InternalDictionary<uint, Avatar> ObjectsAvatars = new InternalDictionary<uint, Avatar>();
377  
378 /// <summary>
379 /// A thread-safe dictionary containing primitives in a simulator
380 /// </summary>
381 public InternalDictionary<uint, Primitive> ObjectsPrimitives = new InternalDictionary<uint, Primitive>();
382  
383 public readonly TerrainPatch[] Terrain;
384  
385 public readonly Vector2[] WindSpeeds;
386  
387 /// <summary>
388 /// Provides access to an internal thread-safe dictionary containing parcel
389 /// information found in this simulator
390 /// </summary>
391 public InternalDictionary<int, Parcel> Parcels
392 {
393 get
394 {
395 if (Client.Settings.POOL_PARCEL_DATA)
396 {
397 return DataPool.Parcels;
398 }
399 if (_Parcels == null) _Parcels = new InternalDictionary<int, Parcel>();
400 return _Parcels;
401 }
402 }
403 private InternalDictionary<int, Parcel> _Parcels;
404  
405 /// <summary>
406 /// Provides access to an internal thread-safe multidimensional array containing a x,y grid mapped
407 /// to each 64x64 parcel's LocalID.
408 /// </summary>
409 public int[,] ParcelMap
410 {
411 get
412 {
413 lock (this)
414 {
415 if (Client.Settings.POOL_PARCEL_DATA)
416 {
417 return DataPool.ParcelMap;
418 }
419 if (_ParcelMap == null) _ParcelMap = new int[64, 64];
420 return _ParcelMap;
421 }
422 }
423 }
424  
425 /// <summary>
426 /// Checks simulator parcel map to make sure it has downloaded all data successfully
427 /// </summary>
428 /// <returns>true if map is full (contains no 0's)</returns>
429 public bool IsParcelMapFull()
430 {
431 for (int y = 0; y < 64; y++)
432 {
433 for (int x = 0; x < 64; x++)
434 {
435 if (this.ParcelMap[y, x] == 0)
436 return false;
437 }
438 }
439 return true;
440 }
441  
442 /// <summary>
443 /// Is it safe to send agent updates to this sim
444 /// AgentMovementComplete message received
445 /// </summary>
446 public bool AgentMovementComplete;
447  
448 #endregion Public Members
449  
450 #region Properties
451  
452 /// <summary>The IP address and port of the server</summary>
453 public IPEndPoint IPEndPoint { get { return remoteEndPoint; } }
454 /// <summary>Whether there is a working connection to the simulator or
455 /// not</summary>
456 public bool Connected { get { return connected; } }
457 /// <summary>Coarse locations of avatars in this simulator</summary>
458 public InternalDictionary<UUID, Vector3> AvatarPositions { get { return avatarPositions; } }
459 /// <summary>AvatarPositions key representing TrackAgent target</summary>
460 public UUID PreyID { get { return preyID; } }
461 /// <summary>Indicates if UDP connection to the sim is fully established</summary>
462 public bool HandshakeComplete { get { return handshakeComplete; } }
463  
464 #endregion Properties
465  
466 #region Internal/Private Members
467 /// <summary>Used internally to track sim disconnections</summary>
468 internal bool DisconnectCandidate = false;
469 /// <summary>Event that is triggered when the simulator successfully
470 /// establishes a connection</summary>
471 internal ManualResetEvent ConnectedEvent = new ManualResetEvent(false);
472 /// <summary>Whether this sim is currently connected or not. Hooked up
473 /// to the property Connected</summary>
474 internal bool connected;
475 /// <summary>Coarse locations of avatars in this simulator</summary>
476 internal InternalDictionary<UUID, Vector3> avatarPositions = new InternalDictionary<UUID, Vector3>();
477 /// <summary>AvatarPositions key representing TrackAgent target</summary>
478 internal UUID preyID = UUID.Zero;
479 /// <summary>Sequence numbers of packets we've received
480 /// (for duplicate checking)</summary>
481 internal IncomingPacketIDCollection PacketArchive;
482 /// <summary>Packets we sent out that need ACKs from the simulator</summary>
483 internal SortedDictionary<uint, NetworkManager.OutgoingPacket> NeedAck = new SortedDictionary<uint, NetworkManager.OutgoingPacket>();
484 /// <summary>Sequence number for pause/resume</summary>
485 internal int pauseSerial;
486 /// <summary>Indicates if UDP connection to the sim is fully established</summary>
487 internal bool handshakeComplete;
488  
489 private NetworkManager Network;
490 private Queue<long> InBytes, OutBytes;
491 // ACKs that are queued up to be sent to the simulator
492 private LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>();
493 private Timer AckTimer;
494 private Timer PingTimer;
495 private Timer StatsTimer;
496 // simulator <> parcel LocalID Map
497 private int[,] _ParcelMap;
498 public readonly SimulatorDataPool DataPool;
499 internal bool DownloadingParcelMap
500 {
501 get
502 {
503 return Client.Settings.POOL_PARCEL_DATA ? DataPool.DownloadingParcelMap : _DownloadingParcelMap;
504 }
505 set
506 {
507 if (Client.Settings.POOL_PARCEL_DATA) DataPool.DownloadingParcelMap = value;
508 _DownloadingParcelMap = value;
509 }
510 }
511  
512 internal bool _DownloadingParcelMap = false;
513  
514  
515 private ManualResetEvent GotUseCircuitCodeAck = new ManualResetEvent(false);
516 #endregion Internal/Private Members
517  
518 /// <summary>
519 ///
520 /// </summary>
521 /// <param name="client">Reference to the GridClient object</param>
522 /// <param name="address">IPEndPoint of the simulator</param>
523 /// <param name="handle">handle of the simulator</param>
524 public Simulator(GridClient client, IPEndPoint address, ulong handle)
525 : base(address)
526 {
527 Client = client;
528 if (Client.Settings.POOL_PARCEL_DATA || Client.Settings.CACHE_PRIMITIVES)
529 {
530 SimulatorDataPool.SimulatorAdd(this);
531 DataPool = SimulatorDataPool.GetSimulatorData(Handle);
532 }
533  
534 Handle = handle;
535 Network = Client.Network;
536 PacketArchive = new IncomingPacketIDCollection(Settings.PACKET_ARCHIVE_SIZE);
537 InBytes = new Queue<long>(Client.Settings.STATS_QUEUE_SIZE);
538 OutBytes = new Queue<long>(Client.Settings.STATS_QUEUE_SIZE);
539  
540 if (client.Settings.STORE_LAND_PATCHES)
541 {
542 Terrain = new TerrainPatch[16 * 16];
543 WindSpeeds = new Vector2[16 * 16];
544 }
545 }
546  
547 /// <summary>
548 /// Called when this Simulator object is being destroyed
549 /// </summary>
550 public void Dispose()
551 {
552 Dispose(true);
553 GC.SuppressFinalize(this);
554 }
555  
556 public virtual void Dispose(bool disposing)
557 {
558 if (disposing)
559 {
560 if (AckTimer != null)
561 AckTimer.Dispose();
562 if (PingTimer != null)
563 PingTimer.Dispose();
564 if (StatsTimer != null)
565 StatsTimer.Dispose();
566 if (ConnectedEvent != null)
567 ConnectedEvent.Close();
568  
569 // Force all the CAPS connections closed for this simulator
570 if (Caps != null)
571 Caps.Disconnect(true);
572 }
573 }
574  
575 /// <summary>
576 /// Attempt to connect to this simulator
577 /// </summary>
578 /// <param name="moveToSim">Whether to move our agent in to this sim or not</param>
579 /// <returns>True if the connection succeeded or connection status is
580 /// unknown, false if there was a failure</returns>
581 public bool Connect(bool moveToSim)
582 {
583 handshakeComplete = false;
584  
585 if (connected)
586 {
587 UseCircuitCode(true);
588 if (moveToSim) Client.Self.CompleteAgentMovement(this);
589 return true;
590 }
591  
592 #region Start Timers
593  
594 // Timer for sending out queued packet acknowledgements
595 if (AckTimer == null)
596 AckTimer = new Timer(AckTimer_Elapsed, null, Settings.NETWORK_TICK_INTERVAL, Timeout.Infinite);
597  
598 // Timer for recording simulator connection statistics
599 if (StatsTimer == null)
600 StatsTimer = new Timer(StatsTimer_Elapsed, null, 1000, 1000);
601  
602 // Timer for periodically pinging the simulator
603 if (PingTimer == null && Client.Settings.SEND_PINGS)
604 PingTimer = new Timer(PingTimer_Elapsed, null, Settings.PING_INTERVAL, Settings.PING_INTERVAL);
605  
606 #endregion Start Timers
607  
608 Logger.Log("Connecting to " + this.ToString(), Helpers.LogLevel.Info, Client);
609  
610 try
611 {
612 // Create the UDP connection
613 Start();
614  
615 // Mark ourselves as connected before firing everything else up
616 connected = true;
617  
618 // Initiate connection
619 UseCircuitCode(true);
620  
621 Stats.ConnectTime = Environment.TickCount;
622  
623 // Move our agent in to the sim to complete the connection
624 if (moveToSim) Client.Self.CompleteAgentMovement(this);
625  
626 if (!ConnectedEvent.WaitOne(Client.Settings.LOGIN_TIMEOUT, false))
627 {
628 Logger.Log("Giving up on waiting for RegionHandshake for " + this.ToString(),
629 Helpers.LogLevel.Warning, Client);
630 //Remove the simulator from the list, not useful if we haven't recieved the RegionHandshake
631 lock (Client.Network.Simulators) {
632 Client.Network.Simulators.Remove(this);
633 }
634 }
635  
636 if (Client.Settings.SEND_AGENT_THROTTLE)
637 Client.Throttle.Set(this);
638  
639 if (Client.Settings.SEND_AGENT_UPDATES)
640 Client.Self.Movement.SendUpdate(true, this);
641  
642 return true;
643 }
644 catch (Exception e)
645 {
646 Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e);
647 }
648  
649 return false;
650 }
651  
652 /// <summary>
653 /// Initiates connection to the simulator
654 /// </summary>
655 /// <param name="waitForAck">Should we block until ack for this packet is recieved</param>
656 public void UseCircuitCode(bool waitForAck)
657 {
658 // Send the UseCircuitCode packet to initiate the connection
659 UseCircuitCodePacket use = new UseCircuitCodePacket();
660 use.CircuitCode.Code = Network.CircuitCode;
661 use.CircuitCode.ID = Client.Self.AgentID;
662 use.CircuitCode.SessionID = Client.Self.SessionID;
663  
664 if (waitForAck)
665 {
666 GotUseCircuitCodeAck.Reset();
667 }
668  
669 // Send the initial packet out
670 SendPacket(use);
671  
672 if (waitForAck)
673 {
674 if (!GotUseCircuitCodeAck.WaitOne(Client.Settings.LOGIN_TIMEOUT, false))
675 {
676 Logger.Log("Failed to get ACK for UseCircuitCode packet", Helpers.LogLevel.Error, Client);
677 }
678 }
679 }
680  
681 public void SetSeedCaps(string seedcaps)
682 {
683 if (Caps != null)
684 {
685 if (Caps._SeedCapsURI == seedcaps) return;
686  
687 Logger.Log("Unexpected change of seed capability", Helpers.LogLevel.Warning, Client);
688 Caps.Disconnect(true);
689 Caps = null;
690 }
691  
692 if (Client.Settings.ENABLE_CAPS)
693 {
694 // Connect to the new CAPS system
695 if (!String.IsNullOrEmpty(seedcaps))
696 Caps = new Caps(this, seedcaps);
697 else
698 Logger.Log("Setting up a sim without a valid capabilities server!", Helpers.LogLevel.Error, Client);
699 }
700  
701 }
702  
703 /// <summary>
704 /// Disconnect from this simulator
705 /// </summary>
706 public void Disconnect(bool sendCloseCircuit)
707 {
708 if (connected)
709 {
710 connected = false;
711  
712 // Destroy the timers
713 if (AckTimer != null) AckTimer.Dispose();
714 if (StatsTimer != null) StatsTimer.Dispose();
715 if (PingTimer != null) PingTimer.Dispose();
716  
717 AckTimer = null;
718 StatsTimer = null;
719 PingTimer = null;
720  
721 // Kill the current CAPS system
722 if (Caps != null)
723 {
724 Caps.Disconnect(true);
725 Caps = null;
726 }
727  
728 if (sendCloseCircuit)
729 {
730 // Try to send the CloseCircuit notice
731 CloseCircuitPacket close = new CloseCircuitPacket();
732 UDPPacketBuffer buf = new UDPPacketBuffer(remoteEndPoint);
733 byte[] data = close.ToBytes();
734 Buffer.BlockCopy(data, 0, buf.Data, 0, data.Length);
735 buf.DataLength = data.Length;
736  
737 AsyncBeginSend(buf);
738 }
739  
740 if (Client.Settings.POOL_PARCEL_DATA || Client.Settings.CACHE_PRIMITIVES)
741 {
742 SimulatorDataPool.SimulatorRelease(this);
743 }
744  
745 // Shut the socket communication down
746 Stop();
747 }
748 }
749  
750 /// <summary>
751 /// Instructs the simulator to stop sending update (and possibly other) packets
752 /// </summary>
753 public void Pause()
754 {
755 AgentPausePacket pause = new AgentPausePacket();
756 pause.AgentData.AgentID = Client.Self.AgentID;
757 pause.AgentData.SessionID = Client.Self.SessionID;
758 pause.AgentData.SerialNum = (uint)Interlocked.Exchange(ref pauseSerial, pauseSerial + 1);
759  
760 Client.Network.SendPacket(pause, this);
761 }
762  
763 /// <summary>
764 /// Instructs the simulator to resume sending update packets (unpause)
765 /// </summary>
766 public void Resume()
767 {
768 AgentResumePacket resume = new AgentResumePacket();
769 resume.AgentData.AgentID = Client.Self.AgentID;
770 resume.AgentData.SessionID = Client.Self.SessionID;
771 resume.AgentData.SerialNum = (uint)Interlocked.Exchange(ref pauseSerial, pauseSerial + 1);
772  
773 Client.Network.SendPacket(resume, this);
774 }
775  
776 /// <summary>
777 /// Retrieve the terrain height at a given coordinate
778 /// </summary>
779 /// <param name="x">Sim X coordinate, valid range is from 0 to 255</param>
780 /// <param name="y">Sim Y coordinate, valid range is from 0 to 255</param>
781 /// <param name="height">The terrain height at the given point if the
782 /// lookup was successful, otherwise 0.0f</param>
783 /// <returns>True if the lookup was successful, otherwise false</returns>
784 public bool TerrainHeightAtPoint(int x, int y, out float height)
785 {
786 if (Terrain != null && x >= 0 && x < 256 && y >= 0 && y < 256)
787 {
788 int patchX = x / 16;
789 int patchY = y / 16;
790 x = x % 16;
791 y = y % 16;
792  
793 TerrainPatch patch = Terrain[patchY * 16 + patchX];
794 if (patch != null)
795 {
796 height = patch.Data[y * 16 + x];
797 return true;
798 }
799 }
800  
801 height = 0.0f;
802 return false;
803 }
804  
805 #region Packet Sending
806  
807 /// <summary>
808 /// Sends a packet
809 /// </summary>
810 /// <param name="packet">Packet to be sent</param>
811 public void SendPacket(Packet packet)
812 {
813 // DEBUG: This can go away after we are sure nothing in the library is trying to do this
814 if (packet.Header.AppendedAcks || (packet.Header.AckList != null && packet.Header.AckList.Length > 0))
815 Logger.Log("Attempting to send packet " + packet.Type + " with ACKs appended before serialization", Helpers.LogLevel.Error);
816  
817 if (packet.HasVariableBlocks)
818 {
819 byte[][] datas;
820 try { datas = packet.ToBytesMultiple(); }
821 catch (NullReferenceException)
822 {
823 Logger.Log("Failed to serialize " + packet.Type + " packet to one or more payloads due to a missing block or field. StackTrace: " +
824 Environment.StackTrace, Helpers.LogLevel.Error);
825 return;
826 }
827 int packetCount = datas.Length;
828  
829 if (packetCount > 1)
830 Logger.DebugLog("Split " + packet.Type + " packet into " + packetCount + " packets");
831  
832 for (int i = 0; i < packetCount; i++)
833 {
834 byte[] data = datas[i];
835 SendPacketData(data, data.Length, packet.Type, packet.Header.Zerocoded);
836 }
837 }
838 else
839 {
840 byte[] data = packet.ToBytes();
841 SendPacketData(data, data.Length, packet.Type, packet.Header.Zerocoded);
842 }
843 }
844  
845 public void SendPacketData(byte[] data, int dataLength, PacketType type, bool doZerocode)
846 {
847 UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndPoint, Packet.MTU);
848  
849 // Zerocode if needed
850 if (doZerocode)
851 {
852 try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); }
853 catch (IndexOutOfRangeException)
854 {
855 // The packet grew larger than Packet.MTU bytes while zerocoding.
856 // Remove the MSG_ZEROCODED flag and send the unencoded data
857 // instead
858 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
859 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
860 }
861 }
862 else
863 {
864 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
865 }
866 buffer.DataLength = dataLength;
867  
868 #region Queue or Send
869  
870 NetworkManager.OutgoingPacket outgoingPacket = new NetworkManager.OutgoingPacket(this, buffer, type);
871  
872 // Send ACK and logout packets directly, everything else goes through the queue
873 if (Client.Settings.THROTTLE_OUTGOING_PACKETS == false ||
874 type == PacketType.PacketAck ||
875 type == PacketType.LogoutRequest)
876 {
877 SendPacketFinal(outgoingPacket);
878 }
879 else
880 {
881 Network.PacketOutbox.Enqueue(outgoingPacket);
882 }
883  
884 #endregion Queue or Send
885  
886 #region Stats Tracking
887 if (Client.Settings.TRACK_UTILIZATION)
888 {
889 Client.Stats.Update(type.ToString(), OpenMetaverse.Stats.Type.Packet, dataLength, 0);
890 }
891 #endregion
892 }
893  
894 internal void SendPacketFinal(NetworkManager.OutgoingPacket outgoingPacket)
895 {
896 UDPPacketBuffer buffer = outgoingPacket.Buffer;
897 byte flags = buffer.Data[0];
898 bool isResend = (flags & Helpers.MSG_RESENT) != 0;
899 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
900  
901 // Keep track of when this packet was sent out (right now)
902 outgoingPacket.TickCount = Environment.TickCount;
903  
904 #region ACK Appending
905  
906 int dataLength = buffer.DataLength;
907  
908 // Keep appending ACKs until there is no room left in the packet or there are
909 // no more ACKs to append
910 uint ackCount = 0;
911 uint ack;
912 while (dataLength + 5 < Packet.MTU && PendingAcks.TryDequeue(out ack))
913 {
914 Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
915 dataLength += 4;
916 ++ackCount;
917 }
918  
919 if (ackCount > 0)
920 {
921 // Set the last byte of the packet equal to the number of appended ACKs
922 buffer.Data[dataLength++] = (byte)ackCount;
923 // Set the appended ACKs flag on this packet
924 buffer.Data[0] |= Helpers.MSG_APPENDED_ACKS;
925 }
926  
927 buffer.DataLength = dataLength;
928  
929 #endregion ACK Appending
930  
931 if (!isResend)
932 {
933 // Not a resend, assign a new sequence number
934 uint sequenceNumber = (uint)Interlocked.Increment(ref Sequence);
935 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
936 outgoingPacket.SequenceNumber = sequenceNumber;
937  
938 if (isReliable)
939 {
940 // Add this packet to the list of ACK responses we are waiting on from the server
941 lock (NeedAck) NeedAck[sequenceNumber] = outgoingPacket;
942 }
943 }
944  
945 // Put the UDP payload on the wire
946 AsyncBeginSend(buffer);
947 }
948  
949 /// <summary>
950 ///
951 /// </summary>
952 public void SendPing()
953 {
954 uint oldestUnacked = 0;
955  
956 // Get the oldest NeedAck value, the first entry in the sorted dictionary
957 lock (NeedAck)
958 {
959 if (NeedAck.Count > 0)
960 {
961 SortedDictionary<uint, NetworkManager.OutgoingPacket>.KeyCollection.Enumerator en = NeedAck.Keys.GetEnumerator();
962 en.MoveNext();
963 oldestUnacked = en.Current;
964 }
965 }
966  
967 //if (oldestUnacked != 0)
968 // Logger.DebugLog("Sending ping with oldestUnacked=" + oldestUnacked);
969  
970 StartPingCheckPacket ping = new StartPingCheckPacket();
971 ping.PingID.PingID = Stats.LastPingID++;
972 ping.PingID.OldestUnacked = oldestUnacked;
973 ping.Header.Reliable = false;
974 SendPacket(ping);
975 Stats.LastPingSent = Environment.TickCount;
976 }
977  
978 #endregion Packet Sending
979  
980 /// <summary>
981 /// Returns Simulator Name as a String
982 /// </summary>
983 /// <returns></returns>
984 public override string ToString()
985 {
986 if (!String.IsNullOrEmpty(Name))
987 return String.Format("{0} ({1})", Name, remoteEndPoint);
988 else
989 return String.Format("({0})", remoteEndPoint);
990 }
991  
992 /// <summary>
993 ///
994 /// </summary>
995 /// <returns></returns>
996 public override int GetHashCode()
997 {
998 return Handle.GetHashCode();
999 }
1000  
1001 /// <summary>
1002 ///
1003 /// </summary>
1004 /// <param name="obj"></param>
1005 /// <returns></returns>
1006 public override bool Equals(object obj)
1007 {
1008 Simulator sim = obj as Simulator;
1009 if (sim == null)
1010 return false;
1011 return (remoteEndPoint.Equals(sim.remoteEndPoint));
1012 }
1013  
1014 public static bool operator ==(Simulator lhs, Simulator rhs)
1015 {
1016 // If both are null, or both are same instance, return true
1017 if (System.Object.ReferenceEquals(lhs, rhs))
1018 {
1019 return true;
1020 }
1021  
1022 // If one is null, but not both, return false.
1023 if (((object)lhs == null) || ((object)rhs == null))
1024 {
1025 return false;
1026 }
1027  
1028 return lhs.remoteEndPoint.Equals(rhs.remoteEndPoint);
1029 }
1030  
1031 public static bool operator !=(Simulator lhs, Simulator rhs)
1032 {
1033 return !(lhs == rhs);
1034 }
1035  
1036 protected override void PacketReceived(UDPPacketBuffer buffer)
1037 {
1038 Packet packet = null;
1039  
1040 // Check if this packet came from the server we expected it to come from
1041 if (!remoteEndPoint.Address.Equals(((IPEndPoint)buffer.RemoteEndPoint).Address))
1042 {
1043 Logger.Log("Received " + buffer.DataLength + " bytes of data from unrecognized source " +
1044 ((IPEndPoint)buffer.RemoteEndPoint).ToString(), Helpers.LogLevel.Warning, Client);
1045 return;
1046 }
1047  
1048 // Update the disconnect flag so this sim doesn't time out
1049 DisconnectCandidate = false;
1050  
1051 #region Packet Decoding
1052  
1053 int packetEnd = buffer.DataLength - 1;
1054  
1055 try
1056 {
1057 packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
1058 // Only allocate a buffer for zerodecoding if the packet is zerocoded
1059 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[8192] : null);
1060 }
1061 catch (MalformedDataException)
1062 {
1063 Logger.Log(String.Format("Malformed data, cannot parse packet:\n{0}",
1064 Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)), Helpers.LogLevel.Error);
1065 }
1066  
1067 // Fail-safe check
1068 if (packet == null)
1069 {
1070 Logger.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning, Client);
1071 return;
1072 }
1073  
1074 Interlocked.Add(ref Stats.RecvBytes, buffer.DataLength);
1075 Interlocked.Increment(ref Stats.RecvPackets);
1076  
1077 #endregion Packet Decoding
1078  
1079 if (packet.Header.Resent)
1080 Interlocked.Increment(ref Stats.ReceivedResends);
1081  
1082 #region ACK Receiving
1083  
1084 // Handle appended ACKs
1085 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1086 {
1087 lock (NeedAck)
1088 {
1089 for (int i = 0; i < packet.Header.AckList.Length; i++)
1090 {
1091 if (NeedAck.ContainsKey(packet.Header.AckList[i]) && NeedAck[packet.Header.AckList[i]].Type == PacketType.UseCircuitCode)
1092 {
1093 GotUseCircuitCodeAck.Set();
1094 }
1095 NeedAck.Remove(packet.Header.AckList[i]);
1096 }
1097 }
1098 }
1099  
1100 // Handle PacketAck packets
1101 if (packet.Type == PacketType.PacketAck)
1102 {
1103 PacketAckPacket ackPacket = (PacketAckPacket)packet;
1104  
1105 lock (NeedAck)
1106 {
1107 for (int i = 0; i < ackPacket.Packets.Length; i++)
1108 {
1109 if (NeedAck.ContainsKey(ackPacket.Packets[i].ID) && NeedAck[ackPacket.Packets[i].ID].Type == PacketType.UseCircuitCode)
1110 {
1111 GotUseCircuitCodeAck.Set();
1112 }
1113 NeedAck.Remove(ackPacket.Packets[i].ID);
1114 }
1115 }
1116 }
1117  
1118 #endregion ACK Receiving
1119  
1120 if (packet.Header.Reliable)
1121 {
1122 #region ACK Sending
1123  
1124 // Add this packet to the list of ACKs that need to be sent out
1125 uint sequence = (uint)packet.Header.Sequence;
1126 PendingAcks.Enqueue(sequence);
1127  
1128 // Send out ACKs if we have a lot of them
1129 if (PendingAcks.Count >= Client.Settings.MAX_PENDING_ACKS)
1130 SendAcks();
1131  
1132 #endregion ACK Sending
1133  
1134 // Check the archive of received packet IDs to see whether we already received this packet
1135 if (!PacketArchive.TryEnqueue(packet.Header.Sequence))
1136 {
1137 if (packet.Header.Resent)
1138 Logger.DebugLog(
1139 string.Format(
1140 "Received a resend of already processed packet #{0}, type: {1} from {2}",
1141 packet.Header.Sequence, packet.Type, Name));
1142 else
1143 Logger.Log(
1144 string.Format(
1145 "Received a duplicate (not marked as resend) of packet #{0}, type: {1} for {2} from {3}",
1146 packet.Header.Sequence, packet.Type, Client.Self.Name, Name),
1147 Helpers.LogLevel.Warning);
1148  
1149 // Avoid firing a callback twice for the same packet
1150 return;
1151 }
1152 }
1153  
1154 #region Inbox Insertion
1155  
1156 NetworkManager.IncomingPacket incomingPacket;
1157 incomingPacket.Simulator = this;
1158 incomingPacket.Packet = packet;
1159  
1160 Network.PacketInbox.Enqueue(incomingPacket);
1161  
1162 #endregion Inbox Insertion
1163  
1164 #region Stats Tracking
1165 if (Client.Settings.TRACK_UTILIZATION)
1166 {
1167 Client.Stats.Update(packet.Type.ToString(), OpenMetaverse.Stats.Type.Packet, 0, packet.Length);
1168 }
1169 #endregion
1170 }
1171  
1172 protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent)
1173 {
1174 // Stats tracking
1175 Interlocked.Add(ref Stats.SentBytes, bytesSent);
1176 Interlocked.Increment(ref Stats.SentPackets);
1177  
1178 Client.Network.RaisePacketSentEvent(buffer.Data, bytesSent, this);
1179 }
1180  
1181  
1182 /// <summary>
1183 /// Sends out pending acknowledgements
1184 /// </summary>
1185 /// <returns>Number of ACKs sent</returns>
1186 private int SendAcks()
1187 {
1188 uint ack;
1189 int ackCount = 0;
1190  
1191 if (PendingAcks.TryDequeue(out ack))
1192 {
1193 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
1194 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
1195 block.ID = ack;
1196 blocks.Add(block);
1197  
1198 while (PendingAcks.TryDequeue(out ack))
1199 {
1200 block = new PacketAckPacket.PacketsBlock();
1201 block.ID = ack;
1202 blocks.Add(block);
1203 }
1204  
1205 PacketAckPacket packet = new PacketAckPacket();
1206 packet.Header.Reliable = false;
1207 packet.Packets = blocks.ToArray();
1208  
1209 ackCount = blocks.Count;
1210 SendPacket(packet);
1211 }
1212  
1213 return ackCount;
1214 }
1215  
1216 /// <summary>
1217 /// Resend unacknowledged packets
1218 /// </summary>
1219 private void ResendUnacked()
1220 {
1221 if (NeedAck.Count > 0)
1222 {
1223 NetworkManager.OutgoingPacket[] array;
1224  
1225 lock (NeedAck)
1226 {
1227 // Create a temporary copy of the outgoing packets array to iterate over
1228 array = new NetworkManager.OutgoingPacket[NeedAck.Count];
1229 NeedAck.Values.CopyTo(array, 0);
1230 }
1231  
1232 int now = Environment.TickCount;
1233  
1234 // Resend packets
1235 for (int i = 0; i < array.Length; i++)
1236 {
1237 NetworkManager.OutgoingPacket outgoing = array[i];
1238  
1239 if (outgoing.TickCount != 0 && now - outgoing.TickCount > Client.Settings.RESEND_TIMEOUT)
1240 {
1241 if (outgoing.ResendCount < Client.Settings.MAX_RESEND_COUNT)
1242 {
1243 if (Client.Settings.LOG_RESENDS)
1244 {
1245 Logger.DebugLog(String.Format("Resending {2} packet #{0}, {1}ms have passed",
1246 outgoing.SequenceNumber, now - outgoing.TickCount, outgoing.Type), Client);
1247 }
1248  
1249 // The TickCount will be set to the current time when the packet
1250 // is actually sent out again
1251 outgoing.TickCount = 0;
1252  
1253 // Set the resent flag
1254 outgoing.Buffer.Data[0] = (byte)(outgoing.Buffer.Data[0] | Helpers.MSG_RESENT);
1255  
1256 // Stats tracking
1257 Interlocked.Increment(ref outgoing.ResendCount);
1258 Interlocked.Increment(ref Stats.ResentPackets);
1259  
1260 SendPacketFinal(outgoing);
1261 }
1262 else
1263 {
1264 Logger.DebugLog(String.Format("Dropping packet #{0} after {1} failed attempts",
1265 outgoing.SequenceNumber, outgoing.ResendCount));
1266  
1267 lock (NeedAck) NeedAck.Remove(outgoing.SequenceNumber);
1268 }
1269 }
1270 }
1271 }
1272 }
1273  
1274 private void AckTimer_Elapsed(object obj)
1275 {
1276 SendAcks();
1277 ResendUnacked();
1278  
1279 // Start the ACK handling functions again after NETWORK_TICK_INTERVAL milliseconds
1280 if (null == AckTimer) return;
1281 try { AckTimer.Change(Settings.NETWORK_TICK_INTERVAL, Timeout.Infinite); }
1282 catch (Exception) { }
1283 }
1284  
1285 private void StatsTimer_Elapsed(object obj)
1286 {
1287 long old_in = 0, old_out = 0;
1288 long recv = Stats.RecvBytes;
1289 long sent = Stats.SentBytes;
1290  
1291 if (InBytes.Count >= Client.Settings.STATS_QUEUE_SIZE)
1292 old_in = InBytes.Dequeue();
1293 if (OutBytes.Count >= Client.Settings.STATS_QUEUE_SIZE)
1294 old_out = OutBytes.Dequeue();
1295  
1296 InBytes.Enqueue(recv);
1297 OutBytes.Enqueue(sent);
1298  
1299 if (old_in > 0 && old_out > 0)
1300 {
1301 Stats.IncomingBPS = (int)(recv - old_in) / Client.Settings.STATS_QUEUE_SIZE;
1302 Stats.OutgoingBPS = (int)(sent - old_out) / Client.Settings.STATS_QUEUE_SIZE;
1303 //Client.Log("Incoming: " + IncomingBPS + " Out: " + OutgoingBPS +
1304 // " Lag: " + LastLag + " Pings: " + ReceivedPongs +
1305 // "/" + SentPings, Helpers.LogLevel.Debug);
1306 }
1307 }
1308  
1309 private void PingTimer_Elapsed(object obj)
1310 {
1311 SendPing();
1312 Interlocked.Increment(ref Stats.SentPings);
1313 }
1314 }
1315  
1316 public sealed class IncomingPacketIDCollection
1317 {
1318 readonly uint[] Items;
1319 HashSet<uint> hashSet;
1320 int first;
1321 int next;
1322 int capacity;
1323  
1324 public IncomingPacketIDCollection(int capacity)
1325 {
1326 this.capacity = capacity;
1327 Items = new uint[capacity];
1328 hashSet = new HashSet<uint>();
1329 }
1330  
1331 public bool TryEnqueue(uint ack)
1332 {
1333 lock (hashSet)
1334 {
1335 if (hashSet.Add(ack))
1336 {
1337 Items[next] = ack;
1338 next = (next + 1) % capacity;
1339 if (next == first)
1340 {
1341 hashSet.Remove(Items[first]);
1342 first = (first + 1) % capacity;
1343 }
1344  
1345 return true;
1346 }
1347 }
1348  
1349 return false;
1350 }
1351 }
1352  
1353 public class SimulatorDataPool
1354 {
1355 private static Timer InactiveSimReaper;
1356  
1357 private static void RemoveOldSims(object state)
1358 {
1359 lock (SimulatorDataPools)
1360 {
1361 int SimTimeout = Settings.SIMULATOR_POOL_TIMEOUT;
1362 List<ulong> reap = new List<ulong>();
1363 foreach (var pool in SimulatorDataPools.Values)
1364 {
1365 if (pool.InactiveSince != DateTime.MaxValue && pool.InactiveSince.AddMilliseconds(SimTimeout) < DateTime.Now)
1366 {
1367 reap.Add(pool.Handle);
1368 }
1369 }
1370 foreach (var hndl in reap)
1371 {
1372 SimulatorDataPools.Remove(hndl);
1373 }
1374 }
1375 }
1376  
1377 public static void SimulatorAdd(Simulator sim)
1378 {
1379 lock (SimulatorDataPools)
1380 {
1381 if (InactiveSimReaper == null)
1382 {
1383 InactiveSimReaper = new Timer(RemoveOldSims, null, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3));
1384 }
1385 SimulatorDataPool pool = GetSimulatorData(sim.Handle);
1386 if (pool.ActiveClients < 1) pool.ActiveClients = 1; else pool.ActiveClients++;
1387 pool.InactiveSince = DateTime.MaxValue;
1388 }
1389 }
1390 public static void SimulatorRelease(Simulator sim)
1391 {
1392 ulong hndl = sim.Handle;
1393 lock (SimulatorDataPools)
1394 {
1395 SimulatorDataPool dataPool = GetSimulatorData(hndl);
1396 dataPool.ActiveClients--;
1397 if (dataPool.ActiveClients <= 0)
1398 {
1399 dataPool.InactiveSince = DateTime.Now;
1400 }
1401 }
1402 }
1403  
1404 static public Dictionary<ulong, SimulatorDataPool> SimulatorDataPools = new Dictionary<ulong, SimulatorDataPool>();
1405  
1406 /// <summary>
1407 /// Simulator handle
1408 /// </summary>
1409 readonly public ulong Handle;
1410 /// <summary>
1411 /// Number of GridClients using this datapool
1412 /// </summary>
1413 public int ActiveClients;
1414 /// <summary>
1415 /// Time that the last client disconnected from the simulator
1416 /// </summary>
1417 public DateTime InactiveSince = DateTime.MaxValue;
1418  
1419 #region Pooled Items
1420 /// <summary>
1421 /// The cache of prims used and unused in this simulator
1422 /// </summary>
1423 public Dictionary<uint, Primitive> PrimCache = new Dictionary<uint, Primitive>();
1424  
1425 /// <summary>
1426 /// Shared parcel info only when POOL_PARCEL_DATA == true
1427 /// </summary>
1428 public InternalDictionary<int, Parcel> Parcels = new InternalDictionary<int, Parcel>();
1429 public int[,] ParcelMap = new int[64, 64];
1430 public bool DownloadingParcelMap = false;
1431  
1432 #endregion Pooled Items
1433  
1434 private SimulatorDataPool(ulong hndl)
1435 {
1436 this.Handle = hndl;
1437 }
1438  
1439 public static SimulatorDataPool GetSimulatorData(ulong hndl)
1440 {
1441 SimulatorDataPool dict;
1442 lock (SimulatorDataPools)
1443 {
1444 if (!SimulatorDataPools.TryGetValue(hndl, out dict))
1445 {
1446 dict = SimulatorDataPools[hndl] = new SimulatorDataPool(hndl);
1447 }
1448 }
1449 return dict;
1450 }
1451 #region Factories
1452 internal Primitive MakePrimitive(uint localID)
1453 {
1454 var dict = PrimCache;
1455 lock (dict)
1456 {
1457 Primitive prim;
1458 if (!dict.TryGetValue(localID, out prim))
1459 {
1460 dict[localID] = prim = new Primitive { RegionHandle = Handle, LocalID = localID };
1461 }
1462 return prim;
1463 }
1464 }
1465  
1466 internal bool NeedsRequest(uint localID)
1467 {
1468 var dict = PrimCache;
1469 lock (dict) return !dict.ContainsKey(localID);
1470 }
1471 #endregion Factories
1472  
1473 internal void ReleasePrims(List<uint> removePrims)
1474 {
1475 lock (PrimCache)
1476 {
1477 foreach (uint u in removePrims)
1478 {
1479 Primitive prim;
1480 if (PrimCache.TryGetValue(u, out prim)) prim.ActiveClients--;
1481 }
1482 }
1483 }
1484 }
1485 }