corrade-vassal – Blame information for rev 12

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.Generic;
12 zed 9 using System.Diagnostics;
2 zed 10 using System.Drawing;
7 zed 11 using System.Drawing.Imaging;
2 zed 12 using System.IO;
13 using System.Linq;
14 using System.Net;
7 zed 15 using System.Net.Sockets;
2 zed 16 using System.Reflection;
17 using System.Text;
18 using System.Text.RegularExpressions;
19 using System.Threading;
20 using System.Web;
21 using System.Windows.Forms;
22 using OpenMetaverse;
23 using Parallel = System.Threading.Tasks.Parallel;
24 using Timer = System.Timers.Timer;
25  
26 namespace Vassal
27 {
28 public partial class Vassal : Form
29 {
8 eva 30 public static Timer vassalTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
31 public static Timer overviewTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
32 public static Timer residentListTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
33 public static Timer estateTopTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
34 public static Timer regionsStateTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
35 public static Timer estateTexturesTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
36 public static Image[] groundTextureImages = new Image[4];
37 public static volatile int regionsStateCheckIndex;
2 zed 38 public static VassalConfiguration vassalConfiguration = new VassalConfiguration();
39 public static Vassal vassalForm;
40 public static readonly object ClientInstanceTeleportLock = new object();
7 zed 41 public static readonly object RegionsStateCheckLock = new object();
2 zed 42  
7 zed 43 /// <summary>
8 eva 44 /// Corrade's input filter function.
7 zed 45 /// </summary>
8 eva 46 private static readonly Func<string, string> wasInput = o =>
7 zed 47 {
8 eva 48 if (string.IsNullOrEmpty(o)) return string.Empty;
7 zed 49  
8 eva 50 foreach (Filter filter in vassalConfiguration.InputFilters)
7 zed 51 {
8 eva 52 switch (filter)
7 zed 53 {
8 eva 54 case Filter.RFC1738:
55 o = wasURLUnescapeDataString(o);
56 break;
57 case Filter.RFC3986:
58 o = wasURIUnescapeDataString(o);
59 break;
60 case Filter.ENIGMA:
61 o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
62 vassalConfiguration.ENIGMA.plugs.ToArray(),
63 vassalConfiguration.ENIGMA.reflector);
64 break;
65 case Filter.VIGENERE:
66 o = wasDecryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
67 break;
68 case Filter.ATBASH:
69 o = wasATBASH(o);
70 break;
71 case Filter.BASE64:
72 o = Encoding.UTF8.GetString(Convert.FromBase64String(o));
73 break;
7 zed 74 }
75 }
8 eva 76 return o;
77 };
7 zed 78  
8 eva 79 /// <summary>
80 /// Corrade's output filter function.
81 /// </summary>
82 private static readonly Func<string, string> wasOutput = o =>
83 {
84 if (string.IsNullOrEmpty(o)) return string.Empty;
85  
86 foreach (Filter filter in vassalConfiguration.OutputFilters)
7 zed 87 {
8 eva 88 switch (filter)
7 zed 89 {
8 eva 90 case Filter.RFC1738:
91 o = wasURLEscapeDataString(o);
92 break;
93 case Filter.RFC3986:
94 o = wasURIEscapeDataString(o);
95 break;
96 case Filter.ENIGMA:
97 o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
98 vassalConfiguration.ENIGMA.plugs.ToArray(),
99 vassalConfiguration.ENIGMA.reflector);
100 break;
101 case Filter.VIGENERE:
102 o = wasEncryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
103 break;
104 case Filter.ATBASH:
105 o = wasATBASH(o);
106 break;
107 case Filter.BASE64:
108 o = Convert.ToBase64String(Encoding.UTF8.GetBytes(o));
109 break;
7 zed 110 }
111 }
8 eva 112 return o;
113 };
7 zed 114  
8 eva 115 private static readonly Action updateCurrentRegionName = () =>
116 {
117 try
7 zed 118 {
8 eva 119 string result = wasPOST(vassalConfiguration.HTTPServerURL,
120 wasKeyValueEscape(new Dictionary<string, string>
121 {
122 {"command", "getregiondata"},
123 {"group", vassalConfiguration.Group},
124 {"password", vassalConfiguration.Password},
125 {"data", "Name"}
126 }), 60000);
127 bool success;
128 if (string.IsNullOrEmpty(result) ||
129 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
7 zed 130 {
8 eva 131 vassalForm.BeginInvoke(
132 (MethodInvoker)
133 (() => { vassalForm.StatusText.Text = @"Failed to query Corrade for current region."; }));
134 return;
7 zed 135 }
8 eva 136 switch (success)
7 zed 137 {
8 eva 138 case true:
139 vassalForm.BeginInvoke((MethodInvoker) (() =>
140 {
141 vassalForm.CurrentRegionAt.Visible = true;
142 vassalForm.CurrentRegionName.Visible = true;
143 vassalForm.CurrentRegionName.Text =
144 wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).Last();
145 }));
146 break;
147 default:
148 vassalForm.BeginInvoke((MethodInvoker) (() =>
149 {
150 vassalForm.CurrentRegionAt.Visible = false;
151 vassalForm.CurrentRegionName.Visible = false;
152 vassalForm.StatusText.Text = @"Error getting current region: " +
153 wasInput(wasKeyValueGet("error", result));
154 }));
155 break;
7 zed 156 }
157 }
8 eva 158 catch (Exception ex)
7 zed 159 {
8 eva 160 vassalForm.BeginInvoke((MethodInvoker) (() =>
7 zed 161 {
8 eva 162 vassalForm.StatusText.Text =
163 @"Error getting current region: " +
164 ex.Message;
165 }));
7 zed 166 }
8 eva 167 };
7 zed 168  
8 eva 169 public Vassal()
170 {
171 InitializeComponent();
172 vassalForm = this;
7 zed 173 }
174  
2 zed 175 ///////////////////////////////////////////////////////////////////////////
176 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
177 ///////////////////////////////////////////////////////////////////////////
7 zed 178 private static double wasMapValueToRange(double value, double xMin, double xMax, double yMin, double yMax)
179 {
180 return yMin + (
181 (
182 yMax - yMin
183 )
184 *
185 (
186 value - xMin
187 )
188 /
189 (
190 xMax - xMin
191 )
192 );
193 }
194  
195 ///////////////////////////////////////////////////////////////////////////
196 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
197 ///////////////////////////////////////////////////////////////////////////
2 zed 198 /// <summary>RFC1738 URL Escapes a string</summary>
199 /// <param name="data">a string to escape</param>
200 /// <returns>an RFC1738 escaped string</returns>
201 private static string wasURLEscapeDataString(string data)
202 {
203 return HttpUtility.UrlEncode(data);
204 }
205  
206 ///////////////////////////////////////////////////////////////////////////
207 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
208 ///////////////////////////////////////////////////////////////////////////
209 /// <summary>RFC1738 URL Unescape a string</summary>
210 /// <param name="data">a string to unescape</param>
211 /// <returns>an RFC1738 unescaped string</returns>
212 private static string wasURLUnescapeDataString(string data)
213 {
214 return HttpUtility.UrlDecode(data);
215 }
216  
217 ///////////////////////////////////////////////////////////////////////////
218 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
219 ///////////////////////////////////////////////////////////////////////////
220 /// <summary>URI unescapes an RFC3986 URI escaped string</summary>
221 /// <param name="data">a string to unescape</param>
222 /// <returns>the resulting string</returns>
223 private static string wasURIUnescapeDataString(string data)
224 {
225 // Uri.UnescapeDataString can only handle 32766 characters at a time
226 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766)
227 .Select(o => Uri.UnescapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766)))))
228 .ToArray());
229 }
230  
231 ///////////////////////////////////////////////////////////////////////////
232 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
233 ///////////////////////////////////////////////////////////////////////////
234 /// <summary>RFC3986 URI Escapes a string</summary>
235 /// <param name="data">a string to escape</param>
236 /// <returns>an RFC3986 escaped string</returns>
237 private static string wasURIEscapeDataString(string data)
238 {
239 // Uri.EscapeDataString can only handle 32766 characters at a time
240 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766)
241 .Select(o => Uri.EscapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766)))))
242 .ToArray());
243 }
244  
245 ///////////////////////////////////////////////////////////////////////////
246 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
247 ///////////////////////////////////////////////////////////////////////////
248 /// <summary>
249 /// Gets an array element at a given modulo index.
250 /// </summary>
251 /// <typeparam name="T">the array type</typeparam>
252 /// <param name="index">a positive or negative index of the element</param>
253 /// <param name="data">the array</param>
254 /// <return>an array element</return>
255 public static T wasGetElementAt<T>(T[] data, int index)
256 {
257 switch (index < 0)
258 {
259 case true:
260 return data[((index%data.Length) + data.Length)%data.Length];
261 default:
262 return data[index%data.Length];
263 }
264 }
265  
266 #region KEY-VALUE DATA
267  
268 ///////////////////////////////////////////////////////////////////////////
269 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
270 ///////////////////////////////////////////////////////////////////////////
271 /// <summary>
272 /// Returns the value of a key from a key-value data string.
273 /// </summary>
274 /// <param name="key">the key of the value</param>
275 /// <param name="data">the key-value data segment</param>
276 /// <returns>true if the key was found in data</returns>
277 private static string wasKeyValueGet(string key, string data)
278 {
279 return data.Split('&')
280 .AsParallel()
281 .Select(o => o.Split('=').ToList())
282 .Where(o => o.Count.Equals(2))
283 .Select(o => new
284 {
285 k = o.First(),
286 v = o.Last()
287 })
288 .Where(o => o.k.Equals(key))
289 .Select(o => o.v)
290 .FirstOrDefault();
291 }
292  
3 eva 293 #endregion
294  
2 zed 295 ///////////////////////////////////////////////////////////////////////////
296 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
297 ///////////////////////////////////////////////////////////////////////////
298 /// <summary>Escapes a dictionary's keys and values for sending as POST data.</summary>
299 /// <param name="data">A dictionary containing keys and values to be escaped</param>
300 private static Dictionary<string, string> wasKeyValueEscape(Dictionary<string, string> data)
301 {
302 return data.AsParallel().ToDictionary(o => wasOutput(o.Key), p => wasOutput(p.Value));
303 }
304  
305 ///////////////////////////////////////////////////////////////////////////
306 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
307 ///////////////////////////////////////////////////////////////////////////
308 /// <summary>
309 /// Converts a list of string to a comma-separated values string.
310 /// </summary>
311 /// <param name="l">a list of strings</param>
312 /// <returns>a commma-separated list of values</returns>
313 /// <remarks>compliant with RFC 4180</remarks>
314 public static string wasEnumerableToCSV(IEnumerable<string> l)
315 {
316 string[] csv = l.Select(o => o.Clone() as string).ToArray();
317 Parallel.ForEach(csv.Select((v, i) => new {i, v}), o =>
318 {
319 string cell = o.v.Replace("\"", "\"\"");
320 switch (new[] {'"', ' ', ',', '\r', '\n'}.Any(p => cell.Contains(p)))
321 {
322 case true:
323 csv[o.i] = "\"" + cell + "\"";
324 break;
325 default:
326 csv[o.i] = cell;
327 break;
328 }
329 });
8 eva 330 return string.Join(",", csv);
2 zed 331 }
332  
333 ///////////////////////////////////////////////////////////////////////////
334 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
335 ///////////////////////////////////////////////////////////////////////////
336 /// <summary>
337 /// Converts a comma-separated list of values to a list of strings.
338 /// </summary>
339 /// <param name="csv">a comma-separated list of values</param>
340 /// <returns>a list of strings</returns>
341 /// <remarks>compliant with RFC 4180</remarks>
342 public static IEnumerable<string> wasCSVToEnumerable(string csv)
343 {
344 Stack<char> s = new Stack<char>();
345 StringBuilder m = new StringBuilder();
346 for (int i = 0; i < csv.Length; ++i)
347 {
348 switch (csv[i])
349 {
350 case ',':
351 if (!s.Any() || !s.Peek().Equals('"'))
352 {
353 yield return m.ToString();
354 m = new StringBuilder();
355 continue;
356 }
357 m.Append(csv[i]);
358 continue;
359 case '"':
360 if (i + 1 < csv.Length && csv[i].Equals(csv[i + 1]))
361 {
362 m.Append(csv[i]);
363 ++i;
364 continue;
365 }
366 if (!s.Any() || !s.Peek().Equals(csv[i]))
367 {
368 s.Push(csv[i]);
369 continue;
370 }
371 s.Pop();
372 continue;
373 }
374 m.Append(csv[i]);
375 }
376  
377 yield return m.ToString();
378 }
379  
380 ///////////////////////////////////////////////////////////////////////////
381 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
382 ///////////////////////////////////////////////////////////////////////////
383 /// <summary>
384 /// Serialises a dictionary to key-value data.
385 /// </summary>
386 /// <param name="data">a dictionary</param>
387 /// <returns>a key-value data encoded string</returns>
388 private static string wasKeyValueEncode(Dictionary<string, string> data)
389 {
8 eva 390 return string.Join("&", data.AsParallel().Select(o => string.Join("=", o.Key, o.Value)));
2 zed 391 }
392  
393 ///////////////////////////////////////////////////////////////////////////
394 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
395 ///////////////////////////////////////////////////////////////////////////
396 /// <summary>
397 /// Sends a post request to an URL with set key-value pairs.
398 /// </summary>
399 /// <param name="URL">the url to send the message to</param>
400 /// <param name="message">key-value pairs to send</param>
401 /// <param name="millisecondsTimeout">the time in milliseconds for the request to timeout</param>
402 private static string wasPOST(string URL, Dictionary<string, string> message, uint millisecondsTimeout)
403 {
404 try
405 {
406 HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL);
407 request.UserAgent = VASSAL_CONSTANTS.USER_AGENT;
408 request.Proxy = WebRequest.DefaultWebProxy;
8 eva 409 request.Pipelined = true;
410 request.KeepAlive = true;
2 zed 411 request.Timeout = (int) millisecondsTimeout;
8 eva 412 request.ReadWriteTimeout = (int) millisecondsTimeout;
2 zed 413 request.AllowAutoRedirect = true;
414 request.AllowWriteStreamBuffering = true;
415 request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
416 request.Method = WebRequestMethods.Http.Post;
417 // set the content type based on chosen output filers
418 switch (vassalConfiguration.OutputFilters.Last())
419 {
420 case Filter.RFC1738:
421 request.ContentType = VASSAL_CONSTANTS.CONTENT_TYPE.WWW_FORM_URLENCODED;
422 break;
423 default:
424 request.ContentType = VASSAL_CONSTANTS.CONTENT_TYPE.TEXT_PLAIN;
425 break;
426 }
427 // send request
428 using (Stream requestStream = request.GetRequestStream())
429 {
430 using (StreamWriter dataStream = new StreamWriter(requestStream))
431 {
432 dataStream.Write(wasKeyValueEncode(message));
433 }
434 }
435 // read response
436 using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
437 {
438 using (Stream responseStream = response.GetResponseStream())
439 {
440 if (responseStream != null)
441 {
442 using (
443 StreamReader streamReader = new StreamReader(responseStream))
444 {
445 return streamReader.ReadToEnd();
446 }
447 }
448 }
449 }
450 }
451 catch (Exception)
452 {
453 }
454  
455 return null;
456 }
457  
8 eva 458 private void RegionSelected(object sender, EventArgs e)
2 zed 459 {
8 eva 460 new Thread(() =>
461 {
462 try
463 {
464 // Stop timers.
465 vassalTimer.Stop();
466 overviewTabTimer.Stop();
467 regionsStateTabTimer.Stop();
468 residentListTabTimer.Stop();
469 estateTopTabTimer.Stop();
470 estateTexturesTabTimer.Stop();
2 zed 471  
8 eva 472 Monitor.Enter(ClientInstanceTeleportLock);
2 zed 473  
8 eva 474 string selectedRegionName = string.Empty;
475 Vector3 selectedRegionPosition = Vector3.Zero;
476 bool startTeleport = false;
477 vassalForm.Invoke((MethodInvoker) (() =>
478 {
479 ListViewItem listViewItem = LoadedRegionsBox.SelectedItem as ListViewItem;
480 switch (listViewItem != null && LoadedRegionsBox.SelectedIndex != -1)
481 {
482 case true:
483 selectedRegionName = listViewItem.Text;
484 selectedRegionPosition = (Vector3) listViewItem.Tag;
485 startTeleport = true;
486 break;
487 default:
488 startTeleport = false;
489 break;
490 }
491 }));
2 zed 492  
8 eva 493 if (!startTeleport) throw new Exception();
2 zed 494  
8 eva 495 // Announce teleport.
496 vassalForm.Invoke((MethodInvoker) (() =>
2 zed 497 {
8 eva 498 vassalForm.RegionTeleportGroup.Enabled = false;
499 vassalForm.StatusProgress.Value = 0;
500 vassalForm.StatusText.Text = @"Teleporting to " + selectedRegionName;
2 zed 501 }));
502  
12 zed 503 // Pause for teleport (10 teleports / 15s allowed).
504 Thread.Sleep(700);
505  
3 eva 506 int elapsedSeconds = 0;
8 eva 507 Timer teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
3 eva 508 teleportTimer.Elapsed += (o, p) =>
2 zed 509 {
510 vassalForm.Invoke((MethodInvoker) (() =>
511 {
3 eva 512 vassalForm.StatusProgress.Value =
513 Math.Min(
514 (int)
515 (100d*
516 (TimeSpan.FromSeconds(++elapsedSeconds).TotalMilliseconds/
517 vassalConfiguration.TeleportTimeout)), 100);
2 zed 518 }));
3 eva 519 };
520 teleportTimer.Start();
521 string result = null;
522 ManualResetEvent receivedPOST = new ManualResetEvent(false);
523 new Thread(() =>
524 {
525 result = wasInput(wasPOST(vassalConfiguration.HTTPServerURL,
526 wasKeyValueEscape(new Dictionary<string, string>
527 {
528 {"command", "teleport"},
529 {"group", vassalConfiguration.Group},
530 {"password", vassalConfiguration.Password},
531 {"region", selectedRegionName},
532 {"position", selectedRegionPosition.ToString()},
533 {"fly", "True"}
534 }), vassalConfiguration.TeleportTimeout));
535 receivedPOST.Set();
536 }) {IsBackground = true}.Start();
537 receivedPOST.WaitOne((int) vassalConfiguration.TeleportTimeout, false);
538 teleportTimer.Stop();
539 switch (!string.IsNullOrEmpty(result) && wasKeyValueGet("success", result) == "True")
540 {
541 case true:
2 zed 542 vassalForm.Invoke((MethodInvoker) (() =>
543 {
3 eva 544 vassalForm.StatusText.Text = @"Now at " + selectedRegionName;
545 vassalForm.CurrentRegionName.Text = selectedRegionName;
2 zed 546 }));
3 eva 547 break;
548 default:
549 switch (!string.IsNullOrEmpty(result))
2 zed 550 {
551 case true:
3 eva 552 vassalForm.Invoke((MethodInvoker) (() =>
2 zed 553 {
3 eva 554 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName +
555 @": " +
556 wasKeyValueGet("error", result);
2 zed 557 }));
558 break;
3 eva 559 default:
8 eva 560 vassalForm.Invoke(
561 (MethodInvoker)
562 (() =>
563 {
564 vassalForm.StatusText.Text = @"Failed teleporting to " +
565 selectedRegionName;
566 }));
3 eva 567 break;
2 zed 568 }
3 eva 569 break;
2 zed 570 }
571 }
3 eva 572 catch (Exception ex)
573 {
8 eva 574 vassalForm.Invoke(
575 (MethodInvoker)
576 (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message; }));
3 eva 577 }
578 finally
579 {
7 zed 580 vassalForm.BeginInvoke((MethodInvoker) (() =>
3 eva 581 {
582 vassalForm.StatusProgress.Value = 100;
583 vassalForm.RegionTeleportGroup.Enabled = true;
584 // Set the map image to the loading spinner.
8 eva 585 Assembly thisAssembly = Assembly.GetExecutingAssembly();
586 Stream file =
3 eva 587 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
588 switch (file != null)
589 {
590 case true:
591 vassalForm.Invoke((MethodInvoker) (() =>
592 {
593 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
594 RegionAvatarsMap.Image = Image.FromStream(file);
595 RegionAvatarsMap.Refresh();
596 }));
597 break;
598 }
7 zed 599 // Clear the resident list table.
600 ResidentListGridView.Rows.Clear();
3 eva 601 // Clear the top scripts table.
602 TopScriptsGridView.Rows.Clear();
603 // Clear the top colliders table.
604 TopCollidersGridView.Rows.Clear();
8 eva 605 // Clear the estate list table.
606 EstateListGridView.Rows.Clear();
607 // Clear the estate list selection box.
608 EstateListSelectBox.SelectedIndex = -1;
3 eva 609 // Invalidate data for overview tab.
610 vassalForm.CurrentRegionAt.Visible = false;
611 vassalForm.CurrentRegionName.Visible = false;
612 Agents.Text = string.Empty;
613 Agents.Enabled = false;
614 LastLag.Text = string.Empty;
615 LastLag.Enabled = false;
616 Dilation.Text = string.Empty;
617 Dilation.Enabled = false;
618 FPS.Text = string.Empty;
619 FPS.Enabled = false;
620 PhysicsFPS.Text = string.Empty;
621 PhysicsFPS.Enabled = false;
622 ActiveScripts.Text = string.Empty;
623 ActiveScripts.Enabled = false;
624 ScriptTime.Text = string.Empty;
625 ScriptTime.Enabled = false;
12 zed 626 FrameTime.Text = string.Empty;
627 FrameTime.Enabled = false;
628 ScriptedObjects.Text = string.Empty;
629 ScriptedObjects.Enabled = false;
630 PhysicsTime.Text = string.Empty;
631 PhysicsTime.Enabled = false;
632 NetTime.Text = string.Empty;
633 NetTime.Enabled = false;
3 eva 634 Objects.Text = string.Empty;
635 Objects.Enabled = false;
636 }));
8 eva 637  
638 Monitor.Exit(ClientInstanceTeleportLock);
639  
640 // start timers
641 vassalTimer.Start();
642 overviewTabTimer.Start();
643 regionsStateTabTimer.Start();
644 residentListTabTimer.Start();
645 estateTopTabTimer.Start();
646 estateTexturesTabTimer.Start();
3 eva 647 }
7 zed 648 })
649 {IsBackground = true}.Start();
2 zed 650 }
651  
652 private void SettingsRequested(object sender, EventArgs e)
653 {
8 eva 654 vassalForm.BeginInvoke((MethodInvoker) (() => { VassalStatusGroup.Enabled = false; }));
2 zed 655 SettingsForm settingsForm = new SettingsForm {TopMost = true};
656 settingsForm.Show();
657 }
658  
659 private void VassalShown(object sender, EventArgs e)
660 {
3 eva 661 // Set the version
662 vassalForm.Version.Text = @"v" + VASSAL_CONSTANTS.VASSAL_VERSION;
663  
4 vero 664 // Disable estate manager tabs since we will enable these dynamically.
8 eva 665 EstateTopTab.Enabled = false;
666 EstateListsTab.Enabled = false;
7 zed 667 ResidentListBanGroup.Enabled = false;
12 zed 668 ResidentListTeleportHomeGroup.Enabled = false;
8 eva 669 EstateTerrainDownloadUploadGroup.Enabled = false;
12 zed 670 EstateVariablesGroup.Enabled = false;
8 eva 671 // Estate textures
672 RegionTexturesLowUUIDApplyBox.Enabled = false;
673 RegionTexturesLowUUIDApplyButton.Enabled = false;
674 RegionTexturesMiddleLowUUIDApplyBox.Enabled = false;
675 RegionTexturesMiddleLowUUIDApplyButton.Enabled = false;
676 RegionTexturesMiddleHighUUIDApplyBox.Enabled = false;
677 RegionTexturesMiddleHighUUIDApplyButton.Enabled = false;
678 RegionTexturesHighUUIDApplyBox.Enabled = false;
679 RegionTexturesHighUUIDApplyButton.Enabled = false;
4 vero 680  
2 zed 681 // Get the configuration file settings if it exists.
682 if (File.Exists(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE))
683 {
4 vero 684 // Load the configuration.
2 zed 685 VassalConfiguration.Load(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE, ref vassalConfiguration);
5 eva 686 // Apply settings
687 RegionRestartDelayBox.Text = vassalConfiguration.RegionRestartDelay.ToString(Utils.EnUsCulture);
2 zed 688 }
689  
690 // Get all the regions if they exist.
691 if (File.Exists(VASSAL_CONSTANTS.VASSAL_REGIONS))
692 {
693 Vector3 localPosition;
3 eva 694 List<KeyValuePair<string, Vector3>> ConfiguredRegions = new List<KeyValuePair<string, Vector3>>(
2 zed 695 File.ReadAllLines(VASSAL_CONSTANTS.VASSAL_REGIONS)
696 .Select(o => new List<string>(wasCSVToEnumerable(o)))
697 .Where(o => o.Count == 2)
698 .ToDictionary(o => o.First(),
699 p =>
700 Vector3.TryParse(p.Last(), out localPosition)
701 ? localPosition
3 eva 702 : Vector3.Zero).OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value));
703 // Populate the loaded regions.
8 eva 704 LoadedRegionsBox.Items.Clear();
705 LoadedRegionsBox.Items.AddRange(
3 eva 706 ConfiguredRegions.Select(o => (object) new ListViewItem {Text = o.Key, Tag = o.Value})
2 zed 707 .ToArray());
3 eva 708 // Populate the batch restart grid view.
709 BatchRestartGridView.Rows.Clear();
710 foreach (KeyValuePair<string, Vector3> data in ConfiguredRegions)
711 {
712 BatchRestartGridView.Rows.Add(data.Key, data.Value.ToString());
713 }
7 zed 714 // Populate the regions state grid view.
715 foreach (KeyValuePair<string, Vector3> data in ConfiguredRegions)
716 {
717 RegionsStateGridView.Rows.Add(data.Key, "Check pening...");
718 }
2 zed 719 }
720  
8 eva 721 // Start the vassal timer.
722 vassalTimer.Elapsed += (o, p) =>
2 zed 723 {
724 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
725 return;
8 eva 726 try
727 {
728 // Check Corrade connection status.
729 TcpClient tcpClient = new TcpClient();
730 Uri uri = new Uri(vassalConfiguration.HTTPServerURL);
731 tcpClient.Connect(uri.Host, uri.Port);
732 // port open
733 vassalForm.BeginInvoke((MethodInvoker) (() =>
734 {
735 vassalForm.CurrentRegionAt.Visible = true;
736 vassalForm.CurrentRegionName.Visible = true;
737 Assembly thisAssembly = Assembly.GetExecutingAssembly();
738 Stream file =
739 thisAssembly.GetManifestResourceStream("Vassal.img.online.png");
740 switch (file != null)
741 {
742 case true:
743 vassalForm.BeginInvoke((MethodInvoker) (() =>
744 {
745 ConnectionStatusPictureBox.Image = Image.FromStream(file);
746 ConnectionStatusPictureBox.Refresh();
747 }));
748 break;
749 }
750 Tabs.Enabled = true;
12 zed 751 RegionTeleportGroup.Enabled = true;
8 eva 752 }));
753 }
754 catch (Exception)
755 {
756 // port closed
757 vassalForm.BeginInvoke((MethodInvoker) (() =>
758 {
759 vassalForm.CurrentRegionAt.Visible = false;
760 vassalForm.CurrentRegionName.Visible = false;
761 Assembly thisAssembly = Assembly.GetExecutingAssembly();
762 Stream file =
763 thisAssembly.GetManifestResourceStream("Vassal.img.offline.png");
764 switch (file != null)
765 {
766 case true:
767 vassalForm.BeginInvoke((MethodInvoker) (() =>
768 {
769 ConnectionStatusPictureBox.Image = Image.FromStream(file);
770 ConnectionStatusPictureBox.Refresh();
771 }));
772 break;
773 }
774 Tabs.Enabled = false;
12 zed 775 RegionTeleportGroup.Enabled = false;
8 eva 776 }));
777 }
2 zed 778  
779 try
780 {
8 eva 781 // Get the simulator name and if we are an estate manager.
2 zed 782 string result = wasPOST(vassalConfiguration.HTTPServerURL,
783 wasKeyValueEscape(new Dictionary<string, string>
784 {
785 {"command", "getregiondata"},
786 {"group", vassalConfiguration.Group},
787 {"password", vassalConfiguration.Password},
788 {
789 "data", wasEnumerableToCSV(new[]
790 {
4 vero 791 "Name",
792 "IsEstateManager"
2 zed 793 })
794 }
795 }), vassalConfiguration.DataTimeout);
796  
797 bool success;
798 if (string.IsNullOrEmpty(result) ||
799 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
800 throw new Exception();
801  
802 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
803 if (data.Count.Equals(0))
804 throw new Exception();
805  
7 zed 806 vassalForm.BeginInvoke((MethodInvoker) (() =>
2 zed 807 {
4 vero 808 // Drop access to features if we are not estate managers.
809 bool isEstateManager;
810 switch (
811 bool.TryParse(data[data.IndexOf("IsEstateManager") + 1], out isEstateManager) &&
812 isEstateManager)
813 {
814 case true: // we are an estate manager
8 eva 815 EstateTopTab.Enabled = true;
816 EstateListsTab.Enabled = true;
7 zed 817 ResidentListBanGroup.Enabled = true;
12 zed 818 ResidentListTeleportHomeGroup.Enabled = true;
8 eva 819 EstateTerrainDownloadUploadGroup.Enabled = true;
12 zed 820 EstateVariablesGroup.Enabled = true;
8 eva 821 RegionToolsRegionDebugGroup.Enabled = true;
822 RegionToolsRegionInfoGroup.Enabled = true;
823 // Estate textures
824 RegionTexturesLowUUIDApplyBox.Enabled = true;
825 RegionTexturesLowUUIDApplyButton.Enabled = true;
826 RegionTexturesMiddleLowUUIDApplyBox.Enabled = true;
827 RegionTexturesMiddleLowUUIDApplyButton.Enabled = true;
828 RegionTexturesMiddleHighUUIDApplyBox.Enabled = true;
829 RegionTexturesMiddleHighUUIDApplyButton.Enabled = true;
830 RegionTexturesHighUUIDApplyBox.Enabled = true;
831 RegionTexturesHighUUIDApplyButton.Enabled = true;
4 vero 832 break;
833 default:
8 eva 834 EstateTopTab.Enabled = false;
835 EstateListsTab.Enabled = false;
7 zed 836 ResidentListBanGroup.Enabled = false;
12 zed 837 ResidentListTeleportHomeGroup.Enabled = false;
8 eva 838 EstateTerrainDownloadUploadGroup.Enabled = false;
12 zed 839 EstateVariablesGroup.Enabled = false;
8 eva 840 RegionToolsRegionDebugGroup.Enabled = false;
841 RegionToolsRegionInfoGroup.Enabled = false;
842 // Estate textures
843 RegionTexturesLowUUIDApplyBox.Enabled = false;
844 RegionTexturesLowUUIDApplyButton.Enabled = false;
845 RegionTexturesMiddleLowUUIDApplyBox.Enabled = false;
846 RegionTexturesMiddleLowUUIDApplyButton.Enabled = false;
847 RegionTexturesMiddleHighUUIDApplyBox.Enabled = false;
848 RegionTexturesMiddleHighUUIDApplyButton.Enabled = false;
849 RegionTexturesHighUUIDApplyBox.Enabled = false;
850 RegionTexturesHighUUIDApplyButton.Enabled = false;
4 vero 851 break;
852 }
853  
3 eva 854 // Show the region name.
855 vassalForm.CurrentRegionName.Text = data[data.IndexOf("Name") + 1];
856 vassalForm.CurrentRegionAt.Visible = true;
857 vassalForm.CurrentRegionName.Visible = true;
8 eva 858 }));
859 }
860 catch (Exception)
861 {
862 }
3 eva 863  
8 eva 864 Monitor.Exit(ClientInstanceTeleportLock);
865 };
866 vassalTimer.Start();
867  
868 // Start the overview timer.
869 overviewTabTimer.Elapsed += (o, p) =>
870 {
871 // Do not do anything in case the tab is not selected.
872 bool run = false;
873 vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(OverviewTab); }));
874  
875 if (!run)
876 {
877 overviewTabTimer.Stop();
878 return;
879 }
880  
881 overviewTabTimer.Stop();
882  
883 try
884 {
12 zed 885 // Start measuring the lag to Corrade.
886 Stopwatch stopWatch = new Stopwatch();
887 stopWatch.Start();
8 eva 888 // Get the statistics.
889 string result = wasPOST(vassalConfiguration.HTTPServerURL,
890 wasKeyValueEscape(new Dictionary<string, string>
891 {
892 {"command", "getregiondata"},
893 {"group", vassalConfiguration.Group},
894 {"password", vassalConfiguration.Password},
895 {
896 "data", wasEnumerableToCSV(new[]
897 {
898 "Agents",
899 "LastLag",
900 "Dilation",
901 "FPS",
902 "PhysicsFPS",
903 "ActiveScripts",
904 "ScriptTime",
905 "Objects",
12 zed 906 "FrameTime",
907 "ScriptedObjects",
908 "PhysicsTime",
909 "NetTime",
8 eva 910 "AvatarPositions"
911 })
912 }
913 }), vassalConfiguration.DataTimeout);
12 zed 914 stopWatch.Stop();
8 eva 915  
916 bool success;
917 if (string.IsNullOrEmpty(result) ||
918 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
919 throw new Exception();
920  
921 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
922 if (data.Count.Equals(0))
923 throw new Exception();
924  
925 vassalForm.BeginInvoke((MethodInvoker) (() =>
926 {
3 eva 927 // Populate the overview tab.
2 zed 928 Agents.Text = data[data.IndexOf("Agents") + 1];
3 eva 929 Agents.Enabled = true;
2 zed 930 LastLag.Text = data[data.IndexOf("LastLag") + 1];
3 eva 931 LastLag.Enabled = true;
2 zed 932 Dilation.Text = data[data.IndexOf("Dilation") + 1];
3 eva 933 Dilation.Enabled = true;
2 zed 934 FPS.Text = data[data.IndexOf("FPS") + 1];
3 eva 935 FPS.Enabled = true;
2 zed 936 PhysicsFPS.Text = data[data.IndexOf("PhysicsFPS") + 1];
3 eva 937 PhysicsFPS.Enabled = true;
2 zed 938 ActiveScripts.Text = data[data.IndexOf("ActiveScripts") + 1];
3 eva 939 ActiveScripts.Enabled = true;
2 zed 940 ScriptTime.Text = data[data.IndexOf("ScriptTime") + 1];
3 eva 941 ScriptTime.Enabled = true;
12 zed 942 FrameTime.Text = data[data.IndexOf("FrameTime") + 1];
943 FrameTime.Enabled = true;
944 ScriptedObjects.Text = data[data.IndexOf("ScriptedObjects") + 1];
945 ScriptedObjects.Enabled = true;
946 PhysicsTime.Text = data[data.IndexOf("PhysicsTime") + 1];
947 PhysicsTime.Enabled = true;
948 NetTime.Text = data[data.IndexOf("NetTime") + 1];
949 NetTime.Enabled = true;
2 zed 950 Objects.Text = data[data.IndexOf("Objects") + 1];
3 eva 951 Objects.Enabled = true;
12 zed 952  
953 // Show the overview lag time.
954 CorradePollTimeDial.Value =
955 (float) Math.Min(TimeSpan.FromMilliseconds(stopWatch.ElapsedMilliseconds).TotalSeconds,
956 CorradePollTimeDial.MaxValue);
2 zed 957 }));
3 eva 958  
8 eva 959 // Get avatar positions.
960 // Pattern: [...], X, 10, Y, 63, Z, 200, [...], X, 52, Y, 73, Z, 55, [...[...]]
961 float X = 0, Y = 0, Z = 0;
962 List<Vector3> positions = data.Select((x, i) => new {Item = x, Index = i})
963 .Where(x => x.Item.Equals("X") || x.Item.Equals("Y") || x.Item.Equals("Z"))
964 .Select(z => data[z.Index + 1]).Select((x, i) => new {Value = x, Index = i})
965 .GroupBy(x => x.Index/3)
966 .Select(x => x.Select(v => v.Value).ToList())
967 .Where(
968 x =>
969 float.TryParse(x[0], out X) && float.TryParse(x[1], out Y) &&
970 float.TryParse(x[2], out Z))
971 .Select(x => new Vector3(X, Y, Z))
972 .ToList();
973  
2 zed 974 // Get the map image.
975 result = wasPOST(vassalConfiguration.HTTPServerURL,
976 wasKeyValueEscape(new Dictionary<string, string>
977 {
978 {"command", "getgridregiondata"},
979 {"group", vassalConfiguration.Group},
980 {"password", vassalConfiguration.Password},
3 eva 981 {"data", "MapImageID"}
2 zed 982 }), vassalConfiguration.DataTimeout);
3 eva 983  
2 zed 984 if (string.IsNullOrEmpty(result) ||
985 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
986 throw new Exception();
987  
988 data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
989 if (!data.Count.Equals(2))
990 throw new Exception();
991 result = wasPOST(vassalConfiguration.HTTPServerURL,
992 wasKeyValueEscape(new Dictionary<string, string>
993 {
994 {"command", "download"},
995 {"group", vassalConfiguration.Group},
996 {"password", vassalConfiguration.Password},
3 eva 997 {"item", data.Last()},
998 {"type", "Texture"},
8 eva 999 {"format", "Jpeg"}
2 zed 1000 }), vassalConfiguration.DataTimeout);
1001 if (string.IsNullOrEmpty(result) ||
1002 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1003 throw new Exception();
1004 byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
1005 Image mapImage;
1006 using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
1007 {
1008 mapImage = Image.FromStream(memoryStream);
1009 }
1010  
1011 // Draw the avatars onto the map.
1012 Graphics mapGraphics = Graphics.FromImage(mapImage);
8 eva 1013 foreach (Vector3 position in positions)
2 zed 1014 {
8 eva 1015 mapGraphics.FillEllipse(Brushes.Chartreuse,
1016 new Rectangle((int) position.X, (int) position.Y, 4, 4));
2 zed 1017 }
1018 mapGraphics.DrawImage(mapImage, new Point(0, 0));
1019  
7 zed 1020 vassalForm.BeginInvoke((MethodInvoker) (() =>
2 zed 1021 {
1022 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.StretchImage;
1023 RegionAvatarsMap.Image = mapImage;
1024 RegionAvatarsMap.Refresh();
1025 }));
1026 }
1027 catch (Exception)
1028 {
1029 }
3 eva 1030  
8 eva 1031 overviewTabTimer.Start();
2 zed 1032 };
1033 overviewTabTimer.Start();
1034  
7 zed 1035 regionsStateTabTimer.Elapsed += (o, p) =>
2 zed 1036 {
7 zed 1037 // Do not do anything in case the tab is not selected.
1038 bool run = false;
8 eva 1039 vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(RegionsStateTab); }));
1040  
1041 if (!run)
7 zed 1042 {
8 eva 1043 regionsStateTabTimer.Stop();
2 zed 1044 return;
8 eva 1045 }
2 zed 1046  
8 eva 1047 regionsStateTabTimer.Stop();
1048  
2 zed 1049 try
1050 {
7 zed 1051 string regionName = string.Empty;
2 zed 1052 vassalForm.Invoke((MethodInvoker) (() =>
1053 {
7 zed 1054 regionName =
1055 RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateRegionName"].Value
1056 .ToString();
8 eva 1057 RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
1058 Color.Gold;
2 zed 1059 }));
1060  
7 zed 1061 if (string.IsNullOrEmpty(regionName))
1062 throw new Exception();
1063  
1064 // Get the region status.
1065 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1066 wasKeyValueEscape(new Dictionary<string, string>
1067 {
1068 {"command", "getgridregiondata"},
1069 {"group", vassalConfiguration.Group},
1070 {"password", vassalConfiguration.Password},
1071 {"region", regionName},
1072 {"data", "Access"}
1073 }), vassalConfiguration.DataTimeout);
1074  
1075 bool success;
1076 if (string.IsNullOrEmpty(result) ||
1077 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1078 throw new Exception();
1079  
1080 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1081 if (!data.Count.Equals(2))
1082 throw new Exception();
1083  
1084 string status = data.Last();
1085 vassalForm.Invoke((MethodInvoker) (() =>
1086 {
1087 switch (status)
1088 {
1089 case "Unknown":
1090 case "Down":
1091 case "NonExistent":
1092 RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
1093 Color.LightPink;
1094 RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastState"].Value =
1095 status;
1096 break;
1097 default:
1098 RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
1099 Color.LightGreen;
1100 RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastState"].Value =
1101 "Up";
1102 break;
1103 }
1104 RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastCheck"].Value = DateTime
1105 .Now.ToUniversalTime()
8 eva 1106 .ToString(LINDEN_CONSTANTS.LSL.DATE_TIME_STAMP);
7 zed 1107 }));
1108 }
1109 catch (Exception)
1110 {
1111 }
1112 finally
1113 {
1114 ++regionsStateCheckIndex;
1115 vassalForm.Invoke((MethodInvoker) (() =>
1116 {
1117 if (regionsStateCheckIndex >= RegionsStateGridView.Rows.Count)
1118 {
1119 regionsStateCheckIndex = 0;
1120 }
1121 }));
1122 }
8 eva 1123  
1124 regionsStateTabTimer.Start();
7 zed 1125 };
1126 regionsStateTabTimer.Start();
1127  
1128 // Start the top scores timer.
8 eva 1129 estateTopTabTimer.Elapsed += (o, p) =>
7 zed 1130 {
1131 // Do not do anything in case the tab is not selected.
1132 bool run = false;
8 eva 1133 vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(EstateTopTab); }));
1134  
1135 if (!run)
7 zed 1136 {
8 eva 1137 estateTopTabTimer.Stop();
7 zed 1138 return;
8 eva 1139 }
7 zed 1140  
8 eva 1141 estateTopTabTimer.Stop();
1142  
7 zed 1143 try
1144 {
8 eva 1145 // Get the top scripts.
2 zed 1146 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1147 wasKeyValueEscape(new Dictionary<string, string>
1148 {
1149 {"command", "getregiontop"},
1150 {"group", vassalConfiguration.Group},
1151 {"password", vassalConfiguration.Password},
1152 {"type", "scripts"}
1153 }), vassalConfiguration.DataTimeout);
1154  
1155 bool success;
1156 if (string.IsNullOrEmpty(result) ||
1157 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1158 throw new Exception();
1159  
1160 HashSet<List<string>> data =
1161 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1162 .Select((x, i) => new {Index = i, Value = x})
1163 .GroupBy(x => x.Index/5)
1164 .Select(x => x.Select(v => v.Value).ToList()));
1165 if (data.Count.Equals(0))
1166 throw new Exception();
1167  
1168 vassalForm.Invoke((MethodInvoker) (() =>
1169 {
3 eva 1170 // Remove rows that are not in the data update.
1171 foreach (
1172 int index in
1173 TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>()
1174 .Where(
1175 topScriptsRow =>
1176 !data.Any(q => q[2].Equals(topScriptsRow.Cells["TopScriptsUUID"].Value)))
1177 .Select(q => q.Index))
2 zed 1178 {
3 eva 1179 TopScriptsGridView.Rows.RemoveAt(index);
2 zed 1180 }
3 eva 1181 // Now update or add new data.
1182 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5)))
1183 {
1184 DataGridViewRow row =
1185 TopScriptsGridView.Rows.AsParallel()
1186 .Cast<DataGridViewRow>()
1187 .FirstOrDefault(q => q.Cells["TopScriptsUUID"].Value.Equals(dataComponents[2]));
1188 switch (row != null)
1189 {
1190 case true: // the row exists, so update it.
1191 row.Cells["TopScriptsScore"].Value = dataComponents[0];
1192 row.Cells["TopScriptsTaskName"].Value = dataComponents[1];
1193 row.Cells["TopScriptsUUID"].Value = dataComponents[2];
1194 row.Cells["TopScriptsOwner"].Value = dataComponents[3];
1195 row.Cells["TopScriptsPosition"].Value = dataComponents[4];
1196 break;
1197 case false: // the row dosn't exist, so add it.
1198 TopScriptsGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2],
1199 dataComponents[3], dataComponents[4]);
1200 break;
1201 }
1202 }
2 zed 1203 }));
1204  
8 eva 1205 // Get the top colliders.
1206 result = wasPOST(vassalConfiguration.HTTPServerURL,
2 zed 1207 wasKeyValueEscape(new Dictionary<string, string>
1208 {
1209 {"command", "getregiontop"},
1210 {"group", vassalConfiguration.Group},
1211 {"password", vassalConfiguration.Password},
1212 {"type", "colliders"}
1213 }), vassalConfiguration.DataTimeout);
1214  
1215 if (string.IsNullOrEmpty(result) ||
1216 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1217 throw new Exception();
1218  
8 eva 1219 data = new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1220 .Select((x, i) => new {Index = i, Value = x})
1221 .GroupBy(x => x.Index/5)
1222 .Select(x => x.Select(v => v.Value).ToList()));
2 zed 1223 if (data.Count.Equals(0))
1224 throw new Exception();
1225  
3 eva 1226 vassalForm.Invoke((MethodInvoker) (() =>
2 zed 1227 {
3 eva 1228 // Remove rows that are not in the data update.
1229 foreach (
1230 int index in
1231 TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>()
1232 .Where(
1233 topCollidersRow =>
1234 !data.Any(q => q[2].Equals(topCollidersRow.Cells["TopCollidersUUID"].Value)))
1235 .Select(q => q.Index))
2 zed 1236 {
3 eva 1237 TopCollidersGridView.Rows.RemoveAt(index);
2 zed 1238 }
3 eva 1239 // Now update or add new data.
1240 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5)))
1241 {
1242 DataGridViewRow row =
1243 TopCollidersGridView.Rows.AsParallel()
1244 .Cast<DataGridViewRow>()
1245 .FirstOrDefault(q => q.Cells["TopCollidersUUID"].Value.Equals(dataComponents[2]));
1246 switch (row != null)
1247 {
1248 case true: // the row exists, so update it.
1249 row.Cells["TopCollidersScore"].Value = dataComponents[0];
1250 row.Cells["TopSCollidersTaskName"].Value = dataComponents[1];
1251 row.Cells["TopCollidersUUID"].Value = dataComponents[2];
1252 row.Cells["TopCollidersOwner"].Value = dataComponents[3];
1253 row.Cells["TopCollidersPosition"].Value = dataComponents[4];
1254 break;
1255 case false: // the row dosn't exist, so add it.
7 zed 1256 TopCollidersGridView.Rows.Add(dataComponents[0], dataComponents[1],
1257 dataComponents[2],
3 eva 1258 dataComponents[3], dataComponents[4]);
1259 break;
1260 }
1261 }
2 zed 1262 }));
1263 }
1264 catch (Exception)
1265 {
8 eva 1266 }
2 zed 1267  
8 eva 1268 estateTopTabTimer.Start();
2 zed 1269 };
8 eva 1270 estateTopTabTimer.Start();
7 zed 1271  
1272 // Start the resident list timer.
8 eva 1273 residentListTabTimer.Elapsed += (o, p) =>
7 zed 1274 {
1275 // Do not do anything in case the tab is not selected.
1276 bool run = false;
8 eva 1277 vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(ResidentListTab); }));
1278  
1279 if (!run)
7 zed 1280 {
8 eva 1281 residentListTabTimer.Stop();
7 zed 1282 return;
8 eva 1283 }
7 zed 1284  
8 eva 1285 residentListTabTimer.Stop();
1286  
7 zed 1287 try
1288 {
1289 // Get the avatar positions.
1290 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1291 wasKeyValueEscape(new Dictionary<string, string>
1292 {
1293 {"command", "getavatarpositions"},
1294 {"group", vassalConfiguration.Group},
1295 {"password", vassalConfiguration.Password},
1296 {"entity", "region"}
1297 }), vassalConfiguration.DataTimeout);
1298  
1299 bool success;
1300 if (string.IsNullOrEmpty(result) ||
1301 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1302 throw new Exception();
1303  
1304 HashSet<List<string>> data =
1305 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1306 .Select((x, i) => new {Index = i, Value = x})
1307 .GroupBy(x => x.Index/3)
1308 .Select(x => x.Select(v => v.Value).ToList()));
1309 if (data.Count.Equals(0))
1310 throw new Exception();
1311  
1312 vassalForm.Invoke((MethodInvoker) (() =>
1313 {
1314 // Remove rows that are not in the data update.
1315 foreach (
1316 int index in
1317 ResidentListGridView.Rows.AsParallel().Cast<DataGridViewRow>()
1318 .Where(
1319 residentListRow =>
1320 !data.Any(q => q[1].Equals(residentListRow.Cells["ResidentListUUID"].Value)))
1321 .Select(q => q.Index))
1322 {
1323 ResidentListGridView.Rows.RemoveAt(index);
1324 }
1325 // Now update or add new data.
1326 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(3)))
1327 {
1328 DataGridViewRow row =
1329 ResidentListGridView.Rows.AsParallel()
1330 .Cast<DataGridViewRow>()
1331 .FirstOrDefault(q => q.Cells["ResidentListUUID"].Value.Equals(dataComponents[1]));
1332 switch (row != null)
1333 {
1334 case true: // the row exists, so update it.
1335 row.Cells["ResidentListName"].Value = dataComponents[0];
1336 row.Cells["ResidentListUUID"].Value = dataComponents[1];
1337 row.Cells["ResidentListPosition"].Value = dataComponents[2];
1338 break;
1339 case false: // the row dosn't exist, so add it.
1340 ResidentListGridView.Rows.Add(dataComponents[0], dataComponents[1],
1341 dataComponents[2]);
1342 break;
1343 }
1344 }
1345 }));
1346 }
1347 catch (Exception)
1348 {
8 eva 1349 }
7 zed 1350  
8 eva 1351 residentListTabTimer.Start();
1352 };
1353 residentListTabTimer.Start();
1354  
1355 estateTexturesTabTimer.Elapsed += (o, p) =>
1356 {
1357 // Do not do anything in case the tab is not selected.
1358 bool run = false;
1359 vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(EstateTexturesTab); }));
1360  
1361 if (!run)
1362 {
1363 estateTexturesTabTimer.Stop();
1364 return;
7 zed 1365 }
8 eva 1366  
1367 estateTexturesTabTimer.Stop();
1368  
1369 try
7 zed 1370 {
8 eva 1371 // Get the region terrain texture UUIDs.
1372 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1373 wasKeyValueEscape(new Dictionary<string, string>
1374 {
1375 {"command", "getregionterraintextures"},
1376 {"group", vassalConfiguration.Group},
1377 {"password", vassalConfiguration.Password}
1378 }), vassalConfiguration.DataTimeout);
1379  
1380 bool success;
1381 if (string.IsNullOrEmpty(result) ||
1382 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1383 throw new Exception();
1384  
1385 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1386 if (!data.Count.Equals(4))
1387 throw new Exception();
1388  
1389 vassalForm.Invoke((MethodInvoker) (() =>
1390 {
1391 RegionTexturesLowUUIDBox.Text = data[0];
1392 if (string.IsNullOrEmpty(RegionTexturesLowUUIDApplyBox.Text))
1393 {
1394 RegionTexturesLowUUIDApplyBox.Text = data[0];
1395 }
1396 RegionTexturesMiddleLowUUIDBox.Text = data[1];
1397 if (string.IsNullOrEmpty(RegionTexturesMiddleLowUUIDApplyBox.Text))
1398 {
1399 RegionTexturesMiddleLowUUIDApplyBox.Text = data[1];
1400 }
1401 RegionTexturesMiddleHighUUIDBox.Text = data[2];
1402 if (string.IsNullOrEmpty(RegionTexturesMiddleHighUUIDApplyBox.Text))
1403 {
1404 RegionTexturesMiddleHighUUIDApplyBox.Text = data[2];
1405 }
1406 RegionTexturesHighUUIDBox.Text = data[3];
1407 if (string.IsNullOrEmpty(RegionTexturesHighUUIDApplyBox.Text))
1408 {
1409 RegionTexturesHighUUIDApplyBox.Text = data[1];
1410 }
1411 }));
1412  
1413 Parallel.ForEach(Enumerable.Range(0, 4), i =>
1414 {
1415 result = wasPOST(vassalConfiguration.HTTPServerURL,
1416 wasKeyValueEscape(new Dictionary<string, string>
1417 {
1418 {"command", "download"},
1419 {"group", vassalConfiguration.Group},
1420 {"password", vassalConfiguration.Password},
1421 {"item", data[i]},
1422 {"type", "Texture"},
1423 {"format", "Jpeg"}
1424 }), vassalConfiguration.DataTimeout);
1425  
1426 if (string.IsNullOrEmpty(result) ||
1427 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1428 return;
1429  
1430 byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
1431 using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
1432 {
1433 groundTextureImages[i] = Image.FromStream(memoryStream);
1434 }
1435  
1436 switch (i)
1437 {
1438 case 0:
1439 vassalForm.BeginInvoke(
1440 (MethodInvoker)
1441 (() => { RegionTexturesLowPictureBox.Image = groundTextureImages[0]; }));
1442  
1443 break;
1444 case 1:
1445 vassalForm.BeginInvoke(
1446 (MethodInvoker)
1447 (() => { RegionTexturesMiddleLowPictureBox.Image = groundTextureImages[1]; }));
1448  
1449 break;
1450 case 2:
1451 vassalForm.BeginInvoke(
1452 (MethodInvoker)
1453 (() => { RegionTexturesMiddleHighPictureBox.Image = groundTextureImages[2]; }));
1454 break;
1455 case 3:
1456 vassalForm.BeginInvoke(
1457 (MethodInvoker)
1458 (() => { RegionTexturesHighPictureBox.Image = groundTextureImages[3]; }));
1459 break;
1460 }
1461 });
7 zed 1462 }
8 eva 1463 catch (Exception)
1464 {
1465 }
1466  
1467 estateTexturesTabTimer.Start();
7 zed 1468 };
8 eva 1469 estateTexturesTabTimer.Start();
2 zed 1470 }
1471  
1472 private void RequestedEditRegions(object sender, EventArgs e)
1473 {
1474 // Clear any selection.
8 eva 1475 LoadedRegionsBox.SelectedIndex = -1;
3 eva 1476 RegionEditForm regionEditForm = new RegionEditForm {TopMost = true};
2 zed 1477 regionEditForm.Show();
1478 }
1479  
1480 private void RequestSelecting(object sender, TabControlCancelEventArgs e)
1481 {
1482 e.Cancel = !e.TabPage.Enabled;
1483 }
3 eva 1484  
1485 private void RequestExportTopScripts(object sender, EventArgs e)
1486 {
1487 vassalForm.BeginInvoke((MethodInvoker) (() =>
1488 {
1489 switch (vassalForm.ExportCSVDialog.ShowDialog())
1490 {
1491 case DialogResult.OK:
1492 string file = vassalForm.ExportCSVDialog.FileName;
1493 new Thread(() =>
1494 {
1495 vassalForm.BeginInvoke((MethodInvoker) (() =>
1496 {
1497 try
1498 {
1499 vassalForm.StatusText.Text = @"exporting...";
1500 vassalForm.StatusProgress.Value = 0;
1501  
1502 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
1503 {
1504 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows)
1505 {
1506 streamWriter.WriteLine(wasEnumerableToCSV(new[]
1507 {
1508 topScriptsRow.Cells["TopScriptsScore"].Value.ToString(),
1509 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString(),
1510 topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(),
1511 topScriptsRow.Cells["TopScriptsOwner"].Value.ToString(),
1512 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString()
1513 }));
1514 }
1515 }
1516  
1517 vassalForm.StatusText.Text = @"exported";
1518 vassalForm.StatusProgress.Value = 100;
1519 }
1520 catch (Exception ex)
1521 {
1522 vassalForm.StatusText.Text = ex.Message;
1523 }
1524 }));
1525 })
7 zed 1526 {IsBackground = true}.Start();
3 eva 1527 break;
1528 }
1529 }));
1530 }
1531  
1532 private void RequestExportTopColliders(object sender, EventArgs e)
1533 {
1534 vassalForm.BeginInvoke((MethodInvoker) (() =>
1535 {
1536 switch (vassalForm.ExportCSVDialog.ShowDialog())
1537 {
1538 case DialogResult.OK:
1539 string file = vassalForm.ExportCSVDialog.FileName;
1540 new Thread(() =>
1541 {
1542 vassalForm.BeginInvoke((MethodInvoker) (() =>
1543 {
1544 try
1545 {
1546 vassalForm.StatusText.Text = @"exporting...";
1547 vassalForm.StatusProgress.Value = 0;
1548  
1549 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
1550 {
1551 foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows)
1552 {
1553 streamWriter.WriteLine(wasEnumerableToCSV(new[]
1554 {
1555 topCollidersRow.Cells["TopCollidersScore"].Value.ToString(),
1556 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString(),
1557 topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(),
1558 topCollidersRow.Cells["TopCollidersOwner"].Value.ToString(),
1559 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString()
1560 }));
1561 }
1562 }
1563  
1564 vassalForm.StatusText.Text = @"exported";
1565 vassalForm.StatusProgress.Value = 100;
1566 }
1567 catch (Exception ex)
1568 {
1569 vassalForm.StatusText.Text = ex.Message;
1570 }
1571 }));
1572 })
7 zed 1573 {IsBackground = true}.Start();
3 eva 1574 break;
1575 }
1576 }));
1577 }
1578  
1579 private void RequestFilterTopScripts(object sender, EventArgs e)
1580 {
1581 vassalForm.BeginInvoke((MethodInvoker) (() =>
1582 {
1583 Regex topScriptsRowRegex;
1584 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
1585 {
1586 case true:
1587 topScriptsRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
1588 break;
1589 default:
1590 topScriptsRowRegex = new Regex(@".+?", RegexOptions.Compiled);
1591 break;
1592 }
1593 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>())
1594 {
1595 topScriptsRow.Visible =
1596 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsScore"].Value.ToString()) ||
1597 topScriptsRowRegex.IsMatch(
1598 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString()) ||
1599 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString()) ||
1600 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsOwner"].Value.ToString()) ||
1601 topScriptsRowRegex.IsMatch(
1602 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString());
1603 }
1604 }));
1605 }
1606  
1607 private void RequestFilterTopColliders(object sender, EventArgs e)
1608 {
7 zed 1609 vassalForm.BeginInvoke((MethodInvoker) (() =>
3 eva 1610 {
1611 Regex topCollidersRowRegex;
1612 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
1613 {
1614 case true:
1615 topCollidersRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
1616 break;
1617 default:
1618 topCollidersRowRegex = new Regex(@".+?", RegexOptions.Compiled);
1619 break;
1620 }
7 zed 1621 foreach (
1622 DataGridViewRow topCollidersRow in TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>())
3 eva 1623 {
1624 topCollidersRow.Visible =
1625 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersScore"].Value.ToString()) ||
1626 topCollidersRowRegex.IsMatch(
1627 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString()) ||
1628 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString()) ||
1629 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersOwner"].Value.ToString()) ||
1630 topCollidersRowRegex.IsMatch(
1631 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString());
1632 }
1633 }));
1634 }
1635  
1636 private void RequestReturnTopScriptsObjects(object sender, EventArgs e)
1637 {
1638 // Block teleports and disable button.
1639 vassalForm.Invoke((MethodInvoker) (() =>
1640 {
1641 vassalForm.ReturnTopScriptsButton.Enabled = false;
1642 RegionTeleportGroup.Enabled = false;
1643 }));
1644  
1645 // Enqueue all the UUIDs to return.
1646 Queue<KeyValuePair<UUID, Vector3>> returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>();
1647 vassalForm.Invoke((MethodInvoker) (() =>
1648 {
1649 foreach (
1650 DataGridViewRow topScriptsRow in
1651 TopScriptsGridView.Rows.AsParallel()
1652 .Cast<DataGridViewRow>()
1653 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
1654 {
1655 Vector3 objectPosition;
1656 UUID returnUUID;
1657 if (!UUID.TryParse(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(), out returnUUID) ||
1658 !Vector3.TryParse(topScriptsRow.Cells["TopScriptsPosition"].Value.ToString(), out objectPosition))
1659 continue;
1660 returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
1661 }
1662 }));
1663  
1664 // If no rows were selected, enable teleports, the return button and return.
1665 if (returnUUIDs.Count.Equals(0))
1666 {
7 zed 1667 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 1668 {
1669 vassalForm.ReturnTopScriptsButton.Enabled = true;
1670 RegionTeleportGroup.Enabled = true;
1671 }));
1672 return;
1673 }
1674  
1675 new Thread(() =>
1676 {
1677 Monitor.Enter(ClientInstanceTeleportLock);
1678  
1679 try
1680 {
8 eva 1681 vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 0; }));
3 eva 1682 int totalObjects = returnUUIDs.Count;
1683 do
1684 {
1685 // Dequeue the first object.
1686 KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue();
1687  
8 eva 1688 vassalForm.Invoke(
1689 (MethodInvoker)
1690 (() => { vassalForm.StatusText.Text = @"Returning object UUID: " + objectData.Key; }));
3 eva 1691  
1692 string currentRegionName = string.Empty;
8 eva 1693 vassalForm.Invoke((MethodInvoker) (() => { currentRegionName = CurrentRegionName.Text; }));
7 zed 1694  
3 eva 1695 // Teleport to the object.
1696 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1697 wasKeyValueEscape(new Dictionary<string, string>
1698 {
1699 {"command", "teleport"},
1700 {"group", vassalConfiguration.Group},
1701 {"password", vassalConfiguration.Password},
1702 {"position", objectData.Value.ToString()},
1703 {"region", currentRegionName},
1704 {"fly", "True"}
1705 }), vassalConfiguration.TeleportTimeout);
1706  
1707 if (string.IsNullOrEmpty(result))
1708 {
8 eva 1709 vassalForm.Invoke(
1710 (MethodInvoker)
1711 (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
3 eva 1712 continue;
1713 }
1714  
1715 // Return the object.
1716 result = wasPOST(vassalConfiguration.HTTPServerURL,
1717 wasKeyValueEscape(new Dictionary<string, string>
1718 {
1719 {"command", "derez"},
1720 {"group", vassalConfiguration.Group},
1721 {"password", vassalConfiguration.Password},
1722 {"item", objectData.Key.ToString()},
7 zed 1723 {"range", "32"}, // maximal prim size = 64 - middle bounding box at half
3 eva 1724 {"type", "ReturnToOwner"}
1725 }), vassalConfiguration.DataTimeout);
1726  
1727 if (string.IsNullOrEmpty(result))
1728 {
8 eva 1729 vassalForm.Invoke(
1730 (MethodInvoker)
1731 (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
3 eva 1732 continue;
1733 }
1734  
1735 bool success;
1736 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1737 {
8 eva 1738 vassalForm.Invoke(
1739 (MethodInvoker)
1740 (() => { vassalForm.StatusText.Text = @"No success status could be retrieved. "; }));
3 eva 1741 continue;
1742 }
1743  
1744 switch (success)
1745 {
1746 case true:
1747 vassalForm.Invoke((MethodInvoker) (() =>
1748 {
8 eva 1749 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key;
3 eva 1750 // Remove the row from the grid view.
7 zed 1751 DataGridViewRow row =
1752 TopScriptsGridView.Rows.AsParallel()
1753 .Cast<DataGridViewRow>()
1754 .FirstOrDefault(
1755 o => o.Cells["TopScriptsUUID"].Value.Equals(objectData.Key.ToString()));
3 eva 1756 if (row == null) return;
1757 int i = row.Index;
1758 TopScriptsGridView.Rows.RemoveAt(i);
1759 }));
1760 break;
1761 case false:
1762 vassalForm.Invoke((MethodInvoker) (() =>
1763 {
8 eva 1764 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key +
3 eva 1765 @": " +
1766 wasInput(wasKeyValueGet("error", result));
1767 }));
1768 break;
1769 }
1770 vassalForm.Invoke((MethodInvoker) (() =>
1771 {
1772 vassalForm.StatusProgress.Value =
8 eva 1773 Math.Min((int) (100d*Math.Abs(returnUUIDs.Count - totalObjects)/totalObjects), 100);
3 eva 1774 }));
1775 } while (!returnUUIDs.Count.Equals(0));
8 eva 1776 vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 100; }));
3 eva 1777 }
1778 catch (Exception ex)
1779 {
8 eva 1780 vassalForm.Invoke(
1781 (MethodInvoker) (() => { vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message; }));
3 eva 1782 }
1783 finally
1784 {
1785 Monitor.Exit(ClientInstanceTeleportLock);
1786 // Allow teleports and enable button.
7 zed 1787 vassalForm.BeginInvoke((MethodInvoker) (() =>
3 eva 1788 {
1789 vassalForm.ReturnTopScriptsButton.Enabled = true;
1790 RegionTeleportGroup.Enabled = true;
1791 }));
1792 }
1793 })
1794 {IsBackground = true}.Start();
1795 }
1796  
1797 private void RequestReturnTopCollidersObjects(object sender, EventArgs e)
1798 {
1799 // Block teleports and disable button.
7 zed 1800 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 1801 {
1802 vassalForm.ReturnTopCollidersButton.Enabled = false;
1803 RegionTeleportGroup.Enabled = false;
1804 }));
1805  
1806 // Enqueue all the UUIDs to return.
7 zed 1807 Queue<KeyValuePair<UUID, Vector3>> returnObjectUUIDQueue = new Queue<KeyValuePair<UUID, Vector3>>();
1808 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 1809 {
1810 foreach (
1811 DataGridViewRow topCollidersRow in
1812 TopCollidersGridView.Rows.AsParallel()
1813 .Cast<DataGridViewRow>()
1814 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
1815 {
1816 Vector3 objectPosition;
1817 UUID returnUUID;
1818 if (!UUID.TryParse(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(), out returnUUID) ||
7 zed 1819 !Vector3.TryParse(topCollidersRow.Cells["TopCollidersPosition"].Value.ToString(),
1820 out objectPosition))
3 eva 1821 continue;
7 zed 1822 returnObjectUUIDQueue.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
3 eva 1823 }
1824 }));
1825  
1826 // If no rows were selected, enable teleports, the return button and return.
7 zed 1827 if (returnObjectUUIDQueue.Count.Equals(0))
3 eva 1828 {
7 zed 1829 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 1830 {
1831 vassalForm.ReturnTopCollidersButton.Enabled = true;
1832 RegionTeleportGroup.Enabled = true;
1833 }));
1834 return;
1835 }
1836  
1837 new Thread(() =>
1838 {
1839 Monitor.Enter(ClientInstanceTeleportLock);
1840  
1841 try
1842 {
8 eva 1843 vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 0; }));
7 zed 1844 int totalObjects = returnObjectUUIDQueue.Count;
3 eva 1845 do
1846 {
1847 // Dequeue the first object.
7 zed 1848 KeyValuePair<UUID, Vector3> objectData = returnObjectUUIDQueue.Dequeue();
3 eva 1849  
8 eva 1850 vassalForm.Invoke(
1851 (MethodInvoker)
1852 (() => { vassalForm.StatusText.Text = @"Returning UUID: " + objectData.Key; }));
3 eva 1853  
1854 string currentRegionName = string.Empty;
8 eva 1855 vassalForm.Invoke((MethodInvoker) (() => { currentRegionName = CurrentRegionName.Text; }));
3 eva 1856  
1857 // Teleport to the object.
1858 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1859 wasKeyValueEscape(new Dictionary<string, string>
1860 {
1861 {"command", "teleport"},
1862 {"group", vassalConfiguration.Group},
1863 {"password", vassalConfiguration.Password},
1864 {"position", objectData.Value.ToString()},
1865 {"region", currentRegionName},
1866 {"fly", "True"}
1867 }), vassalConfiguration.DataTimeout);
1868  
1869 if (string.IsNullOrEmpty(result))
1870 {
8 eva 1871 vassalForm.Invoke(
1872 (MethodInvoker)
1873 (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
3 eva 1874 continue;
1875 }
1876  
1877 // Return the object.
1878 result = wasPOST(vassalConfiguration.HTTPServerURL,
1879 wasKeyValueEscape(new Dictionary<string, string>
1880 {
1881 {"command", "derez"},
1882 {"group", vassalConfiguration.Group},
1883 {"password", vassalConfiguration.Password},
1884 {"item", objectData.Key.ToString()},
7 zed 1885 {"range", "32"}, // maximal prim size = 64 - middle bounding box at half
3 eva 1886 {"type", "ReturnToOwner"}
1887 }), vassalConfiguration.DataTimeout);
1888  
1889 if (string.IsNullOrEmpty(result))
1890 {
8 eva 1891 vassalForm.Invoke(
1892 (MethodInvoker)
1893 (() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
3 eva 1894 continue;
1895 }
1896  
1897 bool success;
1898 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1899 {
8 eva 1900 vassalForm.Invoke(
1901 (MethodInvoker)
1902 (() => { vassalForm.StatusText.Text = @"No success status could be retrieved. "; }));
3 eva 1903 continue;
1904 }
1905  
1906 switch (success)
1907 {
1908 case true:
7 zed 1909 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 1910 {
8 eva 1911 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key;
3 eva 1912 // Remove the row from the grid view.
1913 DataGridViewRow row =
7 zed 1914 TopCollidersGridView.Rows.AsParallel()
1915 .Cast<DataGridViewRow>()
1916 .FirstOrDefault(
1917 o => o.Cells["TopCollidersUUID"].Value.Equals(objectData.Key.ToString()));
3 eva 1918 if (row == null) return;
1919 int i = row.Index;
1920 TopCollidersGridView.Rows.RemoveAt(i);
1921 }));
1922 break;
1923 case false:
7 zed 1924 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 1925 {
8 eva 1926 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key +
3 eva 1927 @": " +
1928 wasInput(wasKeyValueGet("error", result));
1929 }));
1930 break;
1931 }
7 zed 1932 vassalForm.Invoke((MethodInvoker) (() =>
3 eva 1933 {
1934 vassalForm.StatusProgress.Value =
8 eva 1935 Math.Min(
1936 (int) (100d*Math.Abs(returnObjectUUIDQueue.Count - totalObjects)/totalObjects), 100);
3 eva 1937 }));
7 zed 1938 } while (!returnObjectUUIDQueue.Count.Equals(0));
8 eva 1939 vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 100; }));
3 eva 1940 }
1941 catch (Exception ex)
1942 {
8 eva 1943 vassalForm.Invoke(
1944 (MethodInvoker) (() => { vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message; }));
3 eva 1945 }
1946 finally
1947 {
1948 Monitor.Exit(ClientInstanceTeleportLock);
1949 // Allow teleports and enable button.
7 zed 1950 vassalForm.BeginInvoke((MethodInvoker) (() =>
3 eva 1951 {
1952 vassalForm.ReturnTopScriptsButton.Enabled = true;
1953 RegionTeleportGroup.Enabled = true;
1954 }));
1955 }
1956 })
7 zed 1957 {IsBackground = true}.Start();
3 eva 1958 }
1959  
1960 private void RequestBatchRestart(object sender, EventArgs e)
1961 {
7 zed 1962 // Block teleports and disable button.
1963 vassalForm.Invoke((MethodInvoker) (() =>
1964 {
1965 vassalForm.BatchRestartButton.Enabled = false;
1966 RegionTeleportGroup.Enabled = false;
1967 }));
3 eva 1968  
7 zed 1969 // Enqueue all the regions to restart.
1970 Queue<KeyValuePair<string, Vector3>> restartRegionQueue = new Queue<KeyValuePair<string, Vector3>>();
1971 vassalForm.Invoke((MethodInvoker) (() =>
1972 {
1973 foreach (
1974 DataGridViewRow topCollidersRow in
1975 BatchRestartGridView.Rows.AsParallel()
1976 .Cast<DataGridViewRow>()
1977 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
1978 {
1979 Vector3 objectPosition;
1980 string regionName = topCollidersRow.Cells["BatchRestartRegionName"].Value.ToString();
1981 if (string.IsNullOrEmpty(regionName) ||
1982 !Vector3.TryParse(topCollidersRow.Cells["BatchRestartPosition"].Value.ToString(),
1983 out objectPosition))
1984 continue;
1985 restartRegionQueue.Enqueue(new KeyValuePair<string, Vector3>(regionName, objectPosition));
1986 }
1987 }));
1988  
1989 // If no rows were selected, enable teleports, the return button and return.
1990 if (restartRegionQueue.Count.Equals(0))
1991 {
1992 vassalForm.Invoke((MethodInvoker) (() =>
1993 {
1994 vassalForm.BatchRestartButton.Enabled = true;
1995 RegionTeleportGroup.Enabled = true;
1996 }));
1997 return;
1998 }
1999  
2000 new Thread(() =>
2001 {
2002 Monitor.Enter(ClientInstanceTeleportLock);
2003  
2004 try
2005 {
2006 do
2007 {
2008 // Dequeue the first object.
2009 KeyValuePair<string, Vector3> restartRegionData = restartRegionQueue.Dequeue();
2010 DataGridViewRow currentDataGridViewRow = null;
2011 vassalForm.Invoke((MethodInvoker) (() =>
2012 {
2013 currentDataGridViewRow = vassalForm.BatchRestartGridView.Rows.AsParallel()
2014 .Cast<DataGridViewRow>()
2015 .FirstOrDefault(
2016 o =>
2017 o.Cells["BatchRestartRegionName"].Value.ToString()
2018 .Equals(restartRegionData.Key, StringComparison.OrdinalIgnoreCase) &&
2019 o.Cells["BatchRestartPosition"].Value.ToString()
2020 .Equals(restartRegionData.Value.ToString(),
2021 StringComparison.OrdinalIgnoreCase));
2022 }));
2023  
2024 if (currentDataGridViewRow == null) continue;
2025  
2026 try
2027 {
2028 bool success = false;
2029 string result;
2030  
2031 // Retry to teleport to each region a few times.
2032 int teleportRetries = 3;
2033 do
2034 {
2035 vassalForm.Invoke((MethodInvoker) (() =>
2036 {
2037 vassalForm.StatusText.Text = @"Attempting to teleport to " + restartRegionData.Key +
2038 @" " + @"(" +
2039 teleportRetries.ToString(Utils.EnUsCulture) +
2040 @")";
2041 }));
2042  
2043 // Teleport to the region.
2044 result = wasPOST(vassalConfiguration.HTTPServerURL,
2045 wasKeyValueEscape(new Dictionary<string, string>
2046 {
2047 {"command", "teleport"},
2048 {"group", vassalConfiguration.Group},
2049 {"password", vassalConfiguration.Password},
2050 {"position", restartRegionData.Value.ToString()},
2051 {"region", restartRegionData.Key},
2052 {"fly", "True"}
2053 }), vassalConfiguration.DataTimeout);
2054  
2055 if (string.IsNullOrEmpty(result))
2056 {
8 eva 2057 vassalForm.Invoke(
2058 (MethodInvoker)
2059 (() =>
2060 {
2061 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
2062 }));
7 zed 2063 continue;
2064 }
2065 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2066 {
8 eva 2067 vassalForm.Invoke(
2068 (MethodInvoker)
2069 (() =>
2070 {
2071 vassalForm.StatusText.Text = @"No success status could be retrieved. ";
2072 }));
7 zed 2073 continue;
2074 }
2075 switch (success)
2076 {
2077 case true:
8 eva 2078 vassalForm.Invoke(
2079 (MethodInvoker)
2080 (() => { vassalForm.StatusText.Text = @"Teleport succeeded."; }));
7 zed 2081 break;
2082 default:
2083 // In case the destination is to close (Corrade status code 37559),
2084 // then we are on the same region so no need to retry.
2085 uint status; //37559
2086 switch (
2087 uint.TryParse(wasInput(wasKeyValueGet("status", result)), out status) &&
2088 status.Equals(37559))
2089 {
2090 case true: // We are on the region already!
2091 success = true;
2092 break;
2093 default:
8 eva 2094 vassalForm.Invoke(
2095 (MethodInvoker)
2096 (() => { vassalForm.StatusText.Text = @"Teleport failed."; }));
7 zed 2097 break;
2098 }
2099 break;
2100 }
12 zed 2101  
2102 // Pause for teleport (10 teleports / 15s allowed).
2103 Thread.Sleep(700);
7 zed 2104 } while (!success && !(--teleportRetries).Equals(0));
2105  
2106 if (!success)
2107 throw new Exception("Failed to teleport to region.");
2108  
2109 result = wasPOST(vassalConfiguration.HTTPServerURL,
2110 wasKeyValueEscape(new Dictionary<string, string>
2111 {
2112 {"command", "getregiondata"},
2113 {"group", vassalConfiguration.Group},
2114 {"password", vassalConfiguration.Password},
2115 {"data", "IsEstateManager"}
2116 }), vassalConfiguration.DataTimeout);
2117  
2118 if (string.IsNullOrEmpty(result))
2119 throw new Exception("Error communicating with Corrade.");
2120  
2121 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2122 throw new Exception("No success status could be retrieved.");
2123  
2124 if (!success)
2125 throw new Exception("Could not retrieve estate rights.");
2126  
2127 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
2128 if (!data.Count.Equals(2))
2129 throw new Exception("Could not retrieve estate rights.");
2130  
2131 bool isEstateManager;
2132 switch (
2133 bool.TryParse(data[data.IndexOf("IsEstateManager") + 1], out isEstateManager) &&
2134 isEstateManager)
2135 {
2136 case true: // we are an estate manager
2137 result = wasPOST(vassalConfiguration.HTTPServerURL,
2138 wasKeyValueEscape(new Dictionary<string, string>
2139 {
2140 {"command", "restartregion"},
2141 {"group", vassalConfiguration.Group},
2142 {"password", vassalConfiguration.Password},
2143 {"action", "restart"},
2144 {
8 eva 2145 "delay",
2146 vassalConfiguration.RegionRestartDelay.ToString(Utils.EnUsCulture)
7 zed 2147 }
2148 }), vassalConfiguration.DataTimeout);
2149  
2150 if (string.IsNullOrEmpty(result))
2151 throw new Exception("Error communicating with Corrade.");
2152  
2153 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2154 throw new Exception("No success status could be retrieved.");
2155  
2156 if (!success)
2157 throw new Exception("Could not schedule a region restart.");
2158  
2159 vassalForm.Invoke((MethodInvoker) (() =>
2160 {
2161 vassalForm.StatusText.Text = @"Region scheduled for restart.";
2162 currentDataGridViewRow.Selected = false;
2163 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
2164 foreach (
2165 DataGridViewCell cell in
2166 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
2167 {
2168 cell.ToolTipText = @"Region scheduled for restart.";
2169 }
2170 }));
2171 break;
2172 default:
2173 throw new Exception("No estate manager rights for region restart.");
2174 }
2175 }
2176 catch (Exception ex)
2177 {
2178 vassalForm.Invoke((MethodInvoker) (() =>
2179 {
2180 vassalForm.StatusText.Text = ex.Message;
2181 currentDataGridViewRow.Selected = false;
2182 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
2183 foreach (
2184 DataGridViewCell cell in
2185 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
2186 {
2187 cell.ToolTipText = ex.Message;
2188 }
2189 }));
2190 }
12 zed 2191 finally
2192 {
2193 // Pause for teleport (10 teleports / 15s allowed).
2194 Thread.Sleep(700);
2195 }
7 zed 2196 } while (!restartRegionQueue.Count.Equals(0));
2197 }
2198 catch (Exception)
2199 {
2200 }
2201 finally
2202 {
2203 Monitor.Exit(ClientInstanceTeleportLock);
2204 // Allow teleports and enable button.
2205 vassalForm.BeginInvoke((MethodInvoker) (() =>
2206 {
2207 vassalForm.BatchRestartButton.Enabled = true;
2208 RegionTeleportGroup.Enabled = true;
2209 }));
2210 }
2211 })
2212 {IsBackground = true}.Start();
3 eva 2213 }
7 zed 2214  
2215 private void RequestFilterResidentList(object sender, EventArgs e)
2216 {
2217 vassalForm.BeginInvoke((MethodInvoker) (() =>
2218 {
2219 Regex residentListRowRegex;
2220 switch (!string.IsNullOrEmpty(ResidentListFilter.Text))
2221 {
2222 case true:
2223 residentListRowRegex = new Regex(ResidentListFilter.Text, RegexOptions.Compiled);
2224 break;
2225 default:
2226 residentListRowRegex = new Regex(@".+?", RegexOptions.Compiled);
2227 break;
2228 }
2229 foreach (
2230 DataGridViewRow residentListRow in ResidentListGridView.Rows.AsParallel().Cast<DataGridViewRow>())
2231 {
2232 residentListRow.Visible =
2233 residentListRowRegex.IsMatch(residentListRow.Cells["ResidentListName"].Value.ToString()) ||
2234 residentListRowRegex.IsMatch(
2235 residentListRow.Cells["ResidentListUUID"].Value.ToString()) ||
2236 residentListRowRegex.IsMatch(residentListRow.Cells["ResidentListPosition"].Value.ToString());
2237 }
2238 }));
2239 }
2240  
2241 private void RequestBanAgents(object sender, EventArgs e)
2242 {
2243 // Block teleports and disable button.
2244 vassalForm.Invoke((MethodInvoker) (() =>
2245 {
12 zed 2246 ResidentListTeleportHomeGroup.Enabled = false;
7 zed 2247 ResidentListBanGroup.Enabled = false;
2248 RegionTeleportGroup.Enabled = false;
2249 }));
2250  
12 zed 2251 // Enqueue all the agents to ban.
7 zed 2252 Queue<UUID> agentsQueue = new Queue<UUID>();
2253 vassalForm.Invoke((MethodInvoker) (() =>
2254 {
2255 foreach (
2256 DataGridViewRow residentListRow in
2257 ResidentListGridView.Rows.AsParallel()
2258 .Cast<DataGridViewRow>()
2259 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
2260 {
2261 UUID agentUUID;
2262 if (!UUID.TryParse(residentListRow.Cells["ResidentListUUID"].Value.ToString(), out agentUUID))
2263 continue;
2264 agentsQueue.Enqueue(agentUUID);
2265 }
2266 }));
2267  
2268 // If no rows were selected, enable teleports, the return button and return.
2269 if (agentsQueue.Count.Equals(0))
2270 {
2271 vassalForm.Invoke((MethodInvoker) (() =>
2272 {
2273 ResidentListBanGroup.Enabled = true;
2274 RegionTeleportGroup.Enabled = true;
2275 }));
2276 return;
2277 }
2278  
2279 new Thread(() =>
2280 {
2281 Monitor.Enter(ClientInstanceTeleportLock);
2282 try
2283 {
2284 do
2285 {
2286 // Dequeue the first object.
2287 UUID agentUUID = agentsQueue.Dequeue();
2288 DataGridViewRow currentDataGridViewRow = null;
2289 vassalForm.Invoke((MethodInvoker) (() =>
2290 {
2291 currentDataGridViewRow = vassalForm.ResidentListGridView.Rows.AsParallel()
2292 .Cast<DataGridViewRow>()
2293 .FirstOrDefault(
2294 o =>
2295 o.Cells["ResidentListUUID"].Value.ToString()
2296 .Equals(agentUUID.ToString(), StringComparison.OrdinalIgnoreCase));
2297 }));
2298  
2299 if (currentDataGridViewRow == null) continue;
2300  
2301 try
2302 {
2303 bool alsoBan = false;
8 eva 2304 vassalForm.Invoke(
2305 (MethodInvoker) (() => { alsoBan = vassalForm.ResidentBanAllEstatesBox.Checked; }));
7 zed 2306  
12 zed 2307 // Ban the resident.
7 zed 2308 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2309 wasKeyValueEscape(new Dictionary<string, string>
2310 {
2311 {"command", "setestatelist"},
2312 {"group", vassalConfiguration.Group},
2313 {"password", vassalConfiguration.Password},
2314 {"type", "ban"},
2315 {"action", "add"},
2316 {"agent", agentUUID.ToString()},
2317 {"all", alsoBan.ToString()}
2318 }), vassalConfiguration.DataTimeout);
2319  
2320 if (string.IsNullOrEmpty(result))
2321 throw new Exception("Error communicating with Corrade.");
2322  
2323 bool success;
2324 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2325 throw new Exception("No success status could be retrieved.");
2326  
2327 switch (success)
2328 {
2329 case true:
2330 vassalForm.Invoke((MethodInvoker) (() =>
2331 {
2332 vassalForm.StatusText.Text = @"Resident banned.";
2333 currentDataGridViewRow.Selected = false;
2334 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
2335 foreach (
2336 DataGridViewCell cell in
2337 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
2338 {
2339 cell.ToolTipText = @"Resident banned.";
2340 }
2341 }));
2342 break;
2343 default:
2344 throw new Exception("Unable to ban resident.");
2345 }
2346 }
2347 catch (Exception ex)
2348 {
2349 vassalForm.Invoke((MethodInvoker) (() =>
2350 {
2351 vassalForm.StatusText.Text = ex.Message;
2352 currentDataGridViewRow.Selected = false;
2353 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
2354 foreach (
2355 DataGridViewCell cell in
2356 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
2357 {
2358 cell.ToolTipText = ex.Message;
2359 }
2360 }));
2361 }
2362 } while (agentsQueue.Count.Equals(0));
2363 }
2364 catch (Exception)
2365 {
2366 }
2367 finally
2368 {
2369 Monitor.Exit(ClientInstanceTeleportLock);
2370 // Allow teleports and enable button.
2371 vassalForm.BeginInvoke((MethodInvoker) (() =>
2372 {
12 zed 2373 ResidentListTeleportHomeGroup.Enabled = true;
7 zed 2374 ResidentListBanGroup.Enabled = true;
2375 RegionTeleportGroup.Enabled = true;
2376 }));
2377 }
2378 })
2379 {IsBackground = true}.Start();
2380 }
2381  
2382 private void RequestRipTerrain(object sender, EventArgs e)
2383 {
2384 // Block teleports and disable button.
2385 vassalForm.Invoke((MethodInvoker) (() =>
2386 {
2387 RegionTeleportGroup.Enabled = false;
2388 RipTerrainButton.Enabled = false;
2389 }));
2390  
2391 new Thread(() =>
2392 {
2393 Monitor.Enter(ClientInstanceTeleportLock);
2394  
2395 try
2396 {
8 eva 2397 // Get the map heights.
7 zed 2398 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2399 wasKeyValueEscape(new Dictionary<string, string>
2400 {
2401 {"command", "getterrainheight"},
2402 {"group", vassalConfiguration.Group},
2403 {"password", vassalConfiguration.Password},
2404 {"entity", "region"}
2405 }), vassalConfiguration.DataTimeout);
2406  
2407 if (string.IsNullOrEmpty(result))
2408 throw new Exception("Error communicating with Corrade.");
2409  
2410 bool success;
2411 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2412 throw new Exception("No success status could be retrieved.");
2413  
2414 if (!success)
2415 throw new Exception("Could not get terrain heights.");
2416  
2417 List<double> heights = new List<double>();
2418 foreach (string map in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))))
2419 {
2420 double height;
2421 if (!double.TryParse(map, out height))
2422 continue;
2423 heights.Add(height);
2424 }
2425 if (heights.Count.Equals(0))
2426 throw new Exception("Could not get terrain heights.");
2427  
2428 double maxHeight = heights.Max();
2429 using (Bitmap bitmap = new Bitmap(256, 256))
2430 {
2431 foreach (int x in Enumerable.Range(1, 255))
2432 {
2433 foreach (int y in Enumerable.Range(1, 255))
2434 {
2435 bitmap.SetPixel(x, 256 - y,
8 eva 2436 Color.FromArgb(
2437 Math.Max((int) wasMapValueToRange(heights[256*x + y], 0, maxHeight, 0, 255), 0),
2438 0, 0));
7 zed 2439 }
2440 }
8 eva 2441 Bitmap closureBitmap = (Bitmap) bitmap.Clone();
7 zed 2442 vassalForm.BeginInvoke((MethodInvoker) (() =>
2443 {
8 eva 2444 switch (vassalForm.SavePNGFileDialog.ShowDialog())
7 zed 2445 {
2446 case DialogResult.OK:
8 eva 2447 string file = vassalForm.SavePNGFileDialog.FileName;
7 zed 2448 new Thread(() =>
2449 {
2450 vassalForm.BeginInvoke((MethodInvoker) (() =>
2451 {
2452 try
2453 {
2454 vassalForm.StatusText.Text = @"saving terrain...";
2455 vassalForm.StatusProgress.Value = 0;
2456  
2457 closureBitmap.Save(file, ImageFormat.Png);
2458  
2459 vassalForm.StatusText.Text = @"terrain saved";
2460 vassalForm.StatusProgress.Value = 100;
2461 }
2462 catch (Exception ex)
2463 {
2464 vassalForm.StatusText.Text = ex.Message;
2465 }
2466 finally
2467 {
2468 closureBitmap.Dispose();
2469 }
2470 }));
2471 })
8 eva 2472 {IsBackground = true}.Start();
7 zed 2473 break;
2474 }
2475 }));
2476 }
2477 }
2478 catch (Exception ex)
2479 {
8 eva 2480 vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
2481 }
2482 finally
2483 {
2484 Monitor.Exit(ClientInstanceTeleportLock);
2485 vassalForm.BeginInvoke((MethodInvoker) (() =>
7 zed 2486 {
8 eva 2487 RegionTeleportGroup.Enabled = true;
2488 RipTerrainButton.Enabled = true;
7 zed 2489 }));
2490 }
8 eva 2491 }) {IsBackground = true}.Start();
2492 }
2493  
2494 private void RequestDownloadTerrain(object sender, EventArgs e)
2495 {
2496 // Block teleports and disable button.
2497 vassalForm.Invoke((MethodInvoker) (() =>
2498 {
2499 RegionTeleportGroup.Enabled = false;
2500 DownloadTerrainButton.Enabled = false;
2501 }));
2502  
2503 new Thread(() =>
2504 {
2505 Monitor.Enter(ClientInstanceTeleportLock);
2506  
2507 try
2508 {
2509 // Download the terrain.
2510 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2511 wasKeyValueEscape(new Dictionary<string, string>
2512 {
2513 {"command", "terrain"},
2514 {"group", vassalConfiguration.Group},
2515 {"password", vassalConfiguration.Password},
2516 {"action", "get"}
2517 }), vassalConfiguration.DataTimeout);
2518  
2519 if (string.IsNullOrEmpty(result))
2520 throw new Exception("Error communicating with Corrade.");
2521  
2522 bool success;
2523 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2524 throw new Exception("No success status could be retrieved.");
2525  
2526 if (!success)
2527 throw new Exception("Could not download terrain.");
2528  
2529 byte[] data = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
2530  
2531 vassalForm.BeginInvoke((MethodInvoker) (() =>
2532 {
2533 switch (vassalForm.SaveRawFileDialog.ShowDialog())
2534 {
2535 case DialogResult.OK:
2536 string file = vassalForm.SaveRawFileDialog.FileName;
2537 new Thread(() =>
2538 {
2539 vassalForm.BeginInvoke((MethodInvoker) (() =>
2540 {
2541 try
2542 {
2543 vassalForm.StatusText.Text = @"saving terrain...";
2544 vassalForm.StatusProgress.Value = 0;
2545  
2546 File.WriteAllBytes(file, data);
2547  
2548 vassalForm.StatusText.Text = @"terrain saved";
2549 vassalForm.StatusProgress.Value = 100;
2550 }
2551 catch (Exception ex)
2552 {
2553 vassalForm.StatusText.Text = ex.Message;
2554 }
2555 }));
2556 })
2557 {IsBackground = true}.Start();
2558 break;
2559 }
2560 }));
2561 }
2562 catch (Exception ex)
2563 {
2564 vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
2565 }
7 zed 2566 finally
2567 {
2568 Monitor.Exit(ClientInstanceTeleportLock);
8 eva 2569 vassalForm.BeginInvoke((MethodInvoker) (() =>
7 zed 2570 {
8 eva 2571 DownloadTerrainButton.Enabled = true;
7 zed 2572 RegionTeleportGroup.Enabled = true;
2573 }));
2574 }
8 eva 2575 })
2576 {IsBackground = true}.Start();
2577 }
7 zed 2578  
8 eva 2579 private void RequestUploadTerrain(object sender, EventArgs e)
2580 {
2581 // Block teleports and disable button.
2582 vassalForm.Invoke((MethodInvoker) (() =>
2583 {
2584 RegionTeleportGroup.Enabled = false;
2585 UploadTerrainButton.Enabled = false;
2586 }));
2587  
2588 new Thread(() =>
2589 {
2590 Monitor.Enter(ClientInstanceTeleportLock);
2591  
2592 try
2593 {
2594 byte[] data = null;
2595 vassalForm.Invoke((MethodInvoker) (() =>
2596 {
2597 switch (vassalForm.LoadRawFileDialog.ShowDialog())
2598 {
2599 case DialogResult.OK:
2600 string file = vassalForm.LoadRawFileDialog.FileName;
2601 vassalForm.StatusText.Text = @"loading terrain...";
2602 vassalForm.StatusProgress.Value = 0;
2603  
2604 data = File.ReadAllBytes(file);
2605  
2606 vassalForm.StatusText.Text = @"terrain loaded";
2607 vassalForm.StatusProgress.Value = 100;
2608 break;
2609 }
2610 }));
2611  
2612 // Upload the terrain.
2613 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2614 wasKeyValueEscape(new Dictionary<string, string>
2615 {
2616 {"command", "terrain"},
2617 {"group", vassalConfiguration.Group},
2618 {"password", vassalConfiguration.Password},
2619 {"action", "set"},
2620 {"data", Convert.ToBase64String(data)}
2621 }), vassalConfiguration.DataTimeout);
2622  
2623 if (string.IsNullOrEmpty(result))
2624 throw new Exception("Error communicating with Corrade.");
2625  
2626 bool success;
2627 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2628 throw new Exception("No success status could be retrieved.");
2629  
2630 if (!success)
2631 throw new Exception("Could not upload terrain.");
2632 }
2633 catch (Exception ex)
2634 {
2635 vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
2636 }
2637 finally
2638 {
2639 Monitor.Exit(ClientInstanceTeleportLock);
2640 vassalForm.BeginInvoke((MethodInvoker) (() =>
2641 {
2642 UploadTerrainButton.Enabled = true;
2643 RegionTeleportGroup.Enabled = true;
2644 }));
2645 }
2646 })
2647 {IsBackground = true}.Start();
7 zed 2648 }
8 eva 2649  
2650 private void RequestTabsChanged(object sender, EventArgs e)
2651 {
2652 vassalForm.BeginInvoke((MethodInvoker) (() =>
2653 {
2654 overviewTabTimer.Stop();
2655 regionsStateTabTimer.Stop();
2656 residentListTabTimer.Stop();
2657 estateTopTabTimer.Stop();
2658  
2659 if (Tabs.SelectedTab.Equals(OverviewTab))
2660 {
2661 overviewTabTimer.Start();
2662 return;
2663 }
2664 if (Tabs.SelectedTab.Equals(RegionsStateTab))
2665 {
2666 regionsStateTabTimer.Start();
2667 return;
2668 }
2669 if (Tabs.SelectedTab.Equals(ResidentListTab))
2670 {
2671 residentListTabTimer.Start();
2672 return;
2673 }
2674 if (Tabs.SelectedTab.Equals(EstateTopTab))
2675 {
2676 estateTopTabTimer.Start();
2677 return;
2678 }
2679 if (Tabs.SelectedTab.Equals(EstateTexturesTab))
2680 {
2681 estateTexturesTabTimer.Start();
2682 }
2683 }));
2684 }
2685  
2686 private void RequestFilterEstateList(object sender, EventArgs e)
2687 {
2688 vassalForm.BeginInvoke((MethodInvoker) (() =>
2689 {
2690 Regex estateListRowRegex;
2691 switch (!string.IsNullOrEmpty(EstateListFilter.Text))
2692 {
2693 case true:
2694 estateListRowRegex = new Regex(EstateListFilter.Text, RegexOptions.Compiled);
2695 break;
2696 default:
2697 estateListRowRegex = new Regex(@".+?", RegexOptions.Compiled);
2698 break;
2699 }
2700 foreach (DataGridViewRow estateListRow in EstateListGridView.Rows.AsParallel().Cast<DataGridViewRow>())
2701 {
2702 estateListRow.Visible =
2703 estateListRowRegex.IsMatch(estateListRow.Cells["EstateListName"].Value.ToString());
2704 }
2705 }));
2706 }
2707  
2708 private void EstateListSelected(object sender, EventArgs e)
2709 {
2710 string selectedEstateListType = string.Empty;
2711 bool queryEstateList = false;
2712 vassalForm.Invoke((MethodInvoker) (() =>
2713 {
2714 if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
2715 selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
2716 switch (
2717 !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
2718 {
2719 case true:
2720 queryEstateList = true;
2721 break;
2722 default:
2723 EstateListsResidentsGroup.Enabled = false;
2724 EstateListsGroupsGroup.Enabled = false;
2725 queryEstateList = false;
2726 break;
2727 }
2728 }));
2729  
2730 if (!queryEstateList) return;
2731  
2732 new Thread(() =>
2733 {
2734 try
2735 {
2736 Monitor.Enter(ClientInstanceTeleportLock);
2737  
2738 // Disable controls.
2739 vassalForm.Invoke((MethodInvoker) (() =>
2740 {
2741 RegionTeleportGroup.Enabled = false;
2742 EstateListsResidentsGroup.Enabled = false;
2743 EstateListsGroupsGroup.Enabled = false;
2744 }));
2745  
2746 // Get the selected estate list.
2747 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2748 wasKeyValueEscape(new Dictionary<string, string>
2749 {
2750 {"command", "getestatelist"},
2751 {"group", vassalConfiguration.Group},
2752 {"password", vassalConfiguration.Password},
2753 {"type", selectedEstateListType}
2754 }), vassalConfiguration.DataTimeout);
2755  
2756 if (string.IsNullOrEmpty(result))
2757 throw new Exception("Error communicating with Corrade.");
2758  
2759 bool success;
2760 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2761 throw new Exception("No success status could be retrieved.");
2762  
2763 if (!success)
2764 throw new Exception("Could not retrieve estate list.");
2765  
2766 vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
2767 foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
2768 .Where(x => !string.IsNullOrEmpty(x))
2769 .Select((x, i) => new {Index = i, Value = x})
2770 .GroupBy(x => x.Index/2)
2771 .Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
2772 {
2773 vassalForm.Invoke(
2774 (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
2775 }
2776 }
2777 catch (Exception ex)
2778 {
2779 vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusText.Text = ex.Message; }));
2780 }
2781 finally
2782 {
2783 Monitor.Exit(ClientInstanceTeleportLock);
2784 // Enable controls
2785 vassalForm.Invoke((MethodInvoker) (() =>
2786 {
2787 vassalForm.RegionTeleportGroup.Enabled = true;
2788  
2789 switch (selectedEstateListType)
2790 {
2791 case "ban":
2792 case "manager":
2793 case "user":
2794 EstateListsResidentsGroup.Enabled = true;
2795 EstateListsGroupsGroup.Enabled = false;
2796 break;
2797 case "group":
2798 EstateListsResidentsGroup.Enabled = false;
2799 EstateListsGroupsGroup.Enabled = true;
2800 break;
2801 }
2802 }));
2803 }
2804 })
2805 {IsBackground = true}.Start();
2806 }
2807  
2808 private void RequestRemoveEstateListMember(object sender, EventArgs e)
2809 {
2810 // Get the estate list type.
2811 string selectedEstateListType = string.Empty;
2812 bool queryEstateList = false;
2813 vassalForm.Invoke((MethodInvoker) (() =>
2814 {
2815 if (vassalForm.EstateListSelectBox.SelectedItem == null)
2816 {
2817 queryEstateList = false;
2818 return;
2819 }
2820 selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
2821 switch (
2822 !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
2823 {
2824 case true:
2825 queryEstateList = true;
2826 break;
2827 default:
2828 queryEstateList = false;
2829 break;
2830 }
2831 }));
2832  
2833 // If not estate list type is selected then return.
2834 if (!queryEstateList) return;
2835  
2836 // Enqueue all the regions to restart.
2837 Queue<UUID> estateListMembersQueue = new Queue<UUID>();
2838 vassalForm.Invoke((MethodInvoker) (() =>
2839 {
2840 foreach (
2841 DataGridViewRow estateListRow in
2842 EstateListGridView.Rows.AsParallel()
2843 .Cast<DataGridViewRow>()
2844 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
2845 {
2846 UUID estateListMemberUUID;
2847 if (!UUID.TryParse(estateListRow.Cells["EstateListUUID"].Value.ToString(),
2848 out estateListMemberUUID))
2849 continue;
2850 estateListMembersQueue.Enqueue(estateListMemberUUID);
2851 }
2852 }));
2853  
2854 // If no rows were selected, enable teleports, the return button and return.
2855 if (estateListMembersQueue.Count.Equals(0)) return;
2856  
2857 // Block teleports and disable button.
2858 vassalForm.Invoke((MethodInvoker) (() =>
2859 {
2860 RegionTeleportGroup.Enabled = false;
2861 RemoveEstateListMemberButton.Enabled = false;
2862 }));
2863  
2864 new Thread(() =>
2865 {
2866 try
2867 {
2868 Monitor.Enter(ClientInstanceTeleportLock);
2869 UUID memberUUID = UUID.Zero;
2870 do
2871 {
2872 try
2873 {
2874 memberUUID = estateListMembersQueue.Dequeue();
2875  
2876 // Remove the agent or group from the list.
2877 string result = wasPOST(vassalConfiguration.HTTPServerURL,
2878 wasKeyValueEscape(new Dictionary<string, string>
2879 {
2880 {"command", "setestatelist"},
2881 {"group", vassalConfiguration.Group},
2882 {"password", vassalConfiguration.Password},
2883 {"type", selectedEstateListType},
2884 {"action", "remove"},
2885 {selectedEstateListType.Equals("group") ? "target" : "agent", memberUUID.ToString()}
2886 }), vassalConfiguration.DataTimeout);
2887  
2888 if (string.IsNullOrEmpty(result))
2889 throw new Exception("Error communicating with Corrade");
2890  
2891 bool success;
2892 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
2893 throw new Exception("No success status could be retrieved");
2894  
2895 if (!success)
2896 throw new Exception("Unable to remove member");
2897  
2898 vassalForm.Invoke((MethodInvoker) (() =>
2899 {
2900 foreach (
2901 int i in
2902 EstateListGridView.Rows.AsParallel()
2903 .Cast<DataGridViewRow>()
2904 .Where(
2905 o =>
2906 o.Cells["EstateListUUID"].Value.ToString()
2907 .Equals(memberUUID.ToString(),
2908 StringComparison.OrdinalIgnoreCase)).Select(o => o.Index)
2909 )
2910 {
2911 EstateListGridView.Rows.RemoveAt(i);
2912 }
2913 }));
2914 }
2915 catch (Exception ex)
2916 {
2917 vassalForm.Invoke(
2918 (MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + memberUUID; }));
2919 }
2920 } while (!estateListMembersQueue.Count.Equals(0));
2921 }
2922 catch (Exception)
2923 {
2924 }
2925 finally
2926 {
2927 Monitor.Exit(ClientInstanceTeleportLock);
2928 // Enable teleports and enable button.
2929 vassalForm.Invoke((MethodInvoker) (() =>
2930 {
2931 RegionTeleportGroup.Enabled = true;
2932 RemoveEstateListMemberButton.Enabled = true;
2933 }));
2934 }
2935 })
2936 {IsBackground = true}.Start();
2937 }
2938  
2939 private void RequestEstateListsAddResident(object sender, EventArgs e)
2940 {
2941 // Get the estate list type.
2942 string selectedEstateListType = string.Empty;
2943 bool queryEstateList = false;
2944 vassalForm.Invoke((MethodInvoker) (() =>
2945 {
2946 selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
2947 switch (
2948 !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
2949 {
2950 case true:
2951 queryEstateList = true;
2952 break;
2953 default:
2954 queryEstateList = false;
2955 break;
2956 }
2957 }));
2958  
2959 // If not estate list type is selected then return.
2960 if (!queryEstateList) return;
2961  
2962 string firstName = string.Empty;
2963 string lastName = string.Empty;
2964  
2965 vassalForm.Invoke((MethodInvoker) (() =>
2966 {
2967 switch (string.IsNullOrEmpty(EstateListsResidentFirstName.Text))
2968 {
2969 case true:
2970 EstateListsResidentFirstName.BackColor = Color.MistyRose;
2971 return;
2972 default:
2973 EstateListsResidentFirstName.BackColor = Color.Empty;
2974 break;
2975 }
2976 firstName = EstateListsResidentFirstName.Text;
2977 switch (string.IsNullOrEmpty(EstateListsResidentLastName.Text))
2978 {
2979 case true:
2980 EstateListsResidentLastName.BackColor = Color.MistyRose;
2981 return;
2982 default:
2983 EstateListsResidentLastName.BackColor = Color.Empty;
2984 break;
2985 }
2986 lastName = EstateListsResidentLastName.Text;
2987 }));
2988  
2989 if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)) return;
2990  
2991 // Block teleports and disable button.
2992 vassalForm.Invoke((MethodInvoker) (() =>
2993 {
2994 RegionTeleportGroup.Enabled = false;
2995 EstateListsResidentsGroup.Enabled = false;
2996 }));
2997  
2998 new Thread(() =>
2999 {
3000 try
3001 {
3002 Monitor.Enter(ClientInstanceTeleportLock);
3003  
3004 // Add the resident to the list.
3005 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3006 wasKeyValueEscape(new Dictionary<string, string>
3007 {
3008 {"command", "setestatelist"},
3009 {"group", vassalConfiguration.Group},
3010 {"password", vassalConfiguration.Password},
3011 {"type", selectedEstateListType},
3012 {"action", "add"},
3013 {"firstname", firstName},
3014 {"lastname", lastName}
3015 }), vassalConfiguration.DataTimeout);
3016  
3017 if (string.IsNullOrEmpty(result))
3018 throw new Exception("Error communicating with Corrade");
3019  
3020 bool success;
3021 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3022 throw new Exception("No success status could be retrieved");
3023  
3024 if (!success)
3025 throw new Exception("Unable to add resident");
3026  
3027 // Retrieve the estate list for updates.
3028 result = wasPOST(vassalConfiguration.HTTPServerURL,
3029 wasKeyValueEscape(new Dictionary<string, string>
3030 {
3031 {"command", "getestatelist"},
3032 {"group", vassalConfiguration.Group},
3033 {"password", vassalConfiguration.Password},
3034 {"type", selectedEstateListType}
3035 }), vassalConfiguration.DataTimeout);
3036  
3037 if (string.IsNullOrEmpty(result))
3038 throw new Exception("Error communicating with Corrade.");
3039  
3040 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3041 throw new Exception("No success status could be retrieved.");
3042  
3043 if (!success)
3044 throw new Exception("Could not retrieve estate list.");
3045  
3046 vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
3047 foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
3048 .Where(x => !string.IsNullOrEmpty(x))
3049 .Select((x, i) => new {Index = i, Value = x})
3050 .GroupBy(x => x.Index/2)
3051 .Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
3052 {
3053 vassalForm.Invoke(
3054 (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
3055 }
3056 }
3057 catch (Exception ex)
3058 {
3059 vassalForm.Invoke(
3060 (MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + firstName + @" " + lastName; }));
3061 }
3062 finally
3063 {
3064 Monitor.Exit(ClientInstanceTeleportLock);
3065 // Enable teleports and enable button.
3066 vassalForm.Invoke((MethodInvoker) (() =>
3067 {
3068 RegionTeleportGroup.Enabled = true;
3069 EstateListsResidentsGroup.Enabled = true;
3070 }));
3071 }
3072 })
3073 {IsBackground = true}.Start();
3074 }
3075  
3076 private void RequestEstateListsAddGroup(object sender, EventArgs e)
3077 {
3078 // Get the estate list type.
3079 string selectedEstateListType = string.Empty;
3080 bool queryEstateList = false;
3081 vassalForm.Invoke((MethodInvoker) (() =>
3082 {
3083 selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
3084 switch (
3085 !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
3086 {
3087 case true:
3088 queryEstateList = true;
3089 break;
3090 default:
3091 queryEstateList = false;
3092 break;
3093 }
3094 }));
3095  
3096 // If not estate list type is selected then return.
3097 if (!queryEstateList) return;
3098  
3099 string target = string.Empty;
3100  
3101 vassalForm.Invoke((MethodInvoker) (() =>
3102 {
3103 switch (string.IsNullOrEmpty(EstateListsAddGroupBox.Text))
3104 {
3105 case true:
3106 EstateListsAddGroupBox.BackColor = Color.MistyRose;
3107 return;
3108 default:
3109 EstateListsAddGroupBox.BackColor = Color.Empty;
3110 break;
3111 }
3112 target = EstateListsAddGroupBox.Text;
3113 }));
3114  
3115 if (string.IsNullOrEmpty(target)) return;
3116  
3117 // Block teleports and disable button.
3118 vassalForm.Invoke((MethodInvoker) (() =>
3119 {
3120 RegionTeleportGroup.Enabled = false;
3121 EstateListsGroupsGroup.Enabled = false;
3122 }));
3123  
3124 new Thread(() =>
3125 {
3126 try
3127 {
3128 Monitor.Enter(ClientInstanceTeleportLock);
3129  
3130 // Add the group to the list.
3131 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3132 wasKeyValueEscape(new Dictionary<string, string>
3133 {
3134 {"command", "setestatelist"},
3135 {"group", vassalConfiguration.Group},
3136 {"password", vassalConfiguration.Password},
3137 {"type", selectedEstateListType},
3138 {"action", "add"},
3139 {"target", target}
3140 }), vassalConfiguration.DataTimeout);
3141  
3142 if (string.IsNullOrEmpty(result))
3143 throw new Exception("Error communicating with Corrade");
3144  
3145 bool success;
3146 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3147 throw new Exception("No success status could be retrieved");
3148  
3149 if (!success)
3150 throw new Exception("Unable to add group");
3151  
3152 // Retrieve the estate list for updates.
3153 result = wasPOST(vassalConfiguration.HTTPServerURL,
3154 wasKeyValueEscape(new Dictionary<string, string>
3155 {
3156 {"command", "getestatelist"},
3157 {"group", vassalConfiguration.Group},
3158 {"password", vassalConfiguration.Password},
3159 {"type", selectedEstateListType}
3160 }), vassalConfiguration.DataTimeout);
3161  
3162 if (string.IsNullOrEmpty(result))
3163 throw new Exception("Error communicating with Corrade.");
3164  
3165 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3166 throw new Exception("No success status could be retrieved.");
3167  
3168 if (!success)
3169 throw new Exception("Could not retrieve estate list.");
3170  
3171 vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
3172 foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
3173 .Where(x => !string.IsNullOrEmpty(x))
3174 .Select((x, i) => new {Index = i, Value = x})
3175 .GroupBy(x => x.Index/2)
3176 .Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
3177 {
3178 vassalForm.Invoke(
3179 (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
3180 }
3181 }
3182 catch (Exception ex)
3183 {
3184 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target; }));
3185 }
3186 finally
3187 {
3188 Monitor.Exit(ClientInstanceTeleportLock);
3189 // Enable teleports and enable button.
3190 vassalForm.Invoke((MethodInvoker) (() =>
3191 {
3192 RegionTeleportGroup.Enabled = true;
3193 EstateListsGroupsGroup.Enabled = true;
3194 }));
3195 }
3196 })
3197 {IsBackground = true}.Start();
3198 }
3199  
3200 private void RequestRegionDebugApply(object sender, EventArgs e)
3201 {
3202 // Block teleports and disable button.
3203 vassalForm.Invoke((MethodInvoker) (() =>
3204 {
3205 RegionTeleportGroup.Enabled = false;
3206 ApplyRegionDebugButton.Enabled = false;
3207 }));
3208  
3209 new Thread(() =>
3210 {
3211 try
3212 {
3213 Monitor.Enter(ClientInstanceTeleportLock);
3214  
3215 bool scripts = false;
3216 bool collisons = false;
3217 bool physics = false;
3218 vassalForm.Invoke((MethodInvoker) (() =>
3219 {
3220 scripts = RegionDebugScriptsBox.Checked;
3221 collisons = RegionDebugCollisionsBox.Checked;
3222 physics = RegionDebugPhysicsBox.Checked;
3223 }));
3224  
3225 // Set the debug settings.
3226 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3227 wasKeyValueEscape(new Dictionary<string, string>
3228 {
3229 {"command", "setregiondebug"},
3230 {"group", vassalConfiguration.Group},
3231 {"password", vassalConfiguration.Password},
3232 {"scripts", scripts.ToString()},
3233 {"collisions", collisons.ToString()},
3234 {"physics", physics.ToString()}
3235 }), vassalConfiguration.DataTimeout);
3236  
3237 if (string.IsNullOrEmpty(result))
3238 throw new Exception("Error communicating with Corrade");
3239  
3240 bool success;
3241 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3242 throw new Exception("No success status could be retrieved");
3243  
3244 if (!success)
3245 throw new Exception("Unable to set region debug");
3246 }
3247 catch (Exception ex)
3248 {
3249 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
3250 }
3251 finally
3252 {
3253 Monitor.Exit(ClientInstanceTeleportLock);
3254 }
3255  
3256 // Block teleports and disable button.
3257 vassalForm.Invoke((MethodInvoker) (() =>
3258 {
3259 RegionTeleportGroup.Enabled = true;
3260 ApplyRegionDebugButton.Enabled = true;
3261 }));
3262 })
3263 {IsBackground = true}.Start();
3264 }
3265  
3266 private void RequestApplyRegionInfo(object sender, EventArgs e)
3267 {
3268 // Block teleports and disable button.
3269 vassalForm.Invoke((MethodInvoker) (() =>
3270 {
3271 RegionTeleportGroup.Enabled = false;
3272 ApplyRegionInfoButton.Enabled = false;
3273 }));
3274  
3275 new Thread(() =>
3276 {
3277 try
3278 {
3279 Monitor.Enter(ClientInstanceTeleportLock);
3280  
3281 bool terraform = false;
3282 bool fly = false;
3283 bool damage = false;
3284 bool resell = false;
3285 bool push = false;
3286 bool parcel = false;
3287 bool mature = false;
3288 uint agentLimit = 20;
3289 double objectBonus = 2.0;
3290  
3291 bool run = false;
3292  
3293 vassalForm.Invoke((MethodInvoker) (() =>
3294 {
3295 terraform = RegionInfoTerraformBox.Checked;
3296 fly = RegionInfoFlyBox.Checked;
3297 damage = RegionInfoDamageBox.Checked;
3298 resell = RegioninfoResellBox.Checked;
3299 push = RegionInfoPushBox.Checked;
3300 parcel = RegionInfoParcelBox.Checked;
3301 mature = RegionInfoMatureBox.Checked;
3302 switch (!uint.TryParse(RegionInfoAgentLimitBox.Text, out agentLimit))
3303 {
3304 case true:
3305 RegionInfoAgentLimitBox.BackColor = Color.MistyRose;
3306 return;
3307 default:
3308 RegionInfoAgentLimitBox.BackColor = Color.Empty;
3309 run = true;
3310 break;
3311 }
3312 switch (!double.TryParse(RegionInfoObjectBonusBox.Text, out objectBonus))
3313 {
3314 case true:
3315 RegionInfoObjectBonusBox.BackColor = Color.MistyRose;
3316 return;
3317 default:
3318 RegionInfoAgentLimitBox.BackColor = Color.Empty;
3319 break;
3320 }
3321  
3322 run = true;
3323 }));
3324  
3325 if (!run) return;
3326  
3327 // Set the debug settings.
3328 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3329 wasKeyValueEscape(new Dictionary<string, string>
3330 {
3331 {"command", "setregioninfo"},
3332 {"group", vassalConfiguration.Group},
3333 {"password", vassalConfiguration.Password},
3334 {"terraform", terraform.ToString()},
3335 {"fly", fly.ToString()},
3336 {"damage", damage.ToString()},
3337 {"resell", resell.ToString()},
3338 {"push", push.ToString()},
3339 {"parcel", parcel.ToString()},
3340 {"mature", mature.ToString()},
3341 {"limit", agentLimit.ToString(Utils.EnUsCulture)},
3342 {"bonus", objectBonus.ToString(Utils.EnUsCulture)}
3343 }), vassalConfiguration.DataTimeout);
3344  
3345 if (string.IsNullOrEmpty(result))
3346 throw new Exception("Error communicating with Corrade");
3347  
3348 bool success;
3349 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3350 throw new Exception("No success status could be retrieved");
3351  
3352 if (!success)
3353 throw new Exception("Unable to set region info");
3354 }
3355 catch (Exception ex)
3356 {
3357 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
3358 }
3359 finally
3360 {
3361 Monitor.Exit(ClientInstanceTeleportLock);
3362 }
3363  
3364 // Block teleports and disable button.
3365 vassalForm.Invoke((MethodInvoker) (() =>
3366 {
3367 RegionTeleportGroup.Enabled = true;
3368 ApplyRegionInfoButton.Enabled = true;
3369 }));
3370 })
3371 {IsBackground = true}.Start();
3372 }
3373  
3374 private void RequestEstateTexturesApply(object sender, EventArgs e)
3375 {
3376 List<UUID> groundTextureUUIDs = new List<UUID>();
3377 vassalForm.Invoke((MethodInvoker) (() =>
3378 {
3379 UUID textureUUID;
3380 switch (!UUID.TryParse(RegionTexturesLowUUIDApplyBox.Text, out textureUUID))
3381 {
3382 case true:
3383 RegionTexturesLowUUIDApplyBox.BackColor = Color.MistyRose;
3384 return;
3385 default:
3386 RegionTexturesLowUUIDApplyBox.BackColor = Color.Empty;
3387 break;
3388 }
3389 groundTextureUUIDs.Add(textureUUID);
3390  
3391 switch (!UUID.TryParse(RegionTexturesMiddleLowUUIDApplyBox.Text, out textureUUID))
3392 {
3393 case true:
3394 RegionTexturesMiddleLowUUIDApplyBox.BackColor = Color.MistyRose;
3395 return;
3396 default:
3397 RegionTexturesMiddleLowUUIDApplyBox.BackColor = Color.Empty;
3398 break;
3399 }
3400 groundTextureUUIDs.Add(textureUUID);
3401  
3402 switch (!UUID.TryParse(RegionTexturesMiddleHighUUIDApplyBox.Text, out textureUUID))
3403 {
3404 case true:
3405 RegionTexturesMiddleHighUUIDApplyBox.BackColor = Color.MistyRose;
3406 return;
3407 default:
3408 RegionTexturesMiddleHighUUIDApplyBox.BackColor = Color.Empty;
3409 break;
3410 }
3411 groundTextureUUIDs.Add(textureUUID);
3412  
3413 switch (!UUID.TryParse(RegionTexturesHighUUIDApplyBox.Text, out textureUUID))
3414 {
3415 case true:
3416 RegionTexturesHighUUIDApplyBox.BackColor = Color.MistyRose;
3417 return;
3418 default:
3419 RegionTexturesHighUUIDApplyBox.BackColor = Color.Empty;
3420 break;
3421 }
3422 groundTextureUUIDs.Add(textureUUID);
3423 }));
3424  
3425 if (!groundTextureUUIDs.Count.Equals(4)) return;
3426  
3427 // Block teleports and disable button.
3428 vassalForm.Invoke((MethodInvoker) (() =>
3429 {
3430 RegionTeleportGroup.Enabled = false;
3431 GroundTexturesGroup.Enabled = false;
3432 }));
3433  
3434 new Thread(() =>
3435 {
3436 try
3437 {
3438 Monitor.Enter(ClientInstanceTeleportLock);
3439  
3440 // Set the debug settings.
3441 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3442 wasKeyValueEscape(new Dictionary<string, string>
3443 {
3444 {"command", "setregionterraintextures"},
3445 {"group", vassalConfiguration.Group},
3446 {"password", vassalConfiguration.Password},
3447 {"data", wasEnumerableToCSV(groundTextureUUIDs.Select(o => o.ToString()))}
3448 }), vassalConfiguration.DataTimeout);
3449  
3450 if (string.IsNullOrEmpty(result))
3451 throw new Exception("Error communicating with Corrade");
3452  
3453 bool success;
3454 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3455 throw new Exception("No success status could be retrieved");
3456  
3457 if (!success)
3458 throw new Exception("Unable to apply estate ground textures");
3459 }
3460 catch (Exception ex)
3461 {
3462 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
3463 }
3464 finally
3465 {
3466 Monitor.Exit(ClientInstanceTeleportLock);
3467 }
3468  
3469 // Block teleports and disable button.
3470 vassalForm.Invoke((MethodInvoker) (() =>
3471 {
3472 RegionTeleportGroup.Enabled = true;
3473 GroundTexturesGroup.Enabled = true;
3474 }));
3475 })
3476 {IsBackground = true};
3477 }
3478  
3479 private void RequestDownloadRegionTexture(object sender, EventArgs e)
3480 {
3481 string textureName = string.Empty;
3482 UUID textureUUID = UUID.Zero;
3483 bool run = false;
3484 vassalForm.Invoke((MethodInvoker) (() =>
3485 {
3486 Button button = sender as Button;
3487 if (button == null)
3488 {
3489 run = false;
3490 return;
3491 }
3492 textureName = button.Tag.ToString();
3493 switch (textureName)
3494 {
3495 case "Low":
3496 if (!UUID.TryParse(RegionTexturesLowUUIDBox.Text, out textureUUID))
3497 {
3498 run = false;
3499 return;
3500 }
3501 goto case "MiddleLow";
3502 case "MiddleLow":
3503 if (!UUID.TryParse(RegionTexturesMiddleLowUUIDBox.Text, out textureUUID))
3504 {
3505 run = false;
3506 return;
3507 }
3508 goto case "MiddleHigh";
3509 case "MiddleHigh":
3510 if (!UUID.TryParse(RegionTexturesMiddleHighUUIDBox.Text, out textureUUID))
3511 {
3512 run = false;
3513 return;
3514 }
3515 goto case "High";
3516 case "High":
3517 if (!UUID.TryParse(RegionTexturesHighUUIDBox.Text, out textureUUID))
3518 {
3519 run = false;
3520 return;
3521 }
3522 run = true;
3523 break;
3524 }
3525 }));
3526  
3527 if (!run) return;
3528  
3529 // Block teleports and disable button.
3530 vassalForm.Invoke((MethodInvoker) (() =>
3531 {
3532 RegionTeleportGroup.Enabled = false;
3533 GroundTexturesGroup.Enabled = false;
3534 }));
3535  
3536 new Thread(() =>
3537 {
3538 try
3539 {
3540 Monitor.Enter(ClientInstanceTeleportLock);
3541  
3542 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3543 wasKeyValueEscape(new Dictionary<string, string>
3544 {
3545 {"command", "download"},
3546 {"group", vassalConfiguration.Group},
3547 {"password", vassalConfiguration.Password},
3548 {"item", textureUUID.ToString()},
3549 {"type", "Texture"},
3550 {"format", "Png"}
3551 }), vassalConfiguration.DataTimeout);
3552  
3553 if (string.IsNullOrEmpty(result))
3554 throw new Exception("Error communicating with Corrade");
3555  
3556 bool success;
3557 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3558 throw new Exception("No success status could be retrieved");
3559  
3560 byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
3561 Image mapImage;
3562 using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
3563 {
3564 mapImage = Image.FromStream(memoryStream);
3565 }
3566  
3567 vassalForm.BeginInvoke((MethodInvoker) (() =>
3568 {
3569 switch (vassalForm.SavePNGFileDialog.ShowDialog())
3570 {
3571 case DialogResult.OK:
3572 string file = vassalForm.SavePNGFileDialog.FileName;
3573 new Thread(() =>
3574 {
3575 vassalForm.BeginInvoke((MethodInvoker) (() =>
3576 {
3577 try
3578 {
3579 vassalForm.StatusText.Text = @"saving texture...";
3580 vassalForm.StatusProgress.Value = 0;
3581  
3582 mapImage.Save(file, ImageFormat.Png);
3583  
3584 vassalForm.StatusText.Text = @"texture saved";
3585 vassalForm.StatusProgress.Value = 100;
3586 }
3587 catch (Exception ex)
3588 {
3589 vassalForm.StatusText.Text = ex.Message;
3590 }
3591 finally
3592 {
3593 mapImage.Dispose();
3594 }
3595 }));
3596 })
3597 {IsBackground = true}.Start();
3598 break;
3599 }
3600 }));
3601 }
3602 catch (Exception ex)
3603 {
3604 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
3605 }
3606 finally
3607 {
3608 Monitor.Exit(ClientInstanceTeleportLock);
3609 }
3610  
3611 // Block teleports and disable button.
3612 vassalForm.Invoke((MethodInvoker) (() =>
3613 {
3614 RegionTeleportGroup.Enabled = true;
3615 GroundTexturesGroup.Enabled = true;
3616 }));
3617 })
3618 {IsBackground = true}.Start();
3619 }
3620  
3621 private void RequestEstateListsAddGroupsFromCSV(object sender, EventArgs e)
3622 {
3623 // Get the estate list type.
3624 string selectedEstateListType = string.Empty;
3625 bool queryEstateList = false;
3626 vassalForm.Invoke((MethodInvoker) (() =>
3627 {
3628 if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
3629 selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
3630 switch (
3631 !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
3632 {
3633 case true:
3634 queryEstateList = true;
3635 break;
3636 default:
3637 queryEstateList = false;
3638 break;
3639 }
3640 }));
3641  
3642 // If not estate list type is selected then return.
3643 if (!queryEstateList) return;
3644  
3645 Queue<KeyValuePair<string, UUID>> targets = new Queue<KeyValuePair<string, UUID>>();
3646  
3647 vassalForm.Invoke((MethodInvoker) (() =>
3648 {
3649 switch (vassalForm.LoadCSVFile.ShowDialog())
3650 {
3651 case DialogResult.OK:
3652 string file = vassalForm.LoadCSVFile.FileName;
3653 try
3654 {
3655 vassalForm.StatusText.Text = @"loading group list...";
3656 vassalForm.StatusProgress.Value = 0;
3657  
3658 // import groups
3659 UUID targetUUID;
3660 foreach (KeyValuePair<string, UUID> target in
3661 File.ReadAllLines(file)
3662 .AsParallel()
3663 .Select(o => new List<string>(wasCSVToEnumerable(o)))
3664 .Where(o => o.Count == 2)
3665 .ToDictionary(o => o.First(),
3666 p =>
3667 UUID.TryParse(p.Last(), out targetUUID)
3668 ? targetUUID
3669 : UUID.Zero))
3670 {
3671 targets.Enqueue(target);
3672 }
3673  
3674 vassalForm.StatusText.Text = @"group list loaded";
3675 vassalForm.StatusProgress.Value = 100;
3676 }
3677 catch (Exception ex)
3678 {
3679 vassalForm.StatusText.Text = ex.Message;
3680 }
3681 break;
3682 }
3683 }));
3684  
3685 if (targets.Count.Equals(0)) return;
3686 int initialQueueSize = targets.Count;
3687  
3688 // Block teleports and disable button.
3689 vassalForm.Invoke((MethodInvoker) (() =>
3690 {
3691 RegionTeleportGroup.Enabled = false;
3692 EstateListsGroupsGroup.Enabled = false;
3693 }));
3694  
3695 new Thread(() =>
3696 {
3697 try
3698 {
3699 Monitor.Enter(ClientInstanceTeleportLock);
3700  
3701 do
3702 {
3703 KeyValuePair<string, UUID> target = targets.Dequeue();
3704  
3705 vassalForm.Invoke((MethodInvoker) (() =>
3706 {
3707 StatusText.Text = @"Adding to estate list: " + target.Key;
3708 vassalForm.StatusProgress.Value =
3709 Math.Min((int) (100d*Math.Abs(targets.Count - initialQueueSize)/initialQueueSize), 100);
3710 }));
3711  
3712 // Skip any items that already exist.
3713 bool run = false;
3714 vassalForm.Invoke((MethodInvoker) (() =>
3715 {
3716 run =
3717 !EstateListGridView.Rows.AsParallel()
3718 .Cast<DataGridViewRow>()
3719 .Any(o => o.Cells["EstateListUUID"].Value.ToString().Equals(target.Value.ToString()));
3720 }));
3721 if (!run) continue;
3722  
3723 // Skip broken UUIDs.
3724 if (target.Value.Equals(UUID.Zero)) continue;
3725  
3726 try
3727 {
3728 // Add the group to the list.
3729 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3730 wasKeyValueEscape(new Dictionary<string, string>
3731 {
3732 {"command", "setestatelist"},
3733 {"group", vassalConfiguration.Group},
3734 {"password", vassalConfiguration.Password},
3735 {"type", selectedEstateListType},
3736 {"action", "add"},
3737 {"target", target.Value.ToString()}
3738 }), vassalConfiguration.DataTimeout);
3739  
3740 if (string.IsNullOrEmpty(result))
3741 throw new Exception("Error communicating with Corrade");
3742  
3743 bool success;
3744 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3745 throw new Exception("No success status could be retrieved");
3746  
3747 if (!success)
3748 throw new Exception("Unable to add group");
3749 }
3750 catch (Exception ex)
3751 {
3752 vassalForm.Invoke(
3753 (MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target.Value; }));
3754 }
3755 } while (!targets.Count.Equals(0));
3756  
3757 // Retrieve the estate list.
3758 try
3759 {
3760 // Retrieve the estate list for updates.
3761 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3762 wasKeyValueEscape(new Dictionary<string, string>
3763 {
3764 {"command", "getestatelist"},
3765 {"group", vassalConfiguration.Group},
3766 {"password", vassalConfiguration.Password},
3767 {"type", selectedEstateListType}
3768 }), vassalConfiguration.DataTimeout);
3769  
3770 if (string.IsNullOrEmpty(result))
3771 throw new Exception("Error communicating with Corrade.");
3772  
3773 bool success;
3774 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3775 throw new Exception("No success status could be retrieved.");
3776  
3777 if (!success)
3778 throw new Exception("Could not retrieve estate list.");
3779  
3780 vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
3781 foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
3782 .Where(x => !string.IsNullOrEmpty(x))
3783 .Select((x, i) => new {Index = i, Value = x})
3784 .GroupBy(x => x.Index/2)
3785 .Select(x => x.Select(v => v.Value).ToList()))
3786 {
3787 vassalForm.BeginInvoke(
3788 (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
3789 }
3790 }
3791 catch (Exception ex)
3792 {
3793 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
3794 }
3795 }
3796 catch (Exception ex)
3797 {
3798 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
3799 }
3800 finally
3801 {
3802 Monitor.Exit(ClientInstanceTeleportLock);
3803 // Enable teleports and enable button.
3804 vassalForm.Invoke((MethodInvoker) (() =>
3805 {
3806 RegionTeleportGroup.Enabled = true;
3807 EstateListsGroupsGroup.Enabled = true;
3808 }));
3809 }
3810 })
3811 {IsBackground = true}.Start();
3812 }
3813  
3814 private void RequestEstateListsAddResidentsFromCSV(object sender, EventArgs e)
3815 {
3816 // Get the estate list type.
3817 string selectedEstateListType = string.Empty;
3818 bool queryEstateList = false;
3819 vassalForm.Invoke((MethodInvoker) (() =>
3820 {
3821 if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
3822 selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
3823 switch (
3824 !string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
3825 {
3826 case true:
3827 queryEstateList = true;
3828 break;
3829 default:
3830 queryEstateList = false;
3831 break;
3832 }
3833 }));
3834  
3835 // If not estate list type is selected then return.
3836 if (!queryEstateList) return;
3837  
3838 Queue<KeyValuePair<string, UUID>> targets = new Queue<KeyValuePair<string, UUID>>();
3839  
3840 vassalForm.Invoke((MethodInvoker) (() =>
3841 {
3842 switch (vassalForm.LoadCSVFile.ShowDialog())
3843 {
3844 case DialogResult.OK:
3845 string file = vassalForm.LoadCSVFile.FileName;
3846 try
3847 {
3848 vassalForm.StatusText.Text = @"loading residents list...";
3849 vassalForm.StatusProgress.Value = 0;
3850  
3851 // import groups
3852 UUID targetUUID;
3853 foreach (KeyValuePair<string, UUID> target in
3854 File.ReadAllLines(file)
3855 .AsParallel()
3856 .Select(o => new List<string>(wasCSVToEnumerable(o)))
3857 .Where(o => o.Count == 2)
3858 .ToDictionary(o => o.First(),
3859 p =>
3860 UUID.TryParse(p.Last(), out targetUUID)
3861 ? targetUUID
3862 : UUID.Zero))
3863 {
3864 targets.Enqueue(target);
3865 }
3866  
3867 vassalForm.StatusText.Text = @"residents list loaded";
3868 vassalForm.StatusProgress.Value = 100;
3869 }
3870 catch (Exception ex)
3871 {
3872 vassalForm.StatusText.Text = ex.Message;
3873 }
3874 break;
3875 }
3876 }));
3877  
3878 if (targets.Count.Equals(0)) return;
3879 int initialQueueSize = targets.Count;
3880  
3881 // Block teleports and disable button.
3882 vassalForm.Invoke((MethodInvoker) (() =>
3883 {
3884 RegionTeleportGroup.Enabled = false;
3885 EstateListsResidentsGroup.Enabled = false;
3886 }));
3887  
3888 new Thread(() =>
3889 {
3890 try
3891 {
3892 Monitor.Enter(ClientInstanceTeleportLock);
3893  
3894 do
3895 {
3896 KeyValuePair<string, UUID> target = targets.Dequeue();
3897  
3898 vassalForm.Invoke((MethodInvoker) (() =>
3899 {
3900 StatusText.Text = @"Adding to estate list: " + target.Key;
3901 vassalForm.StatusProgress.Value =
3902 Math.Min((int) (100d*Math.Abs(targets.Count - initialQueueSize)/initialQueueSize), 100);
3903 }));
3904  
3905 // Skip any items that already exist.
3906 bool run = false;
3907 vassalForm.Invoke((MethodInvoker) (() =>
3908 {
3909 run =
3910 !EstateListGridView.Rows.AsParallel()
3911 .Cast<DataGridViewRow>()
3912 .Any(o => o.Cells["EstateListUUID"].Value.ToString().Equals(target.Value.ToString()));
3913 }));
3914 if (!run) continue;
3915  
3916 // Skip broken UUIDs.
3917 if (target.Value.Equals(UUID.Zero)) continue;
3918  
3919 try
3920 {
3921 // Add the group to the list.
3922 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3923 wasKeyValueEscape(new Dictionary<string, string>
3924 {
3925 {"command", "setestatelist"},
3926 {"group", vassalConfiguration.Group},
3927 {"password", vassalConfiguration.Password},
3928 {"type", selectedEstateListType},
3929 {"action", "add"},
3930 {"agent", target.Value.ToString()}
3931 }), vassalConfiguration.DataTimeout);
3932  
3933 if (string.IsNullOrEmpty(result))
3934 throw new Exception("Error communicating with Corrade");
3935  
3936 bool success;
3937 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3938 throw new Exception("No success status could be retrieved");
3939  
3940 if (!success)
3941 throw new Exception("Unable to add resident");
3942 }
3943 catch (Exception ex)
3944 {
3945 vassalForm.Invoke(
3946 (MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target.Value; }));
3947 }
3948 } while (!targets.Count.Equals(0));
3949  
3950 // Retrieve the estate list.
3951 try
3952 {
3953 // Retrieve the estate list for updates.
3954 string result = wasPOST(vassalConfiguration.HTTPServerURL,
3955 wasKeyValueEscape(new Dictionary<string, string>
3956 {
3957 {"command", "getestatelist"},
3958 {"group", vassalConfiguration.Group},
3959 {"password", vassalConfiguration.Password},
3960 {"type", selectedEstateListType}
3961 }), vassalConfiguration.DataTimeout);
3962  
3963 if (string.IsNullOrEmpty(result))
3964 throw new Exception("Error communicating with Corrade.");
3965  
3966 bool success;
3967 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
3968 throw new Exception("No success status could be retrieved.");
3969  
3970 if (!success)
3971 throw new Exception("Could not retrieve estate list.");
3972  
3973 vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
3974 foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
3975 .Where(x => !string.IsNullOrEmpty(x))
3976 .Select((x, i) => new {Index = i, Value = x})
3977 .GroupBy(x => x.Index/2)
3978 .Select(x => x.Select(v => v.Value).ToList()))
3979 {
3980 vassalForm.BeginInvoke(
3981 (MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
3982 }
3983 }
3984 catch (Exception ex)
3985 {
3986 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
3987 }
3988 }
3989 catch (Exception ex)
3990 {
3991 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
3992 }
3993 finally
3994 {
3995 Monitor.Exit(ClientInstanceTeleportLock);
3996 // Enable teleports and enable button.
3997 vassalForm.Invoke((MethodInvoker) (() =>
3998 {
3999 RegionTeleportGroup.Enabled = true;
4000 EstateListsResidentsGroup.Enabled = true;
4001 }));
4002 }
4003 })
4004 {IsBackground = true}.Start();
4005 }
4006  
4007 private void RequestExportEstateList(object sender, EventArgs e)
4008 {
4009 vassalForm.BeginInvoke((MethodInvoker) (() =>
4010 {
4011 switch (vassalForm.ExportCSVDialog.ShowDialog())
4012 {
4013 case DialogResult.OK:
4014 string file = vassalForm.ExportCSVDialog.FileName;
4015 new Thread(() =>
4016 {
4017 vassalForm.BeginInvoke((MethodInvoker) (() =>
4018 {
4019 try
4020 {
4021 vassalForm.StatusText.Text = @"exporting...";
4022 vassalForm.StatusProgress.Value = 0;
4023  
4024 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
4025 {
4026 foreach (DataGridViewRow estateListRow in EstateListGridView.Rows)
4027 {
4028 streamWriter.WriteLine(wasEnumerableToCSV(new[]
4029 {
4030 estateListRow.Cells["EstateListName"].Value.ToString(),
4031 estateListRow.Cells["EstateListUUID"].Value.ToString()
4032 }));
4033 }
4034 }
4035  
4036 vassalForm.StatusText.Text = @"exported";
4037 vassalForm.StatusProgress.Value = 100;
4038 }
4039 catch (Exception ex)
4040 {
4041 vassalForm.StatusText.Text = ex.Message;
4042 }
4043 }));
4044 })
4045 {IsBackground = true}.Start();
4046 break;
4047 }
4048 }));
4049 }
4050  
12 zed 4051 private void RequestTeleportHome(object sender, EventArgs e)
4052 {
4053 // Block teleports and disable button.
4054 vassalForm.Invoke((MethodInvoker) (() =>
4055 {
4056 ResidentListTeleportHomeGroup.Enabled = false;
4057 ResidentListBanGroup.Enabled = false;
4058 RegionTeleportGroup.Enabled = false;
4059 }));
4060  
4061 // Enqueue all the agents to teleport home.
4062 Queue<UUID> agentsQueue = new Queue<UUID>();
4063 vassalForm.Invoke((MethodInvoker) (() =>
4064 {
4065 foreach (
4066 DataGridViewRow residentListRow in
4067 ResidentListGridView.Rows.AsParallel()
4068 .Cast<DataGridViewRow>()
4069 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
4070 {
4071 UUID agentUUID;
4072 if (!UUID.TryParse(residentListRow.Cells["ResidentListUUID"].Value.ToString(), out agentUUID))
4073 continue;
4074 agentsQueue.Enqueue(agentUUID);
4075 }
4076 }));
4077  
4078 // If no rows were selected, enable teleports, the return button and return.
4079 if (agentsQueue.Count.Equals(0))
4080 {
4081 vassalForm.Invoke((MethodInvoker) (() =>
4082 {
4083 ResidentListBanGroup.Enabled = true;
4084 RegionTeleportGroup.Enabled = true;
4085 }));
4086 return;
4087 }
4088  
4089 new Thread(() =>
4090 {
4091 Monitor.Enter(ClientInstanceTeleportLock);
4092 try
4093 {
4094 do
4095 {
4096 // Dequeue the first object.
4097 UUID agentUUID = agentsQueue.Dequeue();
4098 DataGridViewRow currentDataGridViewRow = null;
4099 vassalForm.Invoke((MethodInvoker) (() =>
4100 {
4101 currentDataGridViewRow = vassalForm.ResidentListGridView.Rows.AsParallel()
4102 .Cast<DataGridViewRow>()
4103 .FirstOrDefault(
4104 o =>
4105 o.Cells["ResidentListUUID"].Value.ToString()
4106 .Equals(agentUUID.ToString(), StringComparison.OrdinalIgnoreCase));
4107 }));
4108  
4109 if (currentDataGridViewRow == null) continue;
4110  
4111 try
4112 {
4113 // Teleport the user home.
4114 string result = wasPOST(vassalConfiguration.HTTPServerURL,
4115 wasKeyValueEscape(new Dictionary<string, string>
4116 {
4117 {"command", "estateteleportusershome"},
4118 {"group", vassalConfiguration.Group},
4119 {"password", vassalConfiguration.Password},
4120 {"avatars", agentUUID.ToString()}
4121 }), vassalConfiguration.DataTimeout);
4122  
4123 if (string.IsNullOrEmpty(result))
4124 throw new Exception("Error communicating with Corrade.");
4125  
4126 bool success;
4127 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
4128 throw new Exception("No success status could be retrieved.");
4129  
4130 switch (success)
4131 {
4132 case true:
4133 vassalForm.Invoke((MethodInvoker) (() =>
4134 {
4135 vassalForm.StatusText.Text = @"Resident teleported home.";
4136 currentDataGridViewRow.Selected = false;
4137 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
4138 foreach (
4139 DataGridViewCell cell in
4140 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
4141 {
4142 cell.ToolTipText = @"Resident teleported home.";
4143 }
4144 }));
4145 break;
4146 default:
4147 throw new Exception("Unable to teleport resident home.");
4148 }
4149 }
4150 catch (Exception ex)
4151 {
4152 vassalForm.Invoke((MethodInvoker) (() =>
4153 {
4154 vassalForm.StatusText.Text = ex.Message;
4155 currentDataGridViewRow.Selected = false;
4156 currentDataGridViewRow.DefaultCellStyle.BackColor = Color.LightPink;
4157 foreach (
4158 DataGridViewCell cell in
4159 currentDataGridViewRow.Cells.AsParallel().Cast<DataGridViewCell>())
4160 {
4161 cell.ToolTipText = ex.Message;
4162 }
4163 }));
4164 }
4165 } while (agentsQueue.Count.Equals(0));
4166 }
4167 catch (Exception)
4168 {
4169 }
4170 finally
4171 {
4172 Monitor.Exit(ClientInstanceTeleportLock);
4173 // Allow teleports and enable button.
4174 vassalForm.BeginInvoke((MethodInvoker) (() =>
4175 {
4176 ResidentListTeleportHomeGroup.Enabled = true;
4177 ResidentListBanGroup.Enabled = true;
4178 RegionTeleportGroup.Enabled = true;
4179 }));
4180 }
4181 })
4182 {IsBackground = true}.Start();
4183 }
4184  
4185 private void RequestSetVariables(object sender, EventArgs e)
4186 {
4187 // Block teleports and disable button.
4188 vassalForm.Invoke((MethodInvoker) (() =>
4189 {
4190 RegionTeleportGroup.Enabled = false;
4191 SetTerrainVariablesButton.Enabled = false;
4192 }));
4193  
4194 new Thread(() =>
4195 {
4196 try
4197 {
4198 Monitor.Enter(ClientInstanceTeleportLock);
4199  
4200 int waterHeight = 10;
4201 int terrainRaiseLimit = 100;
4202 int terrainLowerLimit = -100;
4203 bool useEstateSun = true;
4204 bool fixedSun = false;
4205 int sunPosition = 18;
4206  
4207 bool run = false;
4208  
4209 vassalForm.Invoke((MethodInvoker) (() =>
4210 {
4211 useEstateSun = TerrainToolsUseEstateSunBox.Checked;
4212 fixedSun = TerrainToolsFixedSunBox.Checked;
4213 switch (!int.TryParse(TerrainToolsWaterHeightBox.Text, out waterHeight))
4214 {
4215 case true:
4216 TerrainToolsWaterHeightBox.BackColor = Color.MistyRose;
4217 return;
4218 default:
4219 TerrainToolsWaterHeightBox.BackColor = Color.Empty;
4220 break;
4221 }
4222 switch (!int.TryParse(TerrainToolsTerrainRaiseLimitBox.Text, out terrainRaiseLimit))
4223 {
4224 case true:
4225 TerrainToolsTerrainRaiseLimitBox.BackColor = Color.MistyRose;
4226 return;
4227 default:
4228 TerrainToolsTerrainRaiseLimitBox.BackColor = Color.Empty;
4229 break;
4230 }
4231 switch (!int.TryParse(TerrainToolsTerrainLowerLimitBox.Text, out terrainLowerLimit))
4232 {
4233 case true:
4234 TerrainToolsTerrainLowerLimitBox.BackColor = Color.MistyRose;
4235 return;
4236 default:
4237 TerrainToolsTerrainLowerLimitBox.BackColor = Color.Empty;
4238 break;
4239 }
4240 switch (!int.TryParse(TerrainToolsSunPositionBox.Text, out sunPosition))
4241 {
4242 case true:
4243 TerrainToolsSunPositionBox.BackColor = Color.MistyRose;
4244 return;
4245 default:
4246 TerrainToolsSunPositionBox.BackColor = Color.Empty;
4247 break;
4248 }
4249  
4250 run = true;
4251 }));
4252  
4253 if (!run) return;
4254  
4255 // Set the terrain variables.
4256 string result = wasPOST(vassalConfiguration.HTTPServerURL,
4257 wasKeyValueEscape(new Dictionary<string, string>
4258 {
4259 {"command", "setregionterrainvariables"},
4260 {"group", vassalConfiguration.Group},
4261 {"password", vassalConfiguration.Password},
4262 {"waterheight", waterHeight.ToString()},
4263 {"terrainraiselimit", terrainRaiseLimit.ToString()},
4264 {"terrainlowerlimit", terrainLowerLimit.ToString()},
4265 {"useestatesun", useEstateSun.ToString()},
4266 {"fixedsun", fixedSun.ToString()},
4267 {"sunposition", sunPosition.ToString()}
4268 }), vassalConfiguration.DataTimeout);
4269  
4270 if (string.IsNullOrEmpty(result))
4271 throw new Exception("Error communicating with Corrade");
4272  
4273 bool success;
4274 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
4275 throw new Exception("No success status could be retrieved");
4276  
4277 if (!success)
4278 throw new Exception("Unable to set region variables");
4279 }
4280 catch (Exception ex)
4281 {
4282 vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
4283 }
4284 finally
4285 {
4286 Monitor.Exit(ClientInstanceTeleportLock);
4287 }
4288  
4289 // Block teleports and disable button.
4290 vassalForm.Invoke((MethodInvoker) (() =>
4291 {
4292 RegionTeleportGroup.Enabled = true;
4293 SetTerrainVariablesButton.Enabled = true;
4294 }));
4295 })
4296 {IsBackground = true}.Start();
4297 }
4298  
4299 private void ReconnectRequested(object sender, EventArgs e)
4300 {
4301 // Spawn a thread to check Corrade's connection status.
4302 new Thread(() =>
4303 {
4304 TcpClient tcpClient = new TcpClient();
4305 try
4306 {
4307 Uri uri = new Uri(vassalConfiguration.HTTPServerURL);
4308 tcpClient.Connect(uri.Host, uri.Port);
4309 // port open
4310 vassalForm.BeginInvoke((MethodInvoker) (() => { vassalForm.Tabs.Enabled = true; }));
4311 // set the loading spinner
4312 if (vassalForm.RegionAvatarsMap.Image == null)
4313 {
4314 Assembly thisAssembly = Assembly.GetExecutingAssembly();
4315 Stream file =
4316 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
4317 switch (file != null)
4318 {
4319 case true:
4320 vassalForm.BeginInvoke((MethodInvoker) (() =>
4321 {
4322 vassalForm.RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
4323 vassalForm.RegionAvatarsMap.Image = Image.FromStream(file);
4324 vassalForm.RegionAvatarsMap.Refresh();
4325 }));
4326 break;
4327 }
4328 }
4329 }
4330 catch (Exception)
4331 {
4332 // port closed
4333 vassalForm.BeginInvoke((MethodInvoker) (() => { vassalForm.Tabs.Enabled = false; }));
4334 }
4335 })
4336 {IsBackground = true}.Start();
4337 }
4338  
8 eva 4339 /// <summary>
4340 /// Linden constants.
4341 /// </summary>
4342 public struct LINDEN_CONSTANTS
4343 {
4344 public struct ALERTS
4345 {
4346 public const string NO_ROOM_TO_SIT_HERE = @"No room to sit here, try another spot.";
4347  
4348 public const string UNABLE_TO_SET_HOME =
4349 @"You can only set your 'Home Location' on your land or at a mainland Infohub.";
4350  
4351 public const string HOME_SET = @"Home position set.";
4352 }
4353  
4354 public struct ASSETS
4355 {
4356 public struct NOTECARD
4357 {
4358 public const string NEWLINE = "\n";
4359 public const uint MAXIMUM_BODY_LENTH = 65536;
4360 }
4361 }
4362  
4363 public struct AVATARS
4364 {
4365 public const uint SET_DISPLAY_NAME_SUCCESS = 200;
4366 public const string LASTNAME_PLACEHOLDER = @"Resident";
4367 public const uint MAXIMUM_DISPLAY_NAME_CHARACTERS = 31;
4368 public const uint MINIMUM_DISPLAY_NAME_CHARACTERS = 1;
4369 public const uint MAXIMUM_NUMBER_OF_ATTACHMENTS = 38;
4370  
4371 public struct PROFILE
4372 {
4373 public const uint SECOND_LIFE_TEXT_SIZE = 510;
4374 public const uint FIRST_LIFE_TEXT_SIZE = 253;
4375 }
4376  
4377 public struct PICKS
4378 {
4379 public const uint MAXIMUM_PICKS = 10;
4380 public const uint MAXIMUM_PICK_DESCRIPTION_SIZE = 1022;
4381 }
4382  
4383 public struct CLASSIFIEDS
4384 {
4385 public const uint MAXIMUM_CLASSIFIEDS = 100;
4386 }
4387 }
4388  
4389 public struct PRIMITIVES
4390 {
4391 public const uint MAXIMUM_NAME_SIZE = 63;
4392 public const uint MAXIMUM_DESCRIPTION_SIZE = 127;
4393 public const double MAXIMUM_REZ_HEIGHT = 4096.0;
4394 public const double MINIMUM_SIZE_X = 0.01;
4395 public const double MINIMUM_SIZE_Y = 0.01;
4396 public const double MINIMUM_SIZE_Z = 0.01;
4397 public const double MAXIMUM_SIZE_X = 64.0;
4398 public const double MAXIMUM_SIZE_Y = 64.0;
4399 public const double MAXIMUM_SIZE_Z = 64.0;
4400 }
4401  
4402 public struct OBJECTS
4403 {
4404 public const uint MAXIMUM_PRIMITIVE_COUNT = 256;
4405 }
4406  
4407 public struct DIRECTORY
4408 {
4409 public struct EVENT
4410 {
4411 public const uint SEARCH_RESULTS_COUNT = 200;
4412 }
4413  
4414 public struct GROUP
4415 {
4416 public const uint SEARCH_RESULTS_COUNT = 100;
4417 }
4418  
4419 public struct LAND
4420 {
4421 public const uint SEARCH_RESULTS_COUNT = 100;
4422 }
4423  
4424 public struct PEOPLE
4425 {
4426 public const uint SEARCH_RESULTS_COUNT = 100;
4427 }
4428 }
4429  
4430 public struct ESTATE
4431 {
4432 public const uint REGION_RESTART_DELAY = 120;
4433 public const uint MAXIMUM_BAN_LIST_LENGTH = 500;
4434 public const uint MAXIMUM_GROUP_LIST_LENGTH = 63;
4435 public const uint MAXIMUM_USER_LIST_LENGTH = 500;
4436 public const uint MAXIMUM_MANAGER_LIST_LENGTH = 10;
4437  
4438 public struct MESSAGES
4439 {
4440 public const string REGION_RESTART_MESSAGE = @"restart";
4441 }
4442 }
4443  
4444 public struct PARCELS
4445 {
4446 public const double MAXIMUM_AUTO_RETURN_TIME = 999999;
4447 public const uint MINIMUM_AUTO_RETURN_TIME = 0;
4448 public const uint MAXIMUM_NAME_LENGTH = 63;
4449 public const uint MAXIMUM_DESCRIPTION_LENGTH = 255;
4450 }
4451  
4452 public struct GRID
4453 {
4454 public const string SECOND_LIFE = @"Second Life";
4455 public const string TIME_ZONE = @"Pacific Standard Time";
4456 }
4457  
4458 public struct CHAT
4459 {
4460 public const uint MAXIMUM_MESSAGE_LENGTH = 1024;
4461 }
4462  
4463 public struct GROUPS
4464 {
4465 public const uint MAXIMUM_NUMBER_OF_ROLES = 10;
4466 public const string EVERYONE_ROLE_NAME = @"Everyone";
4467 public const uint MAXIMUM_GROUP_NAME_LENGTH = 35;
4468 public const uint MAXIMUM_GROUP_TITLE_LENGTH = 20;
4469 }
4470  
4471 public struct NOTICES
4472 {
4473 public const uint MAXIMUM_NOTICE_MESSAGE_LENGTH = 512;
4474 }
4475  
4476 public struct LSL
4477 {
4478 public const string CSV_DELIMITER = @", ";
4479 public const float SENSOR_RANGE = 96;
4480 public const string DATE_TIME_STAMP = @"yyy-MM-ddTHH:mm:ss.ffffffZ";
4481 }
4482  
4483 public struct REGION
4484 {
4485 public const float TELEPORT_MINIMUM_DISTANCE = 1;
4486 public const float DEFAULT_AGENT_LIMIT = 40;
4487 public const float DEFAULT_OBJECT_BONUS = 1;
4488 public const bool DEFAULT_FIXED_SUN = false;
4489 public const float DEFAULT_TERRAIN_LOWER_LIMIT = -4;
4490 public const float DEFAULT_TERRAIN_RAISE_LIMIT = 4;
4491 public const bool DEFAULT_USE_ESTATE_SUN = true;
4492 public const float DEFAULT_WATER_HEIGHT = 20;
4493 public const float SUNRISE = 6;
4494 }
4495  
4496 public struct VIEWER
4497 {
4498 public const float MAXIMUM_DRAW_DISTANCE = 4096;
4499 }
4500  
4501 public struct TELEPORTS
4502 {
4503 public struct THROTTLE
4504 {
4505 public const uint MAX_TELEPORTS = 10;
4506 public const uint GRACE_SECONDS = 15;
4507 }
4508 }
4509 }
4510  
4511 /// <summary>
4512 /// Constants used by Corrade.
4513 /// </summary>
4514 public struct VASSAL_CONSTANTS
4515 {
4516 /// <summary>
4517 /// Copyright.
4518 /// </summary>
4519 public const string COPYRIGHT = @"(c) Copyright 2013 Wizardry and Steamworks";
4520  
4521 public const string WIZARDRY_AND_STEAMWORKS = @"Wizardry and Steamworks";
4522 public const string VASSAL = @"Vassal";
4523 public const string WIZARDRY_AND_STEAMWORKS_WEBSITE = @"http://grimore.org";
4524  
4525 /// <summary>
4526 /// Vassal version.
4527 /// </summary>
4528 public static readonly string VASSAL_VERSION = Assembly.GetEntryAssembly().GetName().Version.ToString();
4529  
4530 /// <summary>
4531 /// Corrade user agent.
4532 /// </summary>
4533 public static readonly string USER_AGENT =
4534 $"{VASSAL}/{VASSAL_VERSION} ({WIZARDRY_AND_STEAMWORKS_WEBSITE})";
4535  
4536 /// <summary>
4537 /// Vassal compile date.
4538 /// </summary>
4539 public static readonly string VASSAL_COMPILE_DATE = new DateTime(2000, 1, 1).Add(new TimeSpan(
4540 TimeSpan.TicksPerDay*Assembly.GetEntryAssembly().GetName().Version.Build + // days since 1 January 2000
4541 TimeSpan.TicksPerSecond*2*Assembly.GetEntryAssembly().GetName().Version.Revision)).ToLongDateString();
4542  
4543 /// <summary>
4544 /// Vassal configuration file.
4545 /// </summary>
4546 public static readonly string VASSAL_CONFIGURATION_FILE = @"Vassal.ini";
4547  
4548 /// <summary>
4549 /// Vassal regions file.
4550 /// </summary>
4551 public static readonly string VASSAL_REGIONS = @"Regions.csv";
4552  
4553 /// <summary>
4554 /// Conten-types that Corrade can send and receive.
4555 /// </summary>
4556 public struct CONTENT_TYPE
4557 {
4558 public const string TEXT_PLAIN = @"text/plain";
4559 public const string WWW_FORM_URLENCODED = @"application/x-www-form-urlencoded";
4560 }
4561 }
4562  
4563 #region CRYPTOGRAPHY
4564  
4565 ///////////////////////////////////////////////////////////////////////////
4566 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4567 ///////////////////////////////////////////////////////////////////////////
4568 /// <summary>
4569 /// Gets a sub-array from an array.
4570 /// </summary>
4571 /// <typeparam name="T">the array type</typeparam>
4572 /// <param name="data">the array</param>
4573 /// <param name="start">the start index</param>
4574 /// <param name="stop">the stop index (-1 denotes the end)</param>
4575 /// <returns>the array slice between start and stop</returns>
4576 public static T[] wasGetSubArray<T>(T[] data, int start, int stop)
4577 {
4578 if (stop.Equals(-1))
4579 stop = data.Length - 1;
4580 T[] result = new T[stop - start + 1];
4581 Array.Copy(data, start, result, 0, stop - start + 1);
4582 return result;
4583 }
4584  
4585 ///////////////////////////////////////////////////////////////////////////
4586 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4587 ///////////////////////////////////////////////////////////////////////////
4588 /// <summary>
4589 /// Delete a sub-array and return the result.
4590 /// </summary>
4591 /// <typeparam name="T">the array type</typeparam>
4592 /// <param name="data">the array</param>
4593 /// <param name="start">the start index</param>
4594 /// <param name="stop">the stop index (-1 denotes the end)</param>
4595 /// <returns>the array without elements between start and stop</returns>
4596 public static T[] wasDeleteSubArray<T>(T[] data, int start, int stop)
4597 {
4598 if (stop.Equals(-1))
4599 stop = data.Length - 1;
4600 T[] result = new T[data.Length - (stop - start) - 1];
4601 Array.Copy(data, 0, result, 0, start);
4602 Array.Copy(data, stop + 1, result, start, data.Length - stop - 1);
4603 return result;
4604 }
4605  
4606 ///////////////////////////////////////////////////////////////////////////
4607 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4608 ///////////////////////////////////////////////////////////////////////////
4609 /// <summary>
4610 /// Concatenate multiple arrays.
4611 /// </summary>
4612 /// <typeparam name="T">the array type</typeparam>
4613 /// <param name="arrays">multiple arrays</param>
4614 /// <returns>a flat array with all arrays concatenated</returns>
4615 public static T[] wasConcatenateArrays<T>(params T[][] arrays)
4616 {
4617 int resultLength = 0;
4618 foreach (T[] o in arrays)
4619 {
4620 resultLength += o.Length;
4621 }
4622 T[] result = new T[resultLength];
4623 int offset = 0;
4624 for (int x = 0; x < arrays.Length; x++)
4625 {
4626 arrays[x].CopyTo(result, offset);
4627 offset += arrays[x].Length;
4628 }
4629 return result;
4630 }
4631  
4632 ///////////////////////////////////////////////////////////////////////////
4633 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4634 ///////////////////////////////////////////////////////////////////////////
4635 /// <summary>
4636 /// Permutes an array in reverse a given number of times.
4637 /// </summary>
4638 /// <typeparam name="T">the array type</typeparam>
4639 /// <param name="input">the array</param>
4640 /// <param name="times">the number of times to permute</param>
4641 /// <returns>the array with the elements permuted</returns>
4642 private static T[] wasReversePermuteArrayElements<T>(T[] input, int times)
4643 {
4644 if (times.Equals(0)) return input;
4645 T[] slice = new T[input.Length];
4646 Array.Copy(input, 1, slice, 0, input.Length - 1);
4647 Array.Copy(input, 0, slice, input.Length - 1, 1);
4648 return wasReversePermuteArrayElements(slice, --times);
4649 }
4650  
4651 ///////////////////////////////////////////////////////////////////////////
4652 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4653 ///////////////////////////////////////////////////////////////////////////
4654 /// <summary>
4655 /// Permutes an array forward a given number of times.
4656 /// </summary>
4657 /// <typeparam name="T">the array type</typeparam>
4658 /// <param name="input">the array</param>
4659 /// <param name="times">the number of times to permute</param>
4660 /// <returns>the array with the elements permuted</returns>
4661 private static T[] wasForwardPermuteArrayElements<T>(T[] input, int times)
4662 {
4663 if (times.Equals(0)) return input;
4664 T[] slice = new T[input.Length];
4665 Array.Copy(input, input.Length - 1, slice, 0, 1);
4666 Array.Copy(input, 0, slice, 1, input.Length - 1);
4667 return wasForwardPermuteArrayElements(slice, --times);
4668 }
4669  
4670 ///////////////////////////////////////////////////////////////////////////
4671 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4672 ///////////////////////////////////////////////////////////////////////////
4673 /// <summary>
4674 /// Encrypt or decrypt a message given a set of rotors, plugs and a reflector.
4675 /// </summary>
4676 /// <param name="message">the message to encyrpt or decrypt</param>
4677 /// <param name="rotors">any combination of: 1, 2, 3, 4, 5, 6, 7, 8, b, g</param>
4678 /// <param name="plugs">the letter representing the start character for the rotor</param>
4679 /// <param name="reflector">any one of: B, b, C, c</param>
4680 /// <returns>either a decrypted or encrypted string</returns>
4681 private static string wasEnigma(string message, char[] rotors, char[] plugs, char reflector)
4682 {
4683 Dictionary<char, char[]> def_rotors = new Dictionary<char, char[]>
4684 {
4685 {
4686 '1', new[]
4687 {
4688 'e', 'k', 'm', 'f', 'l',
4689 'g', 'd', 'q', 'v', 'z',
4690 'n', 't', 'o', 'w', 'y',
4691 'h', 'x', 'u', 's', 'p',
4692 'a', 'i', 'b', 'r', 'c',
4693 'j'
4694 }
4695 },
4696 {
4697 '2', new[]
4698 {
4699 'a', 'j', 'd', 'k', 's',
4700 'i', 'r', 'u', 'x', 'b',
4701 'l', 'h', 'w', 't', 'm',
4702 'c', 'q', 'g', 'z', 'n',
4703 'p', 'y', 'f', 'v', 'o',
4704 'e'
4705 }
4706 },
4707 {
4708 '3', new[]
4709 {
4710 'b', 'd', 'f', 'h', 'j',
4711 'l', 'c', 'p', 'r', 't',
4712 'x', 'v', 'z', 'n', 'y',
4713 'e', 'i', 'w', 'g', 'a',
4714 'k', 'm', 'u', 's', 'q',
4715 'o'
4716 }
4717 },
4718 {
4719 '4', new[]
4720 {
4721 'e', 's', 'o', 'v', 'p',
4722 'z', 'j', 'a', 'y', 'q',
4723 'u', 'i', 'r', 'h', 'x',
4724 'l', 'n', 'f', 't', 'g',
4725 'k', 'd', 'c', 'm', 'w',
4726 'b'
4727 }
4728 },
4729 {
4730 '5', new[]
4731 {
4732 'v', 'z', 'b', 'r', 'g',
4733 'i', 't', 'y', 'u', 'p',
4734 's', 'd', 'n', 'h', 'l',
4735 'x', 'a', 'w', 'm', 'j',
4736 'q', 'o', 'f', 'e', 'c',
4737 'k'
4738 }
4739 },
4740 {
4741 '6', new[]
4742 {
4743 'j', 'p', 'g', 'v', 'o',
4744 'u', 'm', 'f', 'y', 'q',
4745 'b', 'e', 'n', 'h', 'z',
4746 'r', 'd', 'k', 'a', 's',
4747 'x', 'l', 'i', 'c', 't',
4748 'w'
4749 }
4750 },
4751 {
4752 '7', new[]
4753 {
4754 'n', 'z', 'j', 'h', 'g',
4755 'r', 'c', 'x', 'm', 'y',
4756 's', 'w', 'b', 'o', 'u',
4757 'f', 'a', 'i', 'v', 'l',
4758 'p', 'e', 'k', 'q', 'd',
4759 't'
4760 }
4761 },
4762 {
4763 '8', new[]
4764 {
4765 'f', 'k', 'q', 'h', 't',
4766 'l', 'x', 'o', 'c', 'b',
4767 'j', 's', 'p', 'd', 'z',
4768 'r', 'a', 'm', 'e', 'w',
4769 'n', 'i', 'u', 'y', 'g',
4770 'v'
4771 }
4772 },
4773 {
4774 'b', new[]
4775 {
4776 'l', 'e', 'y', 'j', 'v',
4777 'c', 'n', 'i', 'x', 'w',
4778 'p', 'b', 'q', 'm', 'd',
4779 'r', 't', 'a', 'k', 'z',
4780 'g', 'f', 'u', 'h', 'o',
4781 's'
4782 }
4783 },
4784 {
4785 'g', new[]
4786 {
4787 'f', 's', 'o', 'k', 'a',
4788 'n', 'u', 'e', 'r', 'h',
4789 'm', 'b', 't', 'i', 'y',
4790 'c', 'w', 'l', 'q', 'p',
4791 'z', 'x', 'v', 'g', 'j',
4792 'd'
4793 }
4794 }
4795 };
4796  
4797 Dictionary<char, char[]> def_reflectors = new Dictionary<char, char[]>
4798 {
4799 {
4800 'B', new[]
4801 {
4802 'a', 'y', 'b', 'r', 'c', 'u', 'd', 'h',
4803 'e', 'q', 'f', 's', 'g', 'l', 'i', 'p',
4804 'j', 'x', 'k', 'n', 'm', 'o', 't', 'z',
4805 'v', 'w'
4806 }
4807 },
4808 {
4809 'b', new[]
4810 {
4811 'a', 'e', 'b', 'n', 'c', 'k', 'd', 'q',
4812 'f', 'u', 'g', 'y', 'h', 'w', 'i', 'j',
4813 'l', 'o', 'm', 'p', 'r', 'x', 's', 'z',
4814 't', 'v'
4815 }
4816 },
4817 {
4818 'C', new[]
4819 {
4820 'a', 'f', 'b', 'v', 'c', 'p', 'd', 'j',
4821 'e', 'i', 'g', 'o', 'h', 'y', 'k', 'r',
4822 'l', 'z', 'm', 'x', 'n', 'w', 't', 'q',
4823 's', 'u'
4824 }
4825 },
4826 {
4827 'c', new[]
4828 {
4829 'a', 'r', 'b', 'd', 'c', 'o', 'e', 'j',
4830 'f', 'n', 'g', 't', 'h', 'k', 'i', 'v',
4831 'l', 'm', 'p', 'w', 'q', 'z', 's', 'x',
4832 'u', 'y'
4833 }
4834 }
4835 };
4836  
4837 // Setup rotors from plugs.
4838 foreach (char rotor in rotors)
4839 {
4840 char plug = plugs[Array.IndexOf(rotors, rotor)];
4841 int i = Array.IndexOf(def_rotors[rotor], plug);
4842 if (i.Equals(0)) continue;
4843 def_rotors[rotor] = wasConcatenateArrays(new[] {plug},
4844 wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i, i), i, -1),
4845 wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i + 1, -1), 0, i - 1));
4846 }
4847  
4848 StringBuilder result = new StringBuilder();
4849 foreach (char c in message)
4850 {
4851 if (!char.IsLetter(c))
4852 {
4853 result.Append(c);
4854 continue;
4855 }
4856  
4857 // Normalize to lower.
4858 char l = char.ToLower(c);
4859  
4860 Action<char[]> rotate = o =>
4861 {
4862 int i = o.Length - 1;
4863 do
4864 {
4865 def_rotors[o[0]] = wasForwardPermuteArrayElements(def_rotors[o[0]], 1);
4866 if (i.Equals(0))
4867 {
4868 rotors = wasReversePermuteArrayElements(o, 1);
4869 continue;
4870 }
4871 l = wasGetElementAt(def_rotors[o[1]], Array.IndexOf(def_rotors[o[0]], l) - 1);
4872 o = wasReversePermuteArrayElements(o, 1);
4873 } while (--i > -1);
4874 };
4875  
4876 // Forward pass through the Enigma's rotors.
4877 rotate.Invoke(rotors);
4878  
4879 // Reflect
4880 int x = Array.IndexOf(def_reflectors[reflector], l);
4881 l = (x + 1)%2 == 0 ? def_reflectors[reflector][x - 1] : def_reflectors[reflector][x + 1];
4882  
4883 // Reverse the order of the rotors.
4884 Array.Reverse(rotors);
4885  
4886 // Reverse pass through the Enigma's rotors.
4887 rotate.Invoke(rotors);
4888  
4889 if (char.IsUpper(c))
4890 {
4891 l = char.ToUpper(l);
4892 }
4893 result.Append(l);
4894 }
4895  
4896 return result.ToString();
4897 }
4898  
4899 ///////////////////////////////////////////////////////////////////////////
4900 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4901 ///////////////////////////////////////////////////////////////////////////
4902 /// <summary>
4903 /// Expand the VIGENRE key to the length of the input.
4904 /// </summary>
4905 /// <param name="input">the input to expand to</param>
4906 /// <param name="enc_key">the key to expand</param>
4907 /// <returns>the expanded key</returns>
4908 private static string wasVigenereExpandKey(string input, string enc_key)
4909 {
4910 string exp_key = string.Empty;
4911 int i = 0, j = 0;
4912 do
4913 {
4914 char p = input[i];
4915 if (!char.IsLetter(p))
4916 {
4917 exp_key += p;
4918 ++i;
4919 continue;
4920 }
4921 int m = j%enc_key.Length;
4922 exp_key += enc_key[m];
4923 ++j;
4924 ++i;
4925 } while (i < input.Length);
4926 return exp_key;
4927 }
4928  
4929 ///////////////////////////////////////////////////////////////////////////
4930 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4931 ///////////////////////////////////////////////////////////////////////////
4932 /// <summary>
4933 /// Encrypt using VIGENERE.
4934 /// </summary>
4935 /// <param name="input">the input to encrypt</param>
4936 /// <param name="enc_key">the key to encrypt with</param>
4937 /// <returns>the encrypted input</returns>
4938 private static string wasEncryptVIGENERE(string input, string enc_key)
4939 {
4940 char[] a =
4941 {
4942 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
4943 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
4944 };
4945  
4946 enc_key = wasVigenereExpandKey(input, enc_key);
4947 string result = string.Empty;
4948 int i = 0;
4949 do
4950 {
4951 char p = input[i];
4952 if (!char.IsLetter(p))
4953 {
4954 result += p;
4955 ++i;
4956 continue;
4957 }
4958 char q =
4959 wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i]))[
4960 Array.IndexOf(a, char.ToLowerInvariant(p))];
4961 if (char.IsUpper(p))
4962 {
4963 q = char.ToUpperInvariant(q);
4964 }
4965 result += q;
4966 ++i;
4967 } while (i < input.Length);
4968 return result;
4969 }
4970  
4971 ///////////////////////////////////////////////////////////////////////////
4972 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
4973 ///////////////////////////////////////////////////////////////////////////
4974 /// <summary>
4975 /// Decrypt using VIGENERE.
4976 /// </summary>
4977 /// <param name="input">the input to decrypt</param>
4978 /// <param name="enc_key">the key to decrypt with</param>
4979 /// <returns>the decrypted input</returns>
4980 private static string wasDecryptVIGENERE(string input, string enc_key)
4981 {
4982 char[] a =
4983 {
4984 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
4985 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
4986 };
4987  
4988 enc_key = wasVigenereExpandKey(input, enc_key);
4989 string result = string.Empty;
4990 int i = 0;
4991 do
4992 {
4993 char p = input[i];
4994 if (!char.IsLetter(p))
4995 {
4996 result += p;
4997 ++i;
4998 continue;
4999 }
5000 char q =
5001 a[
5002 Array.IndexOf(wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i])),
5003 char.ToLowerInvariant(p))];
5004 if (char.IsUpper(p))
5005 {
5006 q = char.ToUpperInvariant(q);
5007 }
5008 result += q;
5009 ++i;
5010 } while (i < input.Length);
5011 return result;
5012 }
5013  
5014 ///////////////////////////////////////////////////////////////////////////
5015 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
5016 ///////////////////////////////////////////////////////////////////////////
5017 /// <summary>
5018 /// An implementation of the ATBASH cypher for latin alphabets.
5019 /// </summary>
5020 /// <param name="data">the data to encrypt or decrypt</param>
5021 /// <returns>the encrypted or decrypted data</returns>
5022 private static string wasATBASH(string data)
5023 {
5024 char[] a =
5025 {
5026 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
5027 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
5028 };
5029  
5030 char[] input = data.ToArray();
5031  
5032 Parallel.ForEach(Enumerable.Range(0, data.Length), i =>
5033 {
5034 char e = input[i];
5035 if (!char.IsLetter(e)) return;
5036 int x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e));
5037 if (!char.IsUpper(e))
5038 {
5039 input[i] = a[x];
5040 return;
5041 }
5042 input[i] = char.ToUpperInvariant(a[x]);
5043 });
5044  
5045 return new string(input);
5046 }
5047  
5048 #endregion
2 zed 5049 }
8 eva 5050 }