corrade-vassal – Blame information for rev 7

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 zed 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
3 // Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
4 // rights of fair usage, the disclaimer and warranty conditions. //
5 ///////////////////////////////////////////////////////////////////////////
6  
7 using System;
8 using System.Collections;
9 using System.Collections.Generic;
10 using System.ComponentModel;
11 using System.Data;
12 using System.Drawing;
7 zed 13 using System.Drawing.Imaging;
2 zed 14 using System.IO;
15 using System.Linq;
16 using System.Net;
7 zed 17 using System.Net.Sockets;
2 zed 18 using System.Reflection;
19 using System.Text;
20 using System.Text.RegularExpressions;
21 using System.Timers;
22 using System.Threading;
23 using System.Web;
24 using System.Windows.Forms;
25 using OpenMetaverse;
26 using Parallel = System.Threading.Tasks.Parallel;
27 using Timer = System.Timers.Timer;
28  
29 namespace Vassal
30 {
31 public partial class Vassal : Form
32 {
33 public static System.Timers.Timer overviewTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
7 zed 34 public static System.Timers.Timer residentListTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
2 zed 35 public static System.Timers.Timer topScriptsTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
36 public static System.Timers.Timer topCollidersTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
7 zed 37 public static System.Timers.Timer regionsStateTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
38 public static volatile int regionsStateCheckIndex = 0;
2 zed 39 public static VassalConfiguration vassalConfiguration = new VassalConfiguration();
40 public static Vassal vassalForm;
41 public static readonly object ClientInstanceTeleportLock = new object();
7 zed 42 public static readonly object RegionsStateCheckLock = new object();
2 zed 43  
7 zed 44 /// <summary>
45 /// Linden constants.
46 /// </summary>
47 public struct LINDEN_CONSTANTS
48 {
49 public struct ALERTS
50 {
51 public const string NO_ROOM_TO_SIT_HERE = @"No room to sit here, try another spot.";
52  
53 public const string UNABLE_TO_SET_HOME =
54 @"You can only set your 'Home Location' on your land or at a mainland Infohub.";
55  
56 public const string HOME_SET = @"Home position set.";
57 }
58  
59 public struct ASSETS
60 {
61 public struct NOTECARD
62 {
63 public const string NEWLINE = "\n";
64 public const uint MAXIMUM_BODY_LENTH = 65536;
65 }
66 }
67  
68 public struct AVATARS
69 {
70 public const uint SET_DISPLAY_NAME_SUCCESS = 200;
71 public const string LASTNAME_PLACEHOLDER = @"Resident";
72 public const uint MAXIMUM_DISPLAY_NAME_CHARACTERS = 31;
73 public const uint MINIMUM_DISPLAY_NAME_CHARACTERS = 1;
74 public const uint MAXIMUM_NUMBER_OF_ATTACHMENTS = 38;
75  
76 public struct PROFILE
77 {
78 public const uint SECOND_LIFE_TEXT_SIZE = 510;
79 public const uint FIRST_LIFE_TEXT_SIZE = 253;
80 }
81  
82 public struct PICKS
83 {
84 public const uint MAXIMUM_PICKS = 10;
85 public const uint MAXIMUM_PICK_DESCRIPTION_SIZE = 1022;
86 }
87  
88 public struct CLASSIFIEDS
89 {
90 public const uint MAXIMUM_CLASSIFIEDS = 100;
91 }
92 }
93  
94 public struct PRIMITIVES
95 {
96 public const uint MAXIMUM_NAME_SIZE = 63;
97 public const uint MAXIMUM_DESCRIPTION_SIZE = 127;
98 public const double MAXIMUM_REZ_HEIGHT = 4096.0;
99 public const double MINIMUM_SIZE_X = 0.01;
100 public const double MINIMUM_SIZE_Y = 0.01;
101 public const double MINIMUM_SIZE_Z = 0.01;
102 public const double MAXIMUM_SIZE_X = 64.0;
103 public const double MAXIMUM_SIZE_Y = 64.0;
104 public const double MAXIMUM_SIZE_Z = 64.0;
105 }
106  
107 public struct OBJECTS
108 {
109 public const uint MAXIMUM_PRIMITIVE_COUNT = 256;
110 }
111  
112 public struct DIRECTORY
113 {
114 public struct EVENT
115 {
116 public const uint SEARCH_RESULTS_COUNT = 200;
117 }
118  
119 public struct GROUP
120 {
121 public const uint SEARCH_RESULTS_COUNT = 100;
122 }
123  
124 public struct LAND
125 {
126 public const uint SEARCH_RESULTS_COUNT = 100;
127 }
128  
129 public struct PEOPLE
130 {
131 public const uint SEARCH_RESULTS_COUNT = 100;
132 }
133 }
134  
135 public struct ESTATE
136 {
137 public const uint REGION_RESTART_DELAY = 120;
138 public const uint MAXIMUM_BAN_LIST_LENGTH = 500;
139 public const uint MAXIMUM_GROUP_LIST_LENGTH = 63;
140 public const uint MAXIMUM_USER_LIST_LENGTH = 500;
141 public const uint MAXIMUM_MANAGER_LIST_LENGTH = 10;
142  
143 public struct MESSAGES
144 {
145 public const string REGION_RESTART_MESSAGE = @"restart";
146 }
147 }
148  
149 public struct PARCELS
150 {
151 public const double MAXIMUM_AUTO_RETURN_TIME = 999999;
152 public const uint MINIMUM_AUTO_RETURN_TIME = 0;
153 public const uint MAXIMUM_NAME_LENGTH = 63;
154 public const uint MAXIMUM_DESCRIPTION_LENGTH = 255;
155 }
156  
157 public struct GRID
158 {
159 public const string SECOND_LIFE = @"Second Life";
160 public const string TIME_ZONE = @"Pacific Standard Time";
161 }
162  
163 public struct CHAT
164 {
165 public const uint MAXIMUM_MESSAGE_LENGTH = 1024;
166 }
167  
168 public struct GROUPS
169 {
170 public const uint MAXIMUM_NUMBER_OF_ROLES = 10;
171 public const string EVERYONE_ROLE_NAME = @"Everyone";
172 public const uint MAXIMUM_GROUP_NAME_LENGTH = 35;
173 public const uint MAXIMUM_GROUP_TITLE_LENGTH = 20;
174 }
175  
176 public struct NOTICES
177 {
178 public const uint MAXIMUM_NOTICE_MESSAGE_LENGTH = 512;
179 }
180  
181 public struct LSL
182 {
183 public const string CSV_DELIMITER = @", ";
184 public const float SENSOR_RANGE = 96;
185 public const string DATE_TIME_STAMP = @"yyy-MM-ddTHH:mm:ss.ffffffZ";
186 }
187  
188 public struct REGION
189 {
190 public const float TELEPORT_MINIMUM_DISTANCE = 1;
191 public const float DEFAULT_AGENT_LIMIT = 40;
192 public const float DEFAULT_OBJECT_BONUS = 1;
193 public const bool DEFAULT_FIXED_SUN = false;
194 public const float DEFAULT_TERRAIN_LOWER_LIMIT = -4;
195 public const float DEFAULT_TERRAIN_RAISE_LIMIT = 4;
196 public const bool DEFAULT_USE_ESTATE_SUN = true;
197 public const float DEFAULT_WATER_HEIGHT = 20;
198 public const float SUNRISE = 6;
199 }
200  
201 public struct VIEWER
202 {
203 public const float MAXIMUM_DRAW_DISTANCE = 4096;
204 }
205  
206 public struct TELEPORTS
207 {
208 public struct THROTTLE
209 {
210 public const uint MAX_TELEPORTS = 10;
211 public const uint GRACE_SECONDS = 15;
212 }
213 }
214 }
215  
2 zed 216 ///////////////////////////////////////////////////////////////////////////
217 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
218 ///////////////////////////////////////////////////////////////////////////
7 zed 219 private static double wasMapValueToRange(double value, double xMin, double xMax, double yMin, double yMax)
220 {
221 return yMin + (
222 (
223 yMax - yMin
224 )
225 *
226 (
227 value - xMin
228 )
229 /
230 (
231 xMax - xMin
232 )
233 );
234 }
235  
236 ///////////////////////////////////////////////////////////////////////////
237 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
238 ///////////////////////////////////////////////////////////////////////////
2 zed 239 /// <summary>RFC1738 URL Escapes a string</summary>
240 /// <param name="data">a string to escape</param>
241 /// <returns>an RFC1738 escaped string</returns>
242 private static string wasURLEscapeDataString(string data)
243 {
244 return HttpUtility.UrlEncode(data);
245 }
246  
247 ///////////////////////////////////////////////////////////////////////////
248 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
249 ///////////////////////////////////////////////////////////////////////////
250 /// <summary>RFC1738 URL Unescape a string</summary>
251 /// <param name="data">a string to unescape</param>
252 /// <returns>an RFC1738 unescaped string</returns>
253 private static string wasURLUnescapeDataString(string data)
254 {
255 return HttpUtility.UrlDecode(data);
256 }
257  
258 ///////////////////////////////////////////////////////////////////////////
259 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
260 ///////////////////////////////////////////////////////////////////////////
261 /// <summary>URI unescapes an RFC3986 URI escaped string</summary>
262 /// <param name="data">a string to unescape</param>
263 /// <returns>the resulting string</returns>
264 private static string wasURIUnescapeDataString(string data)
265 {
266 // Uri.UnescapeDataString can only handle 32766 characters at a time
267 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766)
268 .Select(o => Uri.UnescapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766)))))
269 .ToArray());
270 }
271  
272 ///////////////////////////////////////////////////////////////////////////
273 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
274 ///////////////////////////////////////////////////////////////////////////
275 /// <summary>RFC3986 URI Escapes a string</summary>
276 /// <param name="data">a string to escape</param>
277 /// <returns>an RFC3986 escaped string</returns>
278 private static string wasURIEscapeDataString(string data)
279 {
280 // Uri.EscapeDataString can only handle 32766 characters at a time
281 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766)
282 .Select(o => Uri.EscapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766)))))
283 .ToArray());
284 }
285  
286 ///////////////////////////////////////////////////////////////////////////
287 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
288 ///////////////////////////////////////////////////////////////////////////
289 /// <summary>
290 /// Gets an array element at a given modulo index.
291 /// </summary>
292 /// <typeparam name="T">the array type</typeparam>
293 /// <param name="index">a positive or negative index of the element</param>
294 /// <param name="data">the array</param>
295 /// <return>an array element</return>
296 public static T wasGetElementAt<T>(T[] data, int index)
297 {
298 switch (index < 0)
299 {
300 case true:
301 return data[((index%data.Length) + data.Length)%data.Length];
302 default:
303 return data[index%data.Length];
304 }
305 }
306  
307 #region KEY-VALUE DATA
308  
309 ///////////////////////////////////////////////////////////////////////////
310 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
311 ///////////////////////////////////////////////////////////////////////////
312 /// <summary>
313 /// Returns the value of a key from a key-value data string.
314 /// </summary>
315 /// <param name="key">the key of the value</param>
316 /// <param name="data">the key-value data segment</param>
317 /// <returns>true if the key was found in data</returns>
318 private static string wasKeyValueGet(string key, string data)
319 {
320 return data.Split('&')
321 .AsParallel()
322 .Select(o => o.Split('=').ToList())
323 .Where(o => o.Count.Equals(2))
324 .Select(o => new
325 {
326 k = o.First(),
327 v = o.Last()
328 })
329 .Where(o => o.k.Equals(key))
330 .Select(o => o.v)
331 .FirstOrDefault();
332 }
333  
3 eva 334 #endregion
335  
2 zed 336 #region CRYPTOGRAPHY
337  
338 ///////////////////////////////////////////////////////////////////////////
339 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
340 ///////////////////////////////////////////////////////////////////////////
341 /// <summary>
342 /// Gets a sub-array from an array.
343 /// </summary>
344 /// <typeparam name="T">the array type</typeparam>
345 /// <param name="data">the array</param>
346 /// <param name="start">the start index</param>
347 /// <param name="stop">the stop index (-1 denotes the end)</param>
348 /// <returns>the array slice between start and stop</returns>
349 public static T[] wasGetSubArray<T>(T[] data, int start, int stop)
350 {
351 if (stop.Equals(-1))
352 stop = data.Length - 1;
353 T[] result = new T[stop - start + 1];
354 Array.Copy(data, start, result, 0, stop - start + 1);
355 return result;
356 }
357  
358 ///////////////////////////////////////////////////////////////////////////
359 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
360 ///////////////////////////////////////////////////////////////////////////
361 /// <summary>
362 /// Delete a sub-array and return the result.
363 /// </summary>
364 /// <typeparam name="T">the array type</typeparam>
365 /// <param name="data">the array</param>
366 /// <param name="start">the start index</param>
367 /// <param name="stop">the stop index (-1 denotes the end)</param>
368 /// <returns>the array without elements between start and stop</returns>
369 public static T[] wasDeleteSubArray<T>(T[] data, int start, int stop)
370 {
371 if (stop.Equals(-1))
372 stop = data.Length - 1;
373 T[] result = new T[data.Length - (stop - start) - 1];
374 Array.Copy(data, 0, result, 0, start);
375 Array.Copy(data, stop + 1, result, start, data.Length - stop - 1);
376 return result;
377 }
378  
379 ///////////////////////////////////////////////////////////////////////////
380 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
381 ///////////////////////////////////////////////////////////////////////////
382 /// <summary>
383 /// Concatenate multiple arrays.
384 /// </summary>
385 /// <typeparam name="T">the array type</typeparam>
386 /// <param name="arrays">multiple arrays</param>
387 /// <returns>a flat array with all arrays concatenated</returns>
388 public static T[] wasConcatenateArrays<T>(params T[][] arrays)
389 {
390 int resultLength = 0;
391 foreach (T[] o in arrays)
392 {
393 resultLength += o.Length;
394 }
395 T[] result = new T[resultLength];
396 int offset = 0;
397 for (int x = 0; x < arrays.Length; x++)
398 {
399 arrays[x].CopyTo(result, offset);
400 offset += arrays[x].Length;
401 }
402 return result;
403 }
404  
405 ///////////////////////////////////////////////////////////////////////////
406 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
407 ///////////////////////////////////////////////////////////////////////////
408 /// <summary>
409 /// Permutes an array in reverse a given number of times.
410 /// </summary>
411 /// <typeparam name="T">the array type</typeparam>
412 /// <param name="input">the array</param>
413 /// <param name="times">the number of times to permute</param>
414 /// <returns>the array with the elements permuted</returns>
415 private static T[] wasReversePermuteArrayElements<T>(T[] input, int times)
416 {
417 if (times.Equals(0)) return input;
418 T[] slice = new T[input.Length];
419 Array.Copy(input, 1, slice, 0, input.Length - 1);
420 Array.Copy(input, 0, slice, input.Length - 1, 1);
421 return wasReversePermuteArrayElements(slice, --times);
422 }
423  
424 ///////////////////////////////////////////////////////////////////////////
425 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
426 ///////////////////////////////////////////////////////////////////////////
427 /// <summary>
428 /// Permutes an array forward a given number of times.
429 /// </summary>
430 /// <typeparam name="T">the array type</typeparam>
431 /// <param name="input">the array</param>
432 /// <param name="times">the number of times to permute</param>
433 /// <returns>the array with the elements permuted</returns>
434 private static T[] wasForwardPermuteArrayElements<T>(T[] input, int times)
435 {
436 if (times.Equals(0)) return input;
437 T[] slice = new T[input.Length];
438 Array.Copy(input, input.Length - 1, slice, 0, 1);
439 Array.Copy(input, 0, slice, 1, input.Length - 1);
440 return wasForwardPermuteArrayElements(slice, --times);
441 }
442  
443 ///////////////////////////////////////////////////////////////////////////
444 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
445 ///////////////////////////////////////////////////////////////////////////
446 /// <summary>
447 /// Encrypt or decrypt a message given a set of rotors, plugs and a reflector.
448 /// </summary>
449 /// <param name="message">the message to encyrpt or decrypt</param>
450 /// <param name="rotors">any combination of: 1, 2, 3, 4, 5, 6, 7, 8, b, g</param>
451 /// <param name="plugs">the letter representing the start character for the rotor</param>
452 /// <param name="reflector">any one of: B, b, C, c</param>
453 /// <returns>either a decrypted or encrypted string</returns>
454 private static string wasEnigma(string message, char[] rotors, char[] plugs, char reflector)
455 {
456 Dictionary<char, char[]> def_rotors = new Dictionary<char, char[]>
457 {
458 {
459 '1', new[]
460 {
461 'e', 'k', 'm', 'f', 'l',
462 'g', 'd', 'q', 'v', 'z',
463 'n', 't', 'o', 'w', 'y',
464 'h', 'x', 'u', 's', 'p',
465 'a', 'i', 'b', 'r', 'c',
466 'j'
467 }
468 },
469 {
470 '2', new[]
471 {
472 'a', 'j', 'd', 'k', 's',
473 'i', 'r', 'u', 'x', 'b',
474 'l', 'h', 'w', 't', 'm',
475 'c', 'q', 'g', 'z', 'n',
476 'p', 'y', 'f', 'v', 'o',
477 'e'
478 }
479 },
480 {
481 '3', new[]
482 {
483 'b', 'd', 'f', 'h', 'j',
484 'l', 'c', 'p', 'r', 't',
485 'x', 'v', 'z', 'n', 'y',
486 'e', 'i', 'w', 'g', 'a',
487 'k', 'm', 'u', 's', 'q',
488 'o'
489 }
490 },
491 {
492 '4', new[]
493 {
494 'e', 's', 'o', 'v', 'p',
495 'z', 'j', 'a', 'y', 'q',
496 'u', 'i', 'r', 'h', 'x',
497 'l', 'n', 'f', 't', 'g',
498 'k', 'd', 'c', 'm', 'w',
499 'b'
500 }
501 },
502 {
503 '5', new[]
504 {
505 'v', 'z', 'b', 'r', 'g',
506 'i', 't', 'y', 'u', 'p',
507 's', 'd', 'n', 'h', 'l',
508 'x', 'a', 'w', 'm', 'j',
509 'q', 'o', 'f', 'e', 'c',
510 'k'
511 }
512 },
513 {
514 '6', new[]
515 {
516 'j', 'p', 'g', 'v', 'o',
517 'u', 'm', 'f', 'y', 'q',
518 'b', 'e', 'n', 'h', 'z',
519 'r', 'd', 'k', 'a', 's',
520 'x', 'l', 'i', 'c', 't',
521 'w'
522 }
523 },
524 {
525 '7', new[]
526 {
527 'n', 'z', 'j', 'h', 'g',
528 'r', 'c', 'x', 'm', 'y',
529 's', 'w', 'b', 'o', 'u',
530 'f', 'a', 'i', 'v', 'l',
531 'p', 'e', 'k', 'q', 'd',
532 't'
533 }
534 },
535 {
536 '8', new[]
537 {
538 'f', 'k', 'q', 'h', 't',
539 'l', 'x', 'o', 'c', 'b',
540 'j', 's', 'p', 'd', 'z',
541 'r', 'a', 'm', 'e', 'w',
542 'n', 'i', 'u', 'y', 'g',
543 'v'
544 }
545 },
546 {
547 'b', new[]
548 {
549 'l', 'e', 'y', 'j', 'v',
550 'c', 'n', 'i', 'x', 'w',
551 'p', 'b', 'q', 'm', 'd',
552 'r', 't', 'a', 'k', 'z',
553 'g', 'f', 'u', 'h', 'o',
554 's'
555 }
556 },
557 {
558 'g', new[]
559 {
560 'f', 's', 'o', 'k', 'a',
561 'n', 'u', 'e', 'r', 'h',
562 'm', 'b', 't', 'i', 'y',
563 'c', 'w', 'l', 'q', 'p',
564 'z', 'x', 'v', 'g', 'j',
565 'd'
566 }
567 }
568 };
569  
570 Dictionary<char, char[]> def_reflectors = new Dictionary<char, char[]>
571 {
572 {
573 'B', new[]
574 {
575 'a', 'y', 'b', 'r', 'c', 'u', 'd', 'h',
576 'e', 'q', 'f', 's', 'g', 'l', 'i', 'p',
577 'j', 'x', 'k', 'n', 'm', 'o', 't', 'z',
578 'v', 'w'
579 }
580 },
581 {
582 'b', new[]
583 {
584 'a', 'e', 'b', 'n', 'c', 'k', 'd', 'q',
585 'f', 'u', 'g', 'y', 'h', 'w', 'i', 'j',
586 'l', 'o', 'm', 'p', 'r', 'x', 's', 'z',
587 't', 'v'
588 }
589 },
590 {
591 'C', new[]
592 {
593 'a', 'f', 'b', 'v', 'c', 'p', 'd', 'j',
594 'e', 'i', 'g', 'o', 'h', 'y', 'k', 'r',
595 'l', 'z', 'm', 'x', 'n', 'w', 't', 'q',
596 's', 'u'
597 }
598 },
599 {
600 'c', new[]
601 {
602 'a', 'r', 'b', 'd', 'c', 'o', 'e', 'j',
603 'f', 'n', 'g', 't', 'h', 'k', 'i', 'v',
604 'l', 'm', 'p', 'w', 'q', 'z', 's', 'x',
605 'u', 'y'
606 }
607 }
608 };
609  
610 // Setup rotors from plugs.
611 foreach (char rotor in rotors)
612 {
613 char plug = plugs[Array.IndexOf(rotors, rotor)];
614 int i = Array.IndexOf(def_rotors[rotor], plug);
615 if (i.Equals(0)) continue;
616 def_rotors[rotor] = wasConcatenateArrays(new[] {plug},
617 wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i, i), i, -1),
618 wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i + 1, -1), 0, i - 1));
619 }
620  
621 StringBuilder result = new StringBuilder();
622 foreach (char c in message)
623 {
624 if (!char.IsLetter(c))
625 {
626 result.Append(c);
627 continue;
628 }
629  
630 // Normalize to lower.
631 char l = char.ToLower(c);
632  
633 Action<char[]> rotate = o =>
634 {
635 int i = o.Length - 1;
636 do
637 {
638 def_rotors[o[0]] = wasForwardPermuteArrayElements(def_rotors[o[0]], 1);
639 if (i.Equals(0))
640 {
641 rotors = wasReversePermuteArrayElements(o, 1);
642 continue;
643 }
644 l = wasGetElementAt(def_rotors[o[1]], Array.IndexOf(def_rotors[o[0]], l) - 1);
645 o = wasReversePermuteArrayElements(o, 1);
646 } while (--i > -1);
647 };
648  
649 // Forward pass through the Enigma's rotors.
650 rotate.Invoke(rotors);
651  
652 // Reflect
653 int x = Array.IndexOf(def_reflectors[reflector], l);
654 l = (x + 1)%2 == 0 ? def_reflectors[reflector][x - 1] : def_reflectors[reflector][x + 1];
655  
656 // Reverse the order of the rotors.
657 Array.Reverse(rotors);
658  
659 // Reverse pass through the Enigma's rotors.
660 rotate.Invoke(rotors);
661  
662 if (char.IsUpper(c))
663 {
664 l = char.ToUpper(l);
665 }
666 result.Append(l);
667 }
668  
669 return result.ToString();
670 }
671  
672 ///////////////////////////////////////////////////////////////////////////
673 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
674 ///////////////////////////////////////////////////////////////////////////
675 /// <summary>
676 /// Expand the VIGENRE key to the length of the input.
677 /// </summary>
678 /// <param name="input">the input to expand to</param>
679 /// <param name="enc_key">the key to expand</param>
680 /// <returns>the expanded key</returns>
681 private static string wasVigenereExpandKey(string input, string enc_key)
682 {
683 string exp_key = string.Empty;
684 int i = 0, j = 0;
685 do
686 {
687 char p = input[i];
688 if (!char.IsLetter(p))
689 {
690 exp_key += p;
691 ++i;
692 continue;
693 }
694 int m = j%enc_key.Length;
695 exp_key += enc_key[m];
696 ++j;
697 ++i;
698 } while (i < input.Length);
699 return exp_key;
700 }
701  
702 ///////////////////////////////////////////////////////////////////////////
703 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
704 ///////////////////////////////////////////////////////////////////////////
705 /// <summary>
706 /// Encrypt using VIGENERE.
707 /// </summary>
708 /// <param name="input">the input to encrypt</param>
709 /// <param name="enc_key">the key to encrypt with</param>
710 /// <returns>the encrypted input</returns>
711 private static string wasEncryptVIGENERE(string input, string enc_key)
712 {
713 char[] a =
714 {
715 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
716 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
717 };
718  
719 enc_key = wasVigenereExpandKey(input, enc_key);
720 string result = string.Empty;
721 int i = 0;
722 do
723 {
724 char p = input[i];
725 if (!char.IsLetter(p))
726 {
727 result += p;
728 ++i;
729 continue;
730 }
731 char q =
732 wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i]))[
733 Array.IndexOf(a, char.ToLowerInvariant(p))];
734 if (char.IsUpper(p))
735 {
736 q = char.ToUpperInvariant(q);
737 }
738 result += q;
739 ++i;
740 } while (i < input.Length);
741 return result;
742 }
743  
744 ///////////////////////////////////////////////////////////////////////////
745 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
746 ///////////////////////////////////////////////////////////////////////////
747 /// <summary>
748 /// Decrypt using VIGENERE.
749 /// </summary>
750 /// <param name="input">the input to decrypt</param>
751 /// <param name="enc_key">the key to decrypt with</param>
752 /// <returns>the decrypted input</returns>
753 private static string wasDecryptVIGENERE(string input, string enc_key)
754 {
755 char[] a =
756 {
757 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
758 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
759 };
760  
761 enc_key = wasVigenereExpandKey(input, enc_key);
762 string result = string.Empty;
763 int i = 0;
764 do
765 {
766 char p = input[i];
767 if (!char.IsLetter(p))
768 {
769 result += p;
770 ++i;
771 continue;
772 }
773 char q =
774 a[
775 Array.IndexOf(wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i])),
776 char.ToLowerInvariant(p))];
777 if (char.IsUpper(p))
778 {
779 q = char.ToUpperInvariant(q);
780 }
781 result += q;
782 ++i;
783 } while (i < input.Length);
784 return result;
785 }
786  
787 ///////////////////////////////////////////////////////////////////////////
788 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
789 ///////////////////////////////////////////////////////////////////////////
790 /// <summary>
791 /// An implementation of the ATBASH cypher for latin alphabets.
792 /// </summary>
793 /// <param name="data">the data to encrypt or decrypt</param>
794 /// <returns>the encrypted or decrypted data</returns>
795 private static string wasATBASH(string data)
796 {
797 char[] a =
798 {
799 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
800 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
801 };
802  
803 char[] input = data.ToArray();
804  
805 Parallel.ForEach(Enumerable.Range(0, data.Length), i =>
806 {
807 char e = input[i];
808 if (!char.IsLetter(e)) return;
809 int x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e));
810 if (!char.IsUpper(e))
811 {
812 input[i] = a[x];
813 return;
814 }
815 input[i] = char.ToUpperInvariant(a[x]);
816 });
817  
818 return new string(input);
819 }
820  
821 #endregion
822  
823 /// <summary>
824 /// Corrade's input filter function.
825 /// </summary>
826 private static readonly Func<string, string> wasInput = o =>
827 {
828 if (string.IsNullOrEmpty(o)) return string.Empty;
829  
830 foreach (Filter filter in vassalConfiguration.InputFilters)
831 {
832 switch (filter)
833 {
834 case Filter.RFC1738:
835 o = wasURLUnescapeDataString(o);
836 break;
837 case Filter.RFC3986:
838 o = wasURIUnescapeDataString(o);
839 break;
840 case Filter.ENIGMA:
841 o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
842 vassalConfiguration.ENIGMA.plugs.ToArray(),
843 vassalConfiguration.ENIGMA.reflector);
844 break;
845 case Filter.VIGENERE:
846 o = wasDecryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
847 break;
848 case Filter.ATBASH:
849 o = wasATBASH(o);
850 break;
851 case Filter.BASE64:
852 o = Encoding.UTF8.GetString(Convert.FromBase64String(o));
853 break;
854 }
855 }
856 return o;
857 };
858  
859 /// <summary>
860 /// Corrade's output filter function.
861 /// </summary>
862 private static readonly Func<string, string> wasOutput = o =>
863 {
864 if (string.IsNullOrEmpty(o)) return string.Empty;
865  
866 foreach (Filter filter in vassalConfiguration.OutputFilters)
867 {
868 switch (filter)
869 {
870 case Filter.RFC1738:
871 o = wasURLEscapeDataString(o);
872 break;
873 case Filter.RFC3986:
874 o = wasURIEscapeDataString(o);
875 break;
876 case Filter.ENIGMA:
877 o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
878 vassalConfiguration.ENIGMA.plugs.ToArray(),
879 vassalConfiguration.ENIGMA.reflector);
880 break;
881 case Filter.VIGENERE:
882 o = wasEncryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
883 break;
884 case Filter.ATBASH:
885 o = wasATBASH(o);
886 break;
887 case Filter.BASE64:
888 o = Convert.ToBase64String(Encoding.UTF8.GetBytes(o));
889 break;
890 }
891 }
892 return o;
893 };
894  
895 ///////////////////////////////////////////////////////////////////////////
896 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
897 ///////////////////////////////////////////////////////////////////////////
898 /// <summary>Escapes a dictionary's keys and values for sending as POST data.</summary>
899 /// <param name="data">A dictionary containing keys and values to be escaped</param>
900 private static Dictionary<string, string> wasKeyValueEscape(Dictionary<string, string> data)
901 {
902 return data.AsParallel().ToDictionary(o => wasOutput(o.Key), p => wasOutput(p.Value));
903 }
904  
905 ///////////////////////////////////////////////////////////////////////////
906 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
907 ///////////////////////////////////////////////////////////////////////////
908 /// <summary>
909 /// Converts a list of string to a comma-separated values string.
910 /// </summary>
911 /// <param name="l">a list of strings</param>
912 /// <returns>a commma-separated list of values</returns>
913 /// <remarks>compliant with RFC 4180</remarks>
914 public static string wasEnumerableToCSV(IEnumerable<string> l)
915 {
916 string[] csv = l.Select(o => o.Clone() as string).ToArray();
917 Parallel.ForEach(csv.Select((v, i) => new {i, v}), o =>
918 {
919 string cell = o.v.Replace("\"", "\"\"");
920 switch (new[] {'"', ' ', ',', '\r', '\n'}.Any(p => cell.Contains(p)))
921 {
922 case true:
923 csv[o.i] = "\"" + cell + "\"";
924 break;
925 default:
926 csv[o.i] = cell;
927 break;
928 }
929 });
930 return String.Join(",", csv);
931 }
932  
933 ///////////////////////////////////////////////////////////////////////////
934 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
935 ///////////////////////////////////////////////////////////////////////////
936 /// <summary>
937 /// Converts a comma-separated list of values to a list of strings.
938 /// </summary>
939 /// <param name="csv">a comma-separated list of values</param>
940 /// <returns>a list of strings</returns>
941 /// <remarks>compliant with RFC 4180</remarks>
942 public static IEnumerable<string> wasCSVToEnumerable(string csv)
943 {
944 Stack<char> s = new Stack<char>();
945 StringBuilder m = new StringBuilder();
946 for (int i = 0; i < csv.Length; ++i)
947 {
948 switch (csv[i])
949 {
950 case ',':
951 if (!s.Any() || !s.Peek().Equals('"'))
952 {
953 yield return m.ToString();
954 m = new StringBuilder();
955 continue;
956 }
957 m.Append(csv[i]);
958 continue;
959 case '"':
960 if (i + 1 < csv.Length && csv[i].Equals(csv[i + 1]))
961 {
962 m.Append(csv[i]);
963 ++i;
964 continue;
965 }
966 if (!s.Any() || !s.Peek().Equals(csv[i]))
967 {
968 s.Push(csv[i]);
969 continue;
970 }
971 s.Pop();
972 continue;
973 }
974 m.Append(csv[i]);
975 }
976  
977 yield return m.ToString();
978 }
979  
980 ///////////////////////////////////////////////////////////////////////////
981 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
982 ///////////////////////////////////////////////////////////////////////////
983 /// <summary>
984 /// Serialises a dictionary to key-value data.
985 /// </summary>
986 /// <param name="data">a dictionary</param>
987 /// <returns>a key-value data encoded string</returns>
988 private static string wasKeyValueEncode(Dictionary<string, string> data)
989 {
990 return String.Join("&", data.AsParallel().Select(o => String.Join("=", o.Key, o.Value)));
991 }
992  
993 ///////////////////////////////////////////////////////////////////////////
994 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
995 ///////////////////////////////////////////////////////////////////////////
996 /// <summary>
997 /// Sends a post request to an URL with set key-value pairs.
998 /// </summary>
999 /// <param name="URL">the url to send the message to</param>
1000 /// <param name="message">key-value pairs to send</param>
1001 /// <param name="millisecondsTimeout">the time in milliseconds for the request to timeout</param>
1002 private static string wasPOST(string URL, Dictionary<string, string> message, uint millisecondsTimeout)
1003 {
1004 try
1005 {
1006 HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL);
1007 request.UserAgent = VASSAL_CONSTANTS.USER_AGENT;
1008 request.Proxy = WebRequest.DefaultWebProxy;
1009 request.Timeout = (int) millisecondsTimeout;
1010 request.AllowAutoRedirect = true;
1011 request.AllowWriteStreamBuffering = true;
1012 request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
1013 request.Method = WebRequestMethods.Http.Post;
1014 // set the content type based on chosen output filers
1015 switch (vassalConfiguration.OutputFilters.Last())
1016 {
1017 case Filter.RFC1738:
1018 request.ContentType = VASSAL_CONSTANTS.CONTENT_TYPE.WWW_FORM_URLENCODED;
1019 break;
1020 default:
1021 request.ContentType = VASSAL_CONSTANTS.CONTENT_TYPE.TEXT_PLAIN;
1022 break;
1023 }
1024 // send request
1025 using (Stream requestStream = request.GetRequestStream())
1026 {
1027 using (StreamWriter dataStream = new StreamWriter(requestStream))
1028 {
1029 dataStream.Write(wasKeyValueEncode(message));
1030 }
1031 }
1032 // read response
1033 using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
1034 {
1035 using (Stream responseStream = response.GetResponseStream())
1036 {
1037 if (responseStream != null)
1038 {
1039 using (
1040 StreamReader streamReader = new StreamReader(responseStream))
1041 {
1042 return streamReader.ReadToEnd();
1043 }
1044 }
1045 }
1046 }
1047 }
1048 catch (Exception)
1049 {
1050  
1051 }
1052  
1053 return null;
1054 }
1055  
1056 /// <summary>
1057 /// Constants used by Corrade.
1058 /// </summary>
1059 public struct VASSAL_CONSTANTS
1060 {
1061 /// <summary>
1062 /// Copyright.
1063 /// </summary>
1064 public const string COPYRIGHT = @"(c) Copyright 2013 Wizardry and Steamworks";
1065  
1066 public const string WIZARDRY_AND_STEAMWORKS = @"Wizardry and Steamworks";
1067 public const string VASSAL = @"Vassal";
1068 public const string WIZARDRY_AND_STEAMWORKS_WEBSITE = @"http://grimore.org";
1069  
1070 /// <summary>
1071 /// Vassal version.
1072 /// </summary>
1073 public static readonly string VASSAL_VERSION = Assembly.GetEntryAssembly().GetName().Version.ToString();
1074  
1075 /// <summary>
1076 /// Corrade user agent.
1077 /// </summary>
1078 public static readonly string USER_AGENT =
1079 $"{VASSAL}/{VASSAL_VERSION} ({WIZARDRY_AND_STEAMWORKS_WEBSITE})";
1080  
1081 /// <summary>
1082 /// Vassal compile date.
1083 /// </summary>
1084 public static readonly string VASSAL_COMPILE_DATE = new DateTime(2000, 1, 1).Add(new TimeSpan(
1085 TimeSpan.TicksPerDay*Assembly.GetEntryAssembly().GetName().Version.Build + // days since 1 January 2000
1086 TimeSpan.TicksPerSecond*2*Assembly.GetEntryAssembly().GetName().Version.Revision)).ToLongDateString();
1087  
1088 /// <summary>
1089 /// Vassal configuration file.
1090 /// </summary>
1091 public static readonly string VASSAL_CONFIGURATION_FILE = @"Vassal.ini";
1092  
1093 /// <summary>
1094 /// Vassal regions file.
1095 /// </summary>
1096 public static readonly string VASSAL_REGIONS = @"Regions.csv";
1097  
1098 /// <summary>
1099 /// Conten-types that Corrade can send and receive.
1100 /// </summary>
1101 public struct CONTENT_TYPE
1102 {
1103 public const string TEXT_PLAIN = @"text/plain";
1104 public const string WWW_FORM_URLENCODED = @"application/x-www-form-urlencoded";
1105 }
1106 }
1107  
1108 private static readonly System.Action updateCurrentRegionName = () =>
1109 {
1110 try
1111 {
1112 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1113 wasKeyValueEscape(new Dictionary<string, string>
1114 {
3 eva 1115 {"command", "getregiondata"},
1116 {"group", vassalConfiguration.Group},
1117 {"password", vassalConfiguration.Password},
1118 {"data", "Name"}
2 zed 1119 }), 60000);
1120 bool success;
1121 if (string.IsNullOrEmpty(result) ||
1122 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1123 {
3 eva 1124 vassalForm.BeginInvoke((MethodInvoker) (() =>
2 zed 1125 {
1126 vassalForm.StatusText.Text = @"Failed to query Corrade for current region.";
1127 }));
1128 return;
1129 }
1130 switch (success)
1131 {
1132 case true:
3 eva 1133 vassalForm.BeginInvoke((MethodInvoker) (() =>
2 zed 1134 {
1135 vassalForm.CurrentRegionAt.Visible = true;
1136 vassalForm.CurrentRegionName.Visible = true;
1137 vassalForm.CurrentRegionName.Text =
1138 wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).Last();
1139 }));
1140 break;
1141 default:
3 eva 1142 vassalForm.BeginInvoke((MethodInvoker) (() =>
2 zed 1143 {
1144 vassalForm.CurrentRegionAt.Visible = false;
1145 vassalForm.CurrentRegionName.Visible = false;
1146 vassalForm.StatusText.Text = @"Error getting current region: " +
1147 wasInput(wasKeyValueGet("error", result));
1148 }));
1149 break;
1150 }
1151 }
1152 catch (Exception ex)
1153 {
3 eva 1154 vassalForm.BeginInvoke((MethodInvoker) (() =>
2 zed 1155 {
1156 vassalForm.StatusText.Text =
1157 @"Error getting current region: " +
1158 ex.Message;
1159 }));
1160 }
1161 };
1162  
1163 public Vassal()
1164 {
1165 InitializeComponent();
1166 vassalForm = this;
1167 }
1168  
1169 private void RegionSelected(object sender, EventArgs e)
1170 {
3 eva 1171 string selectedRegionName = string.Empty;
1172 Vector3 selectedRegionPosition = Vector3.Zero;
1173 bool startTeleport = false;
2 zed 1174 vassalForm.Invoke((MethodInvoker) (() =>
1175 {
3 eva 1176 ListViewItem listViewItem = LoadedRegions.SelectedItem as ListViewItem;
1177 switch (listViewItem != null && LoadedRegions.SelectedIndex != -1)
1178 {
1179 case true:
1180 selectedRegionName = listViewItem.Text;
7 zed 1181 selectedRegionPosition = (Vector3) listViewItem.Tag;
3 eva 1182 startTeleport = true;
1183 break;
1184 default:
1185 startTeleport = false;
1186 break;
1187 }
2 zed 1188 }));
1189  
3 eva 1190 if (!startTeleport) return;
1191  
7 zed 1192  
3 eva 1193 // Announce teleport.
7 zed 1194 vassalForm.Invoke((MethodInvoker) (() =>
2 zed 1195 {
3 eva 1196 vassalForm.RegionTeleportGroup.Enabled = false;
1197 vassalForm.StatusProgress.Value = 0;
1198 vassalForm.StatusText.Text = @"Teleporting to " + selectedRegionName;
1199 }));
2 zed 1200  
1201 new Thread(() =>
1202 {
3 eva 1203 Monitor.Enter(ClientInstanceTeleportLock);
1204 try
2 zed 1205 {
3 eva 1206 int elapsedSeconds = 0;
1207 System.Timers.Timer teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
1208 teleportTimer.Elapsed += (o, p) =>
2 zed 1209 {
1210 vassalForm.Invoke((MethodInvoker) (() =>
1211 {
3 eva 1212 vassalForm.StatusProgress.Value =
1213 Math.Min(
1214 (int)
1215 (100d*
1216 (TimeSpan.FromSeconds(++elapsedSeconds).TotalMilliseconds/
1217 vassalConfiguration.TeleportTimeout)), 100);
2 zed 1218 }));
3 eva 1219 };
1220 teleportTimer.Start();
1221 string result = null;
1222 ManualResetEvent receivedPOST = new ManualResetEvent(false);
1223 new Thread(() =>
1224 {
1225 result = wasInput(wasPOST(vassalConfiguration.HTTPServerURL,
1226 wasKeyValueEscape(new Dictionary<string, string>
1227 {
1228 {"command", "teleport"},
1229 {"group", vassalConfiguration.Group},
1230 {"password", vassalConfiguration.Password},
1231 {"region", selectedRegionName},
1232 {"position", selectedRegionPosition.ToString()},
1233 {"fly", "True"}
1234 }), vassalConfiguration.TeleportTimeout));
1235 receivedPOST.Set();
1236 }) {IsBackground = true}.Start();
1237 receivedPOST.WaitOne((int) vassalConfiguration.TeleportTimeout, false);
1238 teleportTimer.Stop();
1239 switch (!string.IsNullOrEmpty(result) && wasKeyValueGet("success", result) == "True")
1240 {
1241 case true:
2 zed 1242 vassalForm.Invoke((MethodInvoker) (() =>
1243 {
3 eva 1244 vassalForm.StatusText.Text = @"Now at " + selectedRegionName;
1245 vassalForm.CurrentRegionName.Text = selectedRegionName;
2 zed 1246 }));
3 eva 1247 break;
1248 default:
1249 switch (!string.IsNullOrEmpty(result))
2 zed 1250 {
1251 case true:
3 eva 1252 vassalForm.Invoke((MethodInvoker) (() =>
2 zed 1253 {
3 eva 1254 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName +
1255 @": " +
1256 wasKeyValueGet("error", result);
2 zed 1257 }));
1258 break;
3 eva 1259 default:
1260 vassalForm.Invoke((MethodInvoker) (() =>
1261 {
1262 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName;
1263 }));
1264 break;
2 zed 1265 }
3 eva 1266 break;
2 zed 1267 }
1268 }
3 eva 1269 catch (Exception ex)
1270 {
1271 vassalForm.Invoke((MethodInvoker) (() =>
1272 {
1273 vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message;
1274 }));
1275 }
1276 finally
1277 {
1278 Monitor.Exit(ClientInstanceTeleportLock);
7 zed 1279 vassalForm.BeginInvoke((MethodInvoker) (() =>
3 eva 1280 {
1281 vassalForm.StatusProgress.Value = 100;
1282 vassalForm.RegionTeleportGroup.Enabled = true;
1283 // Set the map image to the loading spinner.
1284 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
1285 System.IO.Stream file =
1286 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
1287 switch (file != null)
1288 {
1289 case true:
1290 vassalForm.Invoke((MethodInvoker) (() =>
1291 {
1292 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
1293 RegionAvatarsMap.Image = Image.FromStream(file);
1294 RegionAvatarsMap.Refresh();
1295 }));
1296 break;
1297 }
7 zed 1298 // Clear the resident list table.
1299 ResidentListGridView.Rows.Clear();
3 eva 1300 // Clear the top scripts table.
1301 TopScriptsGridView.Rows.Clear();
1302 // Clear the top colliders table.
1303 TopCollidersGridView.Rows.Clear();
1304 // Invalidate data for overview tab.
1305 vassalForm.CurrentRegionAt.Visible = false;
1306 vassalForm.CurrentRegionName.Visible = false;
1307 Agents.Text = string.Empty;
1308 Agents.Enabled = false;
1309 LastLag.Text = string.Empty;
1310 LastLag.Enabled = false;
1311 Dilation.Text = string.Empty;
1312 Dilation.Enabled = false;
1313 FPS.Text = string.Empty;
1314 FPS.Enabled = false;
1315 PhysicsFPS.Text = string.Empty;
1316 PhysicsFPS.Enabled = false;
1317 ActiveScripts.Text = string.Empty;
1318 ActiveScripts.Enabled = false;
1319 ScriptTime.Text = string.Empty;
1320 ScriptTime.Enabled = false;
1321 Objects.Text = string.Empty;
1322 Objects.Enabled = false;
1323 }));
1324 }
7 zed 1325 })
1326 {IsBackground = true}.Start();
2 zed 1327 }
1328  
1329 private void SettingsRequested(object sender, EventArgs e)
1330 {
1331 SettingsForm settingsForm = new SettingsForm {TopMost = true};
1332 settingsForm.Show();
1333 }
1334  
1335 private void VassalShown(object sender, EventArgs e)
1336 {
3 eva 1337 // Set the version
1338 vassalForm.Version.Text = @"v" + VASSAL_CONSTANTS.VASSAL_VERSION;
1339  
4 vero 1340 // Disable estate manager tabs since we will enable these dynamically.
1341 TopScriptsTab.Enabled = false;
1342 TopCollidersTab.Enabled = false;
7 zed 1343 ResidentListBanGroup.Enabled = false;
4 vero 1344  
2 zed 1345 // Get the configuration file settings if it exists.
1346 if (File.Exists(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE))
1347 {
4 vero 1348 // Load the configuration.
2 zed 1349 VassalConfiguration.Load(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE, ref vassalConfiguration);
5 eva 1350 // Apply settings
1351 RegionRestartDelayBox.Text = vassalConfiguration.RegionRestartDelay.ToString(Utils.EnUsCulture);
2 zed 1352 }
1353  
7 zed 1354 // Spawn a thread to check Corrade's connection status.
1355 new Thread(() =>
1356 {
1357 TcpClient tcpClient = new TcpClient();
1358 try
1359 {
1360 System.Uri uri = new System.Uri(vassalConfiguration.HTTPServerURL);
1361 tcpClient.Connect(uri.Host, uri.Port);
1362 // port open
1363 vassalForm.BeginInvoke((MethodInvoker) (() => { Tabs.Enabled = true; }));
1364 // set the loading spinner
1365 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
1366 System.IO.Stream file =
1367 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
1368 switch (file != null)
1369 {
1370 case true:
1371 vassalForm.BeginInvoke((MethodInvoker) (() =>
1372 {
1373 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
1374 RegionAvatarsMap.Image = Image.FromStream(file);
1375 RegionAvatarsMap.Refresh();
1376 }));
1377 break;
1378 }
1379 }
1380 catch (Exception)
1381 {
1382 // port closed
1383 vassalForm.BeginInvoke((MethodInvoker) (() => { Tabs.Enabled = false; }));
1384 }
1385 })
1386 {IsBackground = true}.Start();
1387  
2 zed 1388 // Get all the regions if they exist.
1389 if (File.Exists(VASSAL_CONSTANTS.VASSAL_REGIONS))
1390 {
1391 Vector3 localPosition;
3 eva 1392 List<KeyValuePair<string, Vector3>> ConfiguredRegions = new List<KeyValuePair<string, Vector3>>(
2 zed 1393 File.ReadAllLines(VASSAL_CONSTANTS.VASSAL_REGIONS)
1394 .Select(o => new List<string>(wasCSVToEnumerable(o)))
1395 .Where(o => o.Count == 2)
1396 .ToDictionary(o => o.First(),
1397 p =>
1398 Vector3.TryParse(p.Last(), out localPosition)
1399 ? localPosition
3 eva 1400 : Vector3.Zero).OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value));
1401 // Populate the loaded regions.
2 zed 1402 LoadedRegions.Items.Clear();
1403 LoadedRegions.Items.AddRange(
3 eva 1404 ConfiguredRegions.Select(o => (object) new ListViewItem {Text = o.Key, Tag = o.Value})
2 zed 1405 .ToArray());
3 eva 1406 // Populate the batch restart grid view.
1407 BatchRestartGridView.Rows.Clear();
1408 foreach (KeyValuePair<string, Vector3> data in ConfiguredRegions)
1409 {
1410 BatchRestartGridView.Rows.Add(data.Key, data.Value.ToString());
1411 }
7 zed 1412 // Populate the regions state grid view.
1413 foreach (KeyValuePair<string, Vector3> data in ConfiguredRegions)
1414 {
1415 RegionsStateGridView.Rows.Add(data.Key, "Check pening...");
1416 }
2 zed 1417 }
1418  
1419 // Start the overview timer.
1420 overviewTabTimer.Elapsed += (o, p) =>
1421 {
1422 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1423 return;
1424  
1425 try
1426 {
7 zed 1427 // Always run the overview regardless which tab is active.
2 zed 1428  
1429 // Get the statistics.
1430 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1431 wasKeyValueEscape(new Dictionary<string, string>
1432 {
1433 {"command", "getregiondata"},
1434 {"group", vassalConfiguration.Group},
1435 {"password", vassalConfiguration.Password},
1436 {
1437 "data", wasEnumerableToCSV(new[]
1438 {
1439 "Agents",
1440 "LastLag",
1441 "Dilation",
1442 "FPS",
1443 "PhysicsFPS",
1444 "ActiveScripts",
1445 "ScriptTime",
3 eva 1446 "Objects",
4 vero 1447 "Name",
1448 "IsEstateManager"
2 zed 1449 })
1450 }
1451 }), vassalConfiguration.DataTimeout);
1452  
1453 bool success;
1454 if (string.IsNullOrEmpty(result) ||
1455 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1456 throw new Exception();
1457  
1458 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1459 if (data.Count.Equals(0))
1460 throw new Exception();
1461  
7 zed 1462 vassalForm.BeginInvoke((MethodInvoker) (() =>
2 zed 1463 {
4 vero 1464 // Drop access to features if we are not estate managers.
1465 bool isEstateManager;
1466 switch (
1467 bool.TryParse(data[data.IndexOf("IsEstateManager") + 1], out isEstateManager) &&
1468 isEstateManager)
1469 {
1470 case true: // we are an estate manager
1471 TopScriptsTab.Enabled = true;
1472 TopCollidersTab.Enabled = true;
7 zed 1473 ResidentListBanGroup.Enabled = true;
4 vero 1474 break;
1475 default:
1476 TopScriptsTab.Enabled = false;
1477 TopCollidersTab.Enabled = false;
7 zed 1478 ResidentListBanGroup.Enabled = false;
4 vero 1479 break;
1480 }
1481  
3 eva 1482 // Show the region name.
1483 vassalForm.CurrentRegionName.Text = data[data.IndexOf("Name") + 1];
1484 vassalForm.CurrentRegionAt.Visible = true;
1485 vassalForm.CurrentRegionName.Visible = true;
1486  
1487 // Populate the overview tab.
2 zed 1488 Agents.Text = data[data.IndexOf("Agents") + 1];
3 eva 1489 Agents.Enabled = true;
2 zed 1490 LastLag.Text = data[data.IndexOf("LastLag") + 1];
3 eva 1491 LastLag.Enabled = true;
2 zed 1492 Dilation.Text = data[data.IndexOf("Dilation") + 1];
3 eva 1493 Dilation.Enabled = true;
2 zed 1494 FPS.Text = data[data.IndexOf("FPS") + 1];
3 eva 1495 FPS.Enabled = true;
2 zed 1496 PhysicsFPS.Text = data[data.IndexOf("PhysicsFPS") + 1];
3 eva 1497 PhysicsFPS.Enabled = true;
2 zed 1498 ActiveScripts.Text = data[data.IndexOf("ActiveScripts") + 1];
3 eva 1499 ActiveScripts.Enabled = true;
2 zed 1500 ScriptTime.Text = data[data.IndexOf("ScriptTime") + 1];
3 eva 1501 ScriptTime.Enabled = true;
2 zed 1502 Objects.Text = data[data.IndexOf("Objects") + 1];
3 eva 1503 Objects.Enabled = true;
2 zed 1504 }));
3 eva 1505  
2 zed 1506 // Get the map image.
1507 result = wasPOST(vassalConfiguration.HTTPServerURL,
1508 wasKeyValueEscape(new Dictionary<string, string>
1509 {
1510 {"command", "getgridregiondata"},
1511 {"group", vassalConfiguration.Group},
1512 {"password", vassalConfiguration.Password},
3 eva 1513 {"data", "MapImageID"}
2 zed 1514 }), vassalConfiguration.DataTimeout);
3 eva 1515  
2 zed 1516 if (string.IsNullOrEmpty(result) ||
1517 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1518 throw new Exception();
1519  
1520 data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1521 if (!data.Count.Equals(2))
1522 throw new Exception();
1523 result = wasPOST(vassalConfiguration.HTTPServerURL,
1524 wasKeyValueEscape(new Dictionary<string, string>
1525 {
1526 {"command", "download"},
1527 {"group", vassalConfiguration.Group},
1528 {"password", vassalConfiguration.Password},
3 eva 1529 {"item", data.Last()},
1530 {"type", "Texture"},
1531 {"format", "Jpeg"},
2 zed 1532 }), vassalConfiguration.DataTimeout);
1533 if (string.IsNullOrEmpty(result) ||
1534 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1535 throw new Exception();
1536 byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
1537 Image mapImage;
1538 using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
1539 {
1540 mapImage = Image.FromStream(memoryStream);
1541 }
1542  
1543 // Get the avatar positions.
1544 result = wasPOST(vassalConfiguration.HTTPServerURL,
1545 wasKeyValueEscape(new Dictionary<string, string>
1546 {
1547 {"command", "getavatarpositions"},
1548 {"group", vassalConfiguration.Group},
1549 {"password", vassalConfiguration.Password},
3 eva 1550 {"entity", "region"}
2 zed 1551 }), vassalConfiguration.DataTimeout);
1552  
1553 if (string.IsNullOrEmpty(result) ||
1554 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1555 throw new Exception();
1556  
1557 // Every thrid element represents a Vecto3 of the avatar position.
3 eva 1558 data =
1559 wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1560 .Skip(2)
1561 .Where((x, i) => i%3 == 0)
1562 .ToList();
2 zed 1563  
1564 // Draw the avatars onto the map.
1565 Graphics mapGraphics = Graphics.FromImage(mapImage);
1566 Vector3 position;
1567 foreach (string vector in data)
1568 {
1569 switch (Vector3.TryParse(vector, out position))
1570 {
1571 case true:
3 eva 1572 mapGraphics.FillEllipse(Brushes.Chartreuse,
1573 new Rectangle((int) position.X, (int) position.Y, 4, 4));
2 zed 1574 break;
1575 }
1576 }
1577 mapGraphics.DrawImage(mapImage, new Point(0, 0));
1578  
7 zed 1579 vassalForm.BeginInvoke((MethodInvoker) (() =>
2 zed 1580 {
1581 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.StretchImage;
1582 RegionAvatarsMap.Image = mapImage;
1583 RegionAvatarsMap.Refresh();
1584 }));
1585 }
1586 catch (Exception)
1587 {
1588  
1589 }
1590 finally
1591 {
1592 Monitor.Exit(ClientInstanceTeleportLock);
1593 }
3 eva 1594  
2 zed 1595 };
1596 overviewTabTimer.Start();
1597  
7 zed 1598 regionsStateTabTimer.Elapsed += (o, p) =>
2 zed 1599 {
7 zed 1600 // Do not do anything in case the tab is not selected.
1601 bool run = false;
1602 vassalForm.Invoke((MethodInvoker) (() =>
1603 {
1604 run = Tabs.SelectedTab.Equals(RegionsStateTab);
1605 }));
1606 if (!run) return;
1607  
1608 if (!Monitor.TryEnter(RegionsStateCheckLock))
2 zed 1609 return;
1610  
1611 try
1612 {
7 zed 1613 string regionName = string.Empty;
2 zed 1614 vassalForm.Invoke((MethodInvoker) (() =>
1615 {
7 zed 1616 regionName =
1617 RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateRegionName"].Value
1618 .ToString();
2 zed 1619 }));
1620  
7 zed 1621 if (string.IsNullOrEmpty(regionName))
1622 throw new Exception();
1623  
1624 // Get the region status.
1625 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1626 wasKeyValueEscape(new Dictionary<string, string>
1627 {
1628 {"command", "getgridregiondata"},
1629 {"group", vassalConfiguration.Group},
1630 {"password", vassalConfiguration.Password},
1631 {"region", regionName},
1632 {"data", "Access"}
1633 }), vassalConfiguration.DataTimeout);
1634  
1635 bool success;
1636 if (string.IsNullOrEmpty(result) ||
1637 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1638 throw new Exception();
1639  
1640 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1641 if (!data.Count.Equals(2))
1642 throw new Exception();
1643  
1644 string status = data.Last();
1645 vassalForm.Invoke((MethodInvoker) (() =>
1646 {
1647 switch (status)
1648 {
1649 case "Unknown":
1650 case "Down":
1651 case "NonExistent":
1652 RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
1653 Color.LightPink;
1654 RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastState"].Value =
1655 status;
1656 break;
1657 default:
1658 RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
1659 Color.LightGreen;
1660 RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastState"].Value =
1661 "Up";
1662 break;
1663 }
1664 RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastCheck"].Value = DateTime
1665 .Now.ToUniversalTime()
1666 .ToString(Vassal.LINDEN_CONSTANTS.LSL.DATE_TIME_STAMP);
1667  
1668 }));
1669 }
1670 catch (Exception)
1671 {
1672  
1673 }
1674 finally
1675 {
1676 Monitor.Exit(RegionsStateCheckLock);
1677 ++regionsStateCheckIndex;
1678 vassalForm.Invoke((MethodInvoker) (() =>
1679 {
1680 if (regionsStateCheckIndex >= RegionsStateGridView.Rows.Count)
1681 {
1682 regionsStateCheckIndex = 0;
1683 }
1684 }));
1685 }
1686 };
1687 regionsStateTabTimer.Start();
1688  
1689 // Start the top scores timer.
1690 topScriptsTabTimer.Elapsed += (o, p) =>
1691 {
1692 // Do not do anything in case the tab is not selected.
1693 bool run = false;
1694 vassalForm.Invoke((MethodInvoker) (() =>
1695 {
1696 run = Tabs.SelectedTab.Equals(TopScriptsTab);
1697 }));
1698 if (!run) return;
1699  
1700 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1701 return;
1702  
1703 try
1704 {
2 zed 1705 // Get the statistics.
1706 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1707 wasKeyValueEscape(new Dictionary<string, string>
1708 {
1709 {"command", "getregiontop"},
1710 {"group", vassalConfiguration.Group},
1711 {"password", vassalConfiguration.Password},
1712 {"type", "scripts"}
1713 }), vassalConfiguration.DataTimeout);
1714  
1715 bool success;
1716 if (string.IsNullOrEmpty(result) ||
1717 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1718 throw new Exception();
1719  
1720 HashSet<List<string>> data =
1721 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1722 .Select((x, i) => new {Index = i, Value = x})
1723 .GroupBy(x => x.Index/5)
1724 .Select(x => x.Select(v => v.Value).ToList()));
1725 if (data.Count.Equals(0))
1726 throw new Exception();
1727  
1728 vassalForm.Invoke((MethodInvoker) (() =>
1729 {
3 eva 1730 // Remove rows that are not in the data update.
1731 foreach (
1732 int index in
1733 TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>()
1734 .Where(
1735 topScriptsRow =>
1736 !data.Any(q => q[2].Equals(topScriptsRow.Cells["TopScriptsUUID"].Value)))
1737 .Select(q => q.Index))
2 zed 1738 {
3 eva 1739 TopScriptsGridView.Rows.RemoveAt(index);
2 zed 1740 }
3 eva 1741 // Now update or add new data.
1742 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5)))
1743 {
1744 DataGridViewRow row =
1745 TopScriptsGridView.Rows.AsParallel()
1746 .Cast<DataGridViewRow>()
1747 .FirstOrDefault(q => q.Cells["TopScriptsUUID"].Value.Equals(dataComponents[2]));
1748 switch (row != null)
1749 {
1750 case true: // the row exists, so update it.
1751 row.Cells["TopScriptsScore"].Value = dataComponents[0];
1752 row.Cells["TopScriptsTaskName"].Value = dataComponents[1];
1753 row.Cells["TopScriptsUUID"].Value = dataComponents[2];
1754 row.Cells["TopScriptsOwner"].Value = dataComponents[3];
1755 row.Cells["TopScriptsPosition"].Value = dataComponents[4];
1756 break;
1757 case false: // the row dosn't exist, so add it.
1758 TopScriptsGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2],
1759 dataComponents[3], dataComponents[4]);
1760 break;
1761 }
1762 }
2 zed 1763 }));
1764 }
1765 catch (Exception)
1766 {
1767  
1768 }
1769 finally
1770 {
1771 Monitor.Exit(ClientInstanceTeleportLock);
1772 }
1773 };
1774 topScriptsTabTimer.Start();
1775  
1776 // Start the top colliders timer.
1777 topCollidersTabTimer.Elapsed += (o, p) =>
1778 {
7 zed 1779 // Do not do anything in case the tab is not selected.
1780 bool run = false;
1781 vassalForm.Invoke((MethodInvoker) (() =>
1782 {
1783 run = Tabs.SelectedTab.Equals(TopCollidersTab);
1784 }));
1785 if (!run) return;
1786  
2 zed 1787 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1788 return;
1789  
1790 try
1791 {
1792 // Get the statistics.
1793 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1794 wasKeyValueEscape(new Dictionary<string, string>
1795 {
1796 {"command", "getregiontop"},
1797 {"group", vassalConfiguration.Group},
1798 {"password", vassalConfiguration.Password},
1799 {"type", "colliders"}
1800 }), vassalConfiguration.DataTimeout);
1801  
1802 bool success;
1803 if (string.IsNullOrEmpty(result) ||
1804 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1805 throw new Exception();
1806  
1807 HashSet<List<string>> data =
1808 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
3 eva 1809 .Select((x, i) => new {Index = i, Value = x})
1810 .GroupBy(x => x.Index/5)
2 zed 1811 .Select(x => x.Select(v => v.Value).ToList()));
1812 if (data.Count.Equals(0))
1813 throw new Exception();
1814  
3 eva 1815 vassalForm.Invoke((MethodInvoker) (() =>
2 zed 1816 {
3 eva 1817 // Remove rows that are not in the data update.
1818 foreach (
1819 int index in
1820 TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>()
1821 .Where(
1822 topCollidersRow =>
1823 !data.Any(q => q[2].Equals(topCollidersRow.Cells["TopCollidersUUID"].Value)))
1824 .Select(q => q.Index))
2 zed 1825 {
3 eva 1826 TopCollidersGridView.Rows.RemoveAt(index);
2 zed 1827 }
3 eva 1828 // Now update or add new data.
1829 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5)))
1830 {
1831 DataGridViewRow row =
1832 TopCollidersGridView.Rows.AsParallel()
1833 .Cast<DataGridViewRow>()
1834 .FirstOrDefault(q => q.Cells["TopCollidersUUID"].Value.Equals(dataComponents[2]));
1835 switch (row != null)
1836 {
1837 case true: // the row exists, so update it.
1838 row.Cells["TopCollidersScore"].Value = dataComponents[0];
1839 row.Cells["TopSCollidersTaskName"].Value = dataComponents[1];
1840 row.Cells["TopCollidersUUID"].Value = dataComponents[2];
1841 row.Cells["TopCollidersOwner"].Value = dataComponents[3];
1842 row.Cells["TopCollidersPosition"].Value = dataComponents[4];
1843 break;
1844 case false: // the row dosn't exist, so add it.
7 zed 1845 TopCollidersGridView.Rows.Add(dataComponents[0], dataComponents[1],
1846 dataComponents[2],
3 eva 1847 dataComponents[3], dataComponents[4]);
1848 break;
1849 }
1850 }
2 zed 1851  
1852 }));
1853 }
1854 catch (Exception)
1855 {
1856  
1857 }
1858 finally
1859 {
1860 Monitor.Exit(ClientInstanceTeleportLock);
1861 }
1862 };
1863 topCollidersTabTimer.Start();
7 zed 1864  
1865 // Start the resident list timer.
1866 residentListTimer.Elapsed += (o, p) =>
1867 {
1868 // Do not do anything in case the tab is not selected.
1869 bool run = false;
1870 vassalForm.Invoke((MethodInvoker) (() =>
1871 {
1872 run = Tabs.SelectedTab.Equals(ResidentListTab);
1873 }));
1874 if (!run) return;
1875  
1876 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1877 return;
1878  
1879 try
1880 {
1881 // Get the avatar positions.
1882 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1883 wasKeyValueEscape(new Dictionary<string, string>
1884 {
1885 {"command", "getavatarpositions"},
1886 {"group", vassalConfiguration.Group},
1887 {"password", vassalConfiguration.Password},
1888 {"entity", "region"}
1889 }), vassalConfiguration.DataTimeout);
1890  
1891 bool success;
1892 if (string.IsNullOrEmpty(result) ||
1893 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1894 throw new Exception();
1895  
1896 HashSet<List<string>> data =
1897 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1898 .Select((x, i) => new {Index = i, Value = x})
1899 .GroupBy(x => x.Index/3)
1900 .Select(x => x.Select(v => v.Value).ToList()));
1901 if (data.Count.Equals(0))
1902 throw new Exception();
1903  
1904 vassalForm.Invoke((MethodInvoker) (() =>
1905 {
1906 // Remove rows that are not in the data update.
1907 foreach (
1908 int index in
1909 ResidentListGridView.Rows.AsParallel().Cast<DataGridViewRow>()
1910 .Where(
1911 residentListRow =>
1912 !data.Any(q => q[1].Equals(residentListRow.Cells["ResidentListUUID"].Value)))
1913 .Select(q => q.Index))
1914 {
1915 ResidentListGridView.Rows.RemoveAt(index);
1916 }
1917 // Now update or add new data.
1918 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(3)))
1919 {
1920 DataGridViewRow row =
1921 ResidentListGridView.Rows.AsParallel()
1922 .Cast<DataGridViewRow>()
1923 .FirstOrDefault(q => q.Cells["ResidentListUUID"].Value.Equals(dataComponents[1]));
1924 switch (row != null)
1925 {
1926 case true: // the row exists, so update it.
1927 row.Cells["ResidentListName"].Value = dataComponents[0];
1928 row.Cells["ResidentListUUID"].Value = dataComponents[1];
1929 row.Cells["ResidentListPosition"].Value = dataComponents[2];
1930 break;
1931 case false: // the row dosn't exist, so add it.
1932 ResidentListGridView.Rows.Add(dataComponents[0], dataComponents[1],
1933 dataComponents[2]);
1934 break;
1935 }
1936 }
1937  
1938 }));
1939 }
1940 catch (Exception)
1941 {
1942  
1943 }
1944 finally
1945 {
1946 Monitor.Exit(ClientInstanceTeleportLock);
1947 }
1948 };
1949 residentListTimer.Start();
2 zed 1950 }
1951  
1952 private void RequestedEditRegions(object sender, EventArgs e)
1953 {
1954 // Clear any selection.
1955 LoadedRegions.SelectedIndex = -1;
3 eva 1956 RegionEditForm regionEditForm = new RegionEditForm {TopMost = true};
2 zed 1957 regionEditForm.Show();
1958 }
1959  
1960 private void RequestSelecting(object sender, TabControlCancelEventArgs e)
1961 {
1962 e.Cancel = !e.TabPage.Enabled;
1963 }
3 eva 1964  
1965 private void RequestExportTopScripts(object sender, EventArgs e)
1966 {
1967 vassalForm.BeginInvoke((MethodInvoker) (() =>
1968 {
1969 switch (vassalForm.ExportCSVDialog.ShowDialog())
1970 {
1971 case DialogResult.OK:
1972 string file = vassalForm.ExportCSVDialog.FileName;
1973 new Thread(() =>
1974 {
1975 vassalForm.BeginInvoke((MethodInvoker) (() =>
1976 {
1977 try
1978 {
1979 vassalForm.StatusText.Text = @"exporting...";
1980 vassalForm.StatusProgress.Value = 0;
1981  
1982 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
1983 {
1984 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows)
1985 {
1986 streamWriter.WriteLine(wasEnumerableToCSV(new[]
1987 {
1988 topScriptsRow.Cells["TopScriptsScore"].Value.ToString(),
1989 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString(),
1990 topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(),
1991 topScriptsRow.Cells["TopScriptsOwner"].Value.ToString(),
1992 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString()
1993 }));
1994 }
1995 }
1996  
1997 vassalForm.StatusText.Text = @"exported";
1998 vassalForm.StatusProgress.Value = 100;
1999 }
2000 catch (Exception ex)
2001 {
2002 vassalForm.StatusText.Text = ex.Message;
2003 }
2004 }));
2005 })
7 zed 2006 {IsBackground = true}.Start();
3 eva 2007 break;
2008 }
2009 }));
2010 }
2011  
2012 private void RequestExportTopColliders(object sender, EventArgs e)
2013 {
2014 vassalForm.BeginInvoke((MethodInvoker) (() =>
2015 {
2016 switch (vassalForm.ExportCSVDialog.ShowDialog())
2017 {
2018 case DialogResult.OK:
2019 string file = vassalForm.ExportCSVDialog.FileName;
2020 new Thread(() =>
2021 {
2022 vassalForm.BeginInvoke((MethodInvoker) (() =>
2023 {
2024 try
2025 {
2026 vassalForm.StatusText.Text = @"exporting...";
2027 vassalForm.StatusProgress.Value = 0;
2028  
2029 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
2030 {
2031 foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows)
2032 {
2033 streamWriter.WriteLine(wasEnumerableToCSV(new[]
2034 {
2035 topCollidersRow.Cells["TopCollidersScore"].Value.ToString(),
2036 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString(),
2037 topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(),
2038 topCollidersRow.Cells["TopCollidersOwner"].Value.ToString(),
2039 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString()
2040 }));
2041 }
2042 }
2043  
2044 vassalForm.StatusText.Text = @"exported";
2045 vassalForm.StatusProgress.Value = 100;
2046 }
2047 catch (Exception ex)
2048 {
2049 vassalForm.StatusText.Text = ex.Message;
2050 }
2051 }));
2052 })
7 zed 2053 {IsBackground = true}.Start();
3 eva 2054 break;
2055 }
2056 }));
2057 }
2058  
2059 private void RequestFilterTopScripts(object sender, EventArgs e)
2060 {
2061 vassalForm.BeginInvoke((MethodInvoker) (() =>
2062 {
2063 Regex topScriptsRowRegex;
2064 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
2065 {
2066 case true:
2067 topScriptsRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
2068 break;
2069 default:
2070 topScriptsRowRegex = new Regex(@".+?", RegexOptions.Compiled);
2071 break;
2072 }
2073 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>())
2074 {
2075 topScriptsRow.Visible =
2076 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsScore"].Value.ToString()) ||
2077 topScriptsRowRegex.IsMatch(
2078 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString()) ||
2079 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString()) ||
2080 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsOwner"].Value.ToString()) ||
2081 topScriptsRowRegex.IsMatch(
2082 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString());
2083 }
2084 }));
2085 }
2086  
2087 private void RequestFilterTopColliders(object sender, EventArgs e)
2088 {
7 zed 2089 vassalForm.BeginInvoke((MethodInvoker) (() =>
3 eva 2090 {
2091 Regex topCollidersRowRegex;
2092 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
2093 {
2094 case true:
2095 topCollidersRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
2096 break;
2097 default:
2098 topCollidersRowRegex = new Regex(@".+?", RegexOptions.Compiled);
2099 break;
2100 }
7 zed 2101 foreach (
2102 DataGridViewRow topCollidersRow in TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>())
3 eva 2103 {
2104 topCollidersRow.Visible =
2105 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersScore"].Value.ToString()) ||
2106 topCollidersRowRegex.IsMatch(
2107 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString()) ||
2108 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString()) ||
2109 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersOwner"].Value.ToString()) ||
2110 topCollidersRowRegex.IsMatch(
2111 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString());
2112 }
2113 }));
2114 }
2115  
2116 private void RequestReturnTopScriptsObjects(object sender, EventArgs e)
2117 {
2118 // Block teleports and disable button.
2119 vassalForm.Invoke((MethodInvoker) (() =>
2120 {
2121 vassalForm.ReturnTopScriptsButton.Enabled = false;
2122 RegionTeleportGroup.Enabled = false;
2123 }));
2124  
2125 // Enqueue all the UUIDs to return.
2126 Queue<KeyValuePair<UUID, Vector3>> returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>();
2127 vassalForm.Invoke((MethodInvoker) (() =>
2128 {
2129 foreach (
2130 DataGridViewRow topScriptsRow in
2131 TopScriptsGridView.Rows.AsParallel()
2132 .Cast<DataGridViewRow>()
2133 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
2134 {
2135 Vector3 objectPosition;
2136 UUID returnUUID;
2137 if (!UUID.TryParse(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(), out returnUUID) ||
2138 !Vector3.TryParse(topScriptsRow.Cells["TopScriptsPosition"].Value.ToString(), out objectPosition))
2139 continue;
2140 returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
2141 }
2142 }));
2143  
2144 // If no rows were selected, enable teleports, the return button and return.
2145 if (returnUUIDs.Count.Equals(0))
2146 {
7 zed 2147 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2148 {
2149 vassalForm.ReturnTopScriptsButton.Enabled = true;
2150 RegionTeleportGroup.Enabled = true;
2151 }));
2152 return;
2153 }
2154  
2155 new Thread(() =>
2156 {
2157 Monitor.Enter(ClientInstanceTeleportLock);
2158  
2159 try
2160 {
2161 vassalForm.Invoke((MethodInvoker) (() =>
2162 {
2163 vassalForm.StatusProgress.Value = 0;
2164 }));
2165 int totalObjects = returnUUIDs.Count;
2166 do
2167 {
2168 // Dequeue the first object.
2169 KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue();
2170  
2171 vassalForm.Invoke((MethodInvoker) (() =>
2172 {
2173 vassalForm.StatusText.Text = @"Returning object UUID: " + objectData.Key.ToString();
2174 }));
2175  
2176 string currentRegionName = string.Empty;
2177 vassalForm.Invoke((MethodInvoker) (() =>
2178 {
2179 currentRegionName = CurrentRegionName.Text;
2180 }));
7 zed 2181  
3 eva 2182 // Teleport to the object.
2183 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2184 wasKeyValueEscape(new Dictionary<string, string>
2185 {
2186 {"command", "teleport"},
2187 {"group", vassalConfiguration.Group},
2188 {"password", vassalConfiguration.Password},
2189 {"position", objectData.Value.ToString()},
2190 {"region", currentRegionName},
2191 {"fly", "True"}
2192 }), vassalConfiguration.TeleportTimeout);
2193  
2194 if (string.IsNullOrEmpty(result))
2195 {
7 zed 2196 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2197 {
2198 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
2199 }));
2200 continue;
2201 }
2202  
2203 // Return the object.
2204 result = wasPOST(vassalConfiguration.HTTPServerURL,
2205 wasKeyValueEscape(new Dictionary<string, string>
2206 {
2207 {"command", "derez"},
2208 {"group", vassalConfiguration.Group},
2209 {"password", vassalConfiguration.Password},
2210 {"item", objectData.Key.ToString()},
7 zed 2211 {"range", "32"}, // maximal prim size = 64 - middle bounding box at half
3 eva 2212 {"type", "ReturnToOwner"}
2213 }), vassalConfiguration.DataTimeout);
2214  
2215 if (string.IsNullOrEmpty(result))
2216 {
2217 vassalForm.Invoke((MethodInvoker) (() =>
2218 {
2219 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
2220 }));
2221 continue;
2222 }
2223  
2224 bool success;
2225 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2226 {
2227 vassalForm.Invoke((MethodInvoker) (() =>
2228 {
2229 vassalForm.StatusText.Text = @"No success status could be retrieved. ";
2230 }));
2231 continue;
2232 }
2233  
2234 switch (success)
2235 {
2236 case true:
2237 vassalForm.Invoke((MethodInvoker) (() =>
2238 {
2239 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString();
2240 // Remove the row from the grid view.
7 zed 2241 DataGridViewRow row =
2242 TopScriptsGridView.Rows.AsParallel()
2243 .Cast<DataGridViewRow>()
2244 .FirstOrDefault(
2245 o => o.Cells["TopScriptsUUID"].Value.Equals(objectData.Key.ToString()));
3 eva 2246 if (row == null) return;
2247 int i = row.Index;
2248 TopScriptsGridView.Rows.RemoveAt(i);
2249 }));
2250 break;
2251 case false:
2252 vassalForm.Invoke((MethodInvoker) (() =>
2253 {
2254 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() +
2255 @": " +
2256 wasInput(wasKeyValueGet("error", result));
2257 }));
2258 break;
2259 }
2260  
2261 vassalForm.Invoke((MethodInvoker) (() =>
2262 {
2263 vassalForm.StatusProgress.Value =
2264 Math.Min((int) (Math.Abs(returnUUIDs.Count - totalObjects)/
2265 (double) totalObjects), 100);
2266 }));
2267 } while (!returnUUIDs.Count.Equals(0));
2268 vassalForm.Invoke((MethodInvoker) (() =>
2269 {
2270 vassalForm.StatusProgress.Value = 100;
2271 }));
2272 }
2273 catch (Exception ex)
2274 {
7 zed 2275 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2276 {
2277 vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message;
2278 }));
2279 }
2280 finally
2281 {
2282 Monitor.Exit(ClientInstanceTeleportLock);
2283 // Allow teleports and enable button.
7 zed 2284 vassalForm.BeginInvoke((MethodInvoker) (() =>
3 eva 2285 {
2286 vassalForm.ReturnTopScriptsButton.Enabled = true;
2287 RegionTeleportGroup.Enabled = true;
2288 }));
2289 }
2290 })
2291 {IsBackground = true}.Start();
2292 }
2293  
2294 private void RequestReturnTopCollidersObjects(object sender, EventArgs e)
2295 {
2296 // Block teleports and disable button.
7 zed 2297 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2298 {
2299 vassalForm.ReturnTopCollidersButton.Enabled = false;
2300 RegionTeleportGroup.Enabled = false;
2301 }));
2302  
2303 // Enqueue all the UUIDs to return.
7 zed 2304 Queue<KeyValuePair<UUID, Vector3>> returnObjectUUIDQueue = new Queue<KeyValuePair<UUID, Vector3>>();
2305 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2306 {
2307 foreach (
2308 DataGridViewRow topCollidersRow in
2309 TopCollidersGridView.Rows.AsParallel()
2310 .Cast<DataGridViewRow>()
2311 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
2312 {
2313 Vector3 objectPosition;
2314 UUID returnUUID;
2315 if (!UUID.TryParse(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(), out returnUUID) ||
7 zed 2316 !Vector3.TryParse(topCollidersRow.Cells["TopCollidersPosition"].Value.ToString(),
2317 out objectPosition))
3 eva 2318 continue;
7 zed 2319 returnObjectUUIDQueue.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
3 eva 2320 }
2321 }));
2322  
2323 // If no rows were selected, enable teleports, the return button and return.
7 zed 2324 if (returnObjectUUIDQueue.Count.Equals(0))
3 eva 2325 {
7 zed 2326 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2327 {
2328 vassalForm.ReturnTopCollidersButton.Enabled = true;
2329 RegionTeleportGroup.Enabled = true;
2330 }));
2331 return;
2332 }
2333  
2334 new Thread(() =>
2335 {
2336 Monitor.Enter(ClientInstanceTeleportLock);
2337  
2338 try
2339 {
7 zed 2340 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2341 {
2342 vassalForm.StatusProgress.Value = 0;
2343 }));
7 zed 2344 int totalObjects = returnObjectUUIDQueue.Count;
3 eva 2345 do
2346 {
2347 // Dequeue the first object.
7 zed 2348 KeyValuePair<UUID, Vector3> objectData = returnObjectUUIDQueue.Dequeue();
3 eva 2349  
7 zed 2350 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2351 {
2352 vassalForm.StatusText.Text = @"Returning UUID: " + objectData.Key.ToString();
2353 }));
2354  
2355 string currentRegionName = string.Empty;
7 zed 2356 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2357 {
2358 currentRegionName = CurrentRegionName.Text;
2359 }));
2360  
2361 // Teleport to the object.
2362 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2363 wasKeyValueEscape(new Dictionary<string, string>
2364 {
2365 {"command", "teleport"},
2366 {"group", vassalConfiguration.Group},
2367 {"password", vassalConfiguration.Password},
2368 {"position", objectData.Value.ToString()},
2369 {"region", currentRegionName},
2370 {"fly", "True"}
2371 }), vassalConfiguration.DataTimeout);
2372  
2373 if (string.IsNullOrEmpty(result))
2374 {
7 zed 2375 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2376 {
2377 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
2378 }));
2379 continue;
2380 }
2381  
2382 // Return the object.
2383 result = wasPOST(vassalConfiguration.HTTPServerURL,
2384 wasKeyValueEscape(new Dictionary<string, string>
2385 {
2386 {"command", "derez"},
2387 {"group", vassalConfiguration.Group},
2388 {"password", vassalConfiguration.Password},
2389 {"item", objectData.Key.ToString()},
7 zed 2390 {"range", "32"}, // maximal prim size = 64 - middle bounding box at half
3 eva 2391 {"type", "ReturnToOwner"}
2392 }), vassalConfiguration.DataTimeout);
2393  
2394 if (string.IsNullOrEmpty(result))
2395 {
7 zed 2396 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2397 {
2398 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
2399 }));
2400 continue;
2401 }
2402  
2403 bool success;
2404 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2405 {
7 zed 2406 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2407 {
2408 vassalForm.StatusText.Text = @"No success status could be retrieved. ";
2409 }));
2410 continue;
2411 }
2412  
2413 switch (success)
2414 {
2415 case true:
7 zed 2416 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2417 {
2418 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString();
2419 // Remove the row from the grid view.
2420 DataGridViewRow row =
7 zed 2421 TopCollidersGridView.Rows.AsParallel()
2422 .Cast<DataGridViewRow>()
2423 .FirstOrDefault(
2424 o => o.Cells["TopCollidersUUID"].Value.Equals(objectData.Key.ToString()));
3 eva 2425 if (row == null) return;
2426 int i = row.Index;
2427 TopCollidersGridView.Rows.RemoveAt(i);
2428 }));
2429 break;
2430 case false:
7 zed 2431 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2432 {
2433 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() +
2434 @": " +
2435 wasInput(wasKeyValueGet("error", result));
2436 }));
2437 break;
2438 }
2439  
7 zed 2440 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2441 {
2442 vassalForm.StatusProgress.Value =
7 zed 2443 Math.Min((int) (Math.Abs(returnObjectUUIDQueue.Count - totalObjects)/
2444 (double) totalObjects), 100);
3 eva 2445 }));
7 zed 2446 } while (!returnObjectUUIDQueue.Count.Equals(0));
2447 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2448 {
2449 vassalForm.StatusProgress.Value = 100;
2450 }));
2451 }
2452 catch (Exception ex)
2453 {
7 zed 2454 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 2455 {
2456 vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message;
2457 }));
2458 }
2459 finally
2460 {
2461 Monitor.Exit(ClientInstanceTeleportLock);
2462 // Allow teleports and enable button.
7 zed 2463 vassalForm.BeginInvoke((MethodInvoker) (() =>
3 eva 2464 {
2465 vassalForm.ReturnTopScriptsButton.Enabled = true;
2466 RegionTeleportGroup.Enabled = true;
2467 }));
2468 }
2469 })
7 zed 2470 {IsBackground = true}.Start();
3 eva 2471 }
2472  
2473 private void RequestBatchRestart(object sender, EventArgs e)
2474 {
7 zed 2475 // Block teleports and disable button.
2476 vassalForm.Invoke((MethodInvoker) (() =>
2477 {
2478 vassalForm.BatchRestartButton.Enabled = false;
2479 RegionTeleportGroup.Enabled = false;
2480 }));
3 eva 2481  
7 zed 2482 // Enqueue all the regions to restart.
2483 Queue<KeyValuePair<string, Vector3>> restartRegionQueue = new Queue<KeyValuePair<string, Vector3>>();
2484 vassalForm.Invoke((MethodInvoker) (() =>
2485 {
2486 foreach (
2487 DataGridViewRow topCollidersRow in
2488 BatchRestartGridView.Rows.AsParallel()
2489 .Cast<DataGridViewRow>()
2490 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
2491 {
2492 Vector3 objectPosition;
2493 string regionName = topCollidersRow.Cells["BatchRestartRegionName"].Value.ToString();
2494 if (string.IsNullOrEmpty(regionName) ||
2495 !Vector3.TryParse(topCollidersRow.Cells["BatchRestartPosition"].Value.ToString(),
2496 out objectPosition))
2497 continue;
2498 restartRegionQueue.Enqueue(new KeyValuePair<string, Vector3>(regionName, objectPosition));
2499 }
2500 }));
2501  
2502 // If no rows were selected, enable teleports, the return button and return.
2503 if (restartRegionQueue.Count.Equals(0))
2504 {
2505 vassalForm.Invoke((MethodInvoker) (() =>
2506 {
2507 vassalForm.BatchRestartButton.Enabled = true;
2508 RegionTeleportGroup.Enabled = true;
2509 }));
2510 return;
2511 }
2512  
2513 new Thread(() =>
2514 {
2515 Monitor.Enter(ClientInstanceTeleportLock);
2516  
2517 try
2518 {
2519 do
2520 {
2521 // Dequeue the first object.
2522 KeyValuePair<string, Vector3> restartRegionData = restartRegionQueue.Dequeue();
2523 DataGridViewRow currentDataGridViewRow = null;
2524 vassalForm.Invoke((MethodInvoker) (() =>
2525 {
2526 currentDataGridViewRow = vassalForm.BatchRestartGridView.Rows.AsParallel()
2527 .Cast<DataGridViewRow>()
2528 .FirstOrDefault(
2529 o =>
2530 o.Cells["BatchRestartRegionName"].Value.ToString()
2531 .Equals(restartRegionData.Key, StringComparison.OrdinalIgnoreCase) &&
2532 o.Cells["BatchRestartPosition"].Value.ToString()
2533 .Equals(restartRegionData.Value.ToString(),
2534 StringComparison.OrdinalIgnoreCase));
2535 }));
2536  
2537 if (currentDataGridViewRow == null) continue;
2538  
2539 try
2540 {
2541 bool success = false;
2542 string result;
2543  
2544 // Retry to teleport to each region a few times.
2545 int teleportRetries = 3;
2546 do
2547 {
2548 vassalForm.Invoke((MethodInvoker) (() =>
2549 {
2550 vassalForm.StatusText.Text = @"Attempting to teleport to " + restartRegionData.Key +
2551 @" " + @"(" +
2552 teleportRetries.ToString(Utils.EnUsCulture) +
2553 @")";
2554 }));
2555  
2556 // Teleport to the region.
2557 result = wasPOST(vassalConfiguration.HTTPServerURL,
2558 wasKeyValueEscape(new Dictionary<string, string>
2559 {
2560 {"command", "teleport"},
2561 {"group", vassalConfiguration.Group},
2562 {"password", vassalConfiguration.Password},
2563 {"position", restartRegionData.Value.ToString()},
2564 {"region", restartRegionData.Key},
2565 {"fly", "True"}
2566 }), vassalConfiguration.DataTimeout);
2567  
2568 if (string.IsNullOrEmpty(result))
2569 {
2570 vassalForm.Invoke((MethodInvoker) (() =>
2571 {
2572 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
2573 }));
2574 continue;
2575 }
2576 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2577 {
2578 vassalForm.Invoke((MethodInvoker) (() =>
2579 {
2580 vassalForm.StatusText.Text = @"No success status could be retrieved. ";
2581 }));
2582 continue;
2583 }
2584 switch (success)
2585 {
2586 case true:
2587 vassalForm.Invoke((MethodInvoker) (() =>
2588 {
2589 vassalForm.StatusText.Text = @"Teleport succeeded.";
2590 }));
2591 Thread.Sleep(TimeSpan.FromSeconds(1).Milliseconds);
2592 break;
2593 default:
2594 // In case the destination is to close (Corrade status code 37559),
2595 // then we are on the same region so no need to retry.
2596 uint status; //37559
2597 switch (
2598 uint.TryParse(wasInput(wasKeyValueGet("status", result)), out status) &&
2599 status.Equals(37559))
2600 {
2601 case true: // We are on the region already!
2602 success = true;
2603 break;
2604 default:
2605 vassalForm.Invoke((MethodInvoker) (() =>
2606 {
2607 vassalForm.StatusText.Text = @"Teleport failed.";
2608 }));
2609 Thread.Sleep(10000);
2610 break;
2611 }
2612 break;
2613 }
2614 } while (!success && !(--teleportRetries).Equals(0));
2615  
2616 if (!success)
2617 throw new Exception("Failed to teleport to region.");
2618  
2619 result = wasPOST(vassalConfiguration.HTTPServerURL,
2620 wasKeyValueEscape(new Dictionary<string, string>
2621 {
2622 {"command", "getregiondata"},
2623 {"group", vassalConfiguration.Group},
2624 {"password", vassalConfiguration.Password},
2625 {"data", "IsEstateManager"}
2626 }), vassalConfiguration.DataTimeout);
2627  
2628 if (string.IsNullOrEmpty(result))
2629 throw new Exception("Error communicating with Corrade.");
2630  
2631 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2632 throw new Exception("No success status could be retrieved.");
2633  
2634 if (!success)
2635 throw new Exception("Could not retrieve estate rights.");
2636  
2637 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
2638 if (!data.Count.Equals(2))
2639 throw new Exception("Could not retrieve estate rights.");
2640  
2641 bool isEstateManager;
2642 switch (
2643 bool.TryParse(data[data.IndexOf("IsEstateManager") + 1], out isEstateManager) &&
2644 isEstateManager)
2645 {
2646 case true: // we are an estate manager
2647 result = wasPOST(vassalConfiguration.HTTPServerURL,
2648 wasKeyValueEscape(new Dictionary<string, string>
2649 {
2650 {"command", "restartregion"},
2651 {"group", vassalConfiguration.Group},
2652 {"password", vassalConfiguration.Password},
2653 {"action", "restart"},
2654 {
2655 "delay", vassalConfiguration.RegionRestartDelay.ToString(Utils.EnUsCulture)
2656 }
2657 }), vassalConfiguration.DataTimeout);
2658  
2659 if (string.IsNullOrEmpty(result))
2660 throw new Exception("Error communicating with Corrade.");
2661  
2662 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2663 throw new Exception("No success status could be retrieved.");
2664  
2665 if (!success)
2666 throw new Exception("Could not schedule a region restart.");
2667  
2668 vassalForm.Invoke((MethodInvoker) (() =>
2669 {
2670 vassalForm.StatusText.Text = @"Region scheduled for restart.";
2671 currentDataGridViewRow.Selected = false;
2672 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
2673 foreach (
2674 DataGridViewCell cell in
2675 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
2676 {
2677 cell.ToolTipText = @"Region scheduled for restart.";
2678 }
2679 }));
2680 break;
2681 default:
2682 throw new Exception("No estate manager rights for region restart.");
2683 }
2684 }
2685 catch (Exception ex)
2686 {
2687 vassalForm.Invoke((MethodInvoker) (() =>
2688 {
2689 vassalForm.StatusText.Text = ex.Message;
2690 currentDataGridViewRow.Selected = false;
2691 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
2692 foreach (
2693 DataGridViewCell cell in
2694 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
2695 {
2696 cell.ToolTipText = ex.Message;
2697 }
2698 }));
2699 }
2700 } while (!restartRegionQueue.Count.Equals(0));
2701 }
2702 catch (Exception)
2703 {
2704  
2705 }
2706 finally
2707 {
2708 Monitor.Exit(ClientInstanceTeleportLock);
2709 // Allow teleports and enable button.
2710 vassalForm.BeginInvoke((MethodInvoker) (() =>
2711 {
2712 vassalForm.BatchRestartButton.Enabled = true;
2713 RegionTeleportGroup.Enabled = true;
2714 }));
2715 }
2716 })
2717 {IsBackground = true}.Start();
2718  
3 eva 2719 }
7 zed 2720  
2721 private void RequestFilterResidentList(object sender, EventArgs e)
2722 {
2723 vassalForm.BeginInvoke((MethodInvoker) (() =>
2724 {
2725 Regex residentListRowRegex;
2726 switch (!string.IsNullOrEmpty(ResidentListFilter.Text))
2727 {
2728 case true:
2729 residentListRowRegex = new Regex(ResidentListFilter.Text, RegexOptions.Compiled);
2730 break;
2731 default:
2732 residentListRowRegex = new Regex(@".+?", RegexOptions.Compiled);
2733 break;
2734 }
2735 foreach (
2736 DataGridViewRow residentListRow in ResidentListGridView.Rows.AsParallel().Cast<DataGridViewRow>())
2737 {
2738 residentListRow.Visible =
2739 residentListRowRegex.IsMatch(residentListRow.Cells["ResidentListName"].Value.ToString()) ||
2740 residentListRowRegex.IsMatch(
2741 residentListRow.Cells["ResidentListUUID"].Value.ToString()) ||
2742 residentListRowRegex.IsMatch(residentListRow.Cells["ResidentListPosition"].Value.ToString());
2743 }
2744 }));
2745 }
2746  
2747 private void RequestBanAgents(object sender, EventArgs e)
2748 {
2749 // Block teleports and disable button.
2750 vassalForm.Invoke((MethodInvoker) (() =>
2751 {
2752 ResidentListBanGroup.Enabled = false;
2753 RegionTeleportGroup.Enabled = false;
2754 }));
2755  
2756 // Enqueue all the regions to restart.
2757 Queue<UUID> agentsQueue = new Queue<UUID>();
2758 vassalForm.Invoke((MethodInvoker) (() =>
2759 {
2760 foreach (
2761 DataGridViewRow residentListRow in
2762 ResidentListGridView.Rows.AsParallel()
2763 .Cast<DataGridViewRow>()
2764 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
2765 {
2766 UUID agentUUID;
2767 if (!UUID.TryParse(residentListRow.Cells["ResidentListUUID"].Value.ToString(), out agentUUID))
2768 continue;
2769 agentsQueue.Enqueue(agentUUID);
2770 }
2771 }));
2772  
2773 // If no rows were selected, enable teleports, the return button and return.
2774 if (agentsQueue.Count.Equals(0))
2775 {
2776 vassalForm.Invoke((MethodInvoker) (() =>
2777 {
2778 ResidentListBanGroup.Enabled = true;
2779 RegionTeleportGroup.Enabled = true;
2780 }));
2781 return;
2782 }
2783  
2784 new Thread(() =>
2785 {
2786 Monitor.Enter(ClientInstanceTeleportLock);
2787 try
2788 {
2789 do
2790 {
2791 // Dequeue the first object.
2792 UUID agentUUID = agentsQueue.Dequeue();
2793 DataGridViewRow currentDataGridViewRow = null;
2794 vassalForm.Invoke((MethodInvoker) (() =>
2795 {
2796 currentDataGridViewRow = vassalForm.ResidentListGridView.Rows.AsParallel()
2797 .Cast<DataGridViewRow>()
2798 .FirstOrDefault(
2799 o =>
2800 o.Cells["ResidentListUUID"].Value.ToString()
2801 .Equals(agentUUID.ToString(), StringComparison.OrdinalIgnoreCase));
2802 }));
2803  
2804 if (currentDataGridViewRow == null) continue;
2805  
2806 try
2807 {
2808 bool alsoBan = false;
2809 vassalForm.Invoke((MethodInvoker) (() =>
2810 {
2811 alsoBan = vassalForm.ResidentBanAllEstatesBox.Checked;
2812 }));
2813  
2814 // Teleport to the region.
2815 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2816 wasKeyValueEscape(new Dictionary<string, string>
2817 {
2818 {"command", "setestatelist"},
2819 {"group", vassalConfiguration.Group},
2820 {"password", vassalConfiguration.Password},
2821 {"type", "ban"},
2822 {"action", "add"},
2823 {"agent", agentUUID.ToString()},
2824 {"all", alsoBan.ToString()}
2825 }), vassalConfiguration.DataTimeout);
2826  
2827 if (string.IsNullOrEmpty(result))
2828 throw new Exception("Error communicating with Corrade.");
2829  
2830 bool success;
2831 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2832 throw new Exception("No success status could be retrieved.");
2833  
2834 switch (success)
2835 {
2836 case true:
2837 vassalForm.Invoke((MethodInvoker) (() =>
2838 {
2839 vassalForm.StatusText.Text = @"Resident banned.";
2840 currentDataGridViewRow.Selected = false;
2841 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
2842 foreach (
2843 DataGridViewCell cell in
2844 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
2845 {
2846 cell.ToolTipText = @"Resident banned.";
2847 }
2848 }));
2849 break;
2850 default:
2851 throw new Exception("Unable to ban resident.");
2852 }
2853 }
2854 catch (Exception ex)
2855 {
2856 vassalForm.Invoke((MethodInvoker) (() =>
2857 {
2858 vassalForm.StatusText.Text = ex.Message;
2859 currentDataGridViewRow.Selected = false;
2860 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
2861 foreach (
2862 DataGridViewCell cell in
2863 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
2864 {
2865 cell.ToolTipText = ex.Message;
2866 }
2867 }));
2868 }
2869  
2870 } while (agentsQueue.Count.Equals(0));
2871 }
2872 catch (Exception)
2873 {
2874  
2875 }
2876 finally
2877 {
2878 Monitor.Exit(ClientInstanceTeleportLock);
2879 // Allow teleports and enable button.
2880 vassalForm.BeginInvoke((MethodInvoker) (() =>
2881 {
2882 ResidentListBanGroup.Enabled = true;
2883 RegionTeleportGroup.Enabled = true;
2884 }));
2885 }
2886 })
2887 {IsBackground = true}.Start();
2888 }
2889  
2890 private void RequestRipTerrain(object sender, EventArgs e)
2891 {
2892 // Block teleports and disable button.
2893 vassalForm.Invoke((MethodInvoker) (() =>
2894 {
2895 RegionTeleportGroup.Enabled = false;
2896 RipTerrainButton.Enabled = false;
2897 }));
2898  
2899 new Thread(() =>
2900 {
2901 Monitor.Enter(ClientInstanceTeleportLock);
2902  
2903 try
2904 {
2905 // Get the statistics.
2906 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2907 wasKeyValueEscape(new Dictionary<string, string>
2908 {
2909 {"command", "getterrainheight"},
2910 {"group", vassalConfiguration.Group},
2911 {"password", vassalConfiguration.Password},
2912 {"entity", "region"}
2913 }), vassalConfiguration.DataTimeout);
2914  
2915 if (string.IsNullOrEmpty(result))
2916 throw new Exception("Error communicating with Corrade.");
2917  
2918 bool success;
2919 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2920 throw new Exception("No success status could be retrieved.");
2921  
2922 if (!success)
2923 throw new Exception("Could not get terrain heights.");
2924  
2925 List<double> heights = new List<double>();
2926 foreach (string map in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))))
2927 {
2928 double height;
2929 if (!double.TryParse(map, out height))
2930 continue;
2931 heights.Add(height);
2932 }
2933 if (heights.Count.Equals(0))
2934 throw new Exception("Could not get terrain heights.");
2935  
2936 double maxHeight = heights.Max();
2937 using (Bitmap bitmap = new Bitmap(256, 256))
2938 {
2939 foreach (int x in Enumerable.Range(1, 255))
2940 {
2941 foreach (int y in Enumerable.Range(1, 255))
2942 {
2943 bitmap.SetPixel(x, 256 - y,
2944 Color.FromArgb((int) wasMapValueToRange(heights[256*x + y], 0, maxHeight, 0, 255), 0, 0));
2945 }
2946 }
2947 Bitmap closureBitmap = (Bitmap)bitmap.Clone();
2948 vassalForm.BeginInvoke((MethodInvoker) (() =>
2949 {
2950 switch (vassalForm.SaveTerrainFileDialog.ShowDialog())
2951 {
2952 case DialogResult.OK:
2953 string file = vassalForm.SaveTerrainFileDialog.FileName;
2954 new Thread(() =>
2955 {
2956 vassalForm.BeginInvoke((MethodInvoker) (() =>
2957 {
2958 try
2959 {
2960 vassalForm.StatusText.Text = @"saving terrain...";
2961 vassalForm.StatusProgress.Value = 0;
2962  
2963 closureBitmap.Save(file, ImageFormat.Png);
2964  
2965 vassalForm.StatusText.Text = @"terrain saved";
2966 vassalForm.StatusProgress.Value = 100;
2967 }
2968 catch (Exception ex)
2969 {
2970 vassalForm.StatusText.Text = ex.Message;
2971 }
2972 finally
2973 {
2974 closureBitmap.Dispose();
2975 }
2976 }));
2977 })
2978 {IsBackground = true, Priority = ThreadPriority.Normal}.Start();
2979 break;
2980 }
2981 }));
2982 }
2983  
2984 }
2985 catch (Exception ex)
2986 {
2987 vassalForm.BeginInvoke((MethodInvoker)(() =>
2988 {
2989 StatusText.Text = ex.Message;
2990 }));
2991 }
2992 finally
2993 {
2994 Monitor.Exit(ClientInstanceTeleportLock);
2995 vassalForm.BeginInvoke((MethodInvoker)(() =>
2996 {
2997 RegionTeleportGroup.Enabled = true;
2998 RipTerrainButton.Enabled = true;
2999 }));
3000 }
3001  
3002 }) {IsBackground = true}.Start();
3003 }
2 zed 3004 }
3005 }