corrade-vassal – Diff between revs 2 and 3

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 2 Rev 3
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // 2 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
3 // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // 3 // Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
4 // rights of fair usage, the disclaimer and warranty conditions. // 4 // rights of fair usage, the disclaimer and warranty conditions. //
5 /////////////////////////////////////////////////////////////////////////// 5 ///////////////////////////////////////////////////////////////////////////
6   6  
7 using System; 7 using System;
8 using System.Collections; 8 using System.Collections;
9 using System.Collections.Generic; 9 using System.Collections.Generic;
10 using System.ComponentModel; 10 using System.ComponentModel;
11 using System.Data; 11 using System.Data;
12 using System.Drawing; 12 using System.Drawing;
13 using System.IO; 13 using System.IO;
14 using System.Linq; 14 using System.Linq;
15 using System.Net; 15 using System.Net;
16 using System.Reflection; 16 using System.Reflection;
17 using System.Text; 17 using System.Text;
18 using System.Text.RegularExpressions; 18 using System.Text.RegularExpressions;
19 using System.Timers; 19 using System.Timers;
20 using System.Threading; 20 using System.Threading;
21 using System.Web; 21 using System.Web;
22 using System.Windows.Forms; 22 using System.Windows.Forms;
23 using OpenMetaverse; 23 using OpenMetaverse;
24 using Parallel = System.Threading.Tasks.Parallel; 24 using Parallel = System.Threading.Tasks.Parallel;
25 using Timer = System.Timers.Timer; 25 using Timer = System.Timers.Timer;
26   26  
27 namespace Vassal 27 namespace Vassal
28 { 28 {
29 public partial class Vassal : Form 29 public partial class Vassal : Form
30 { 30 {
31 public static System.Timers.Timer overviewTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds); 31 public static System.Timers.Timer overviewTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
32 public static System.Timers.Timer topScriptsTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds); 32 public static System.Timers.Timer topScriptsTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
33 public static System.Timers.Timer topCollidersTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds); 33 public static System.Timers.Timer topCollidersTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
34 public static Dictionary<string, Vector3> ConfiguredRegions = new Dictionary<string, Vector3>(); -  
35 public static VassalConfiguration vassalConfiguration = new VassalConfiguration(); 34 public static VassalConfiguration vassalConfiguration = new VassalConfiguration();
36 public static Vassal vassalForm; 35 public static Vassal vassalForm;
37 public static readonly object ClientInstanceTeleportLock = new object(); 36 public static readonly object ClientInstanceTeleportLock = new object();
38   37  
39 /////////////////////////////////////////////////////////////////////////// 38 ///////////////////////////////////////////////////////////////////////////
40 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // 39 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
41 /////////////////////////////////////////////////////////////////////////// 40 ///////////////////////////////////////////////////////////////////////////
42 /// <summary>RFC1738 URL Escapes a string</summary> 41 /// <summary>RFC1738 URL Escapes a string</summary>
43 /// <param name="data">a string to escape</param> 42 /// <param name="data">a string to escape</param>
44 /// <returns>an RFC1738 escaped string</returns> 43 /// <returns>an RFC1738 escaped string</returns>
45 private static string wasURLEscapeDataString(string data) 44 private static string wasURLEscapeDataString(string data)
46 { 45 {
47 return HttpUtility.UrlEncode(data); 46 return HttpUtility.UrlEncode(data);
48 } 47 }
49   48  
50 /////////////////////////////////////////////////////////////////////////// 49 ///////////////////////////////////////////////////////////////////////////
51 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // 50 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
52 /////////////////////////////////////////////////////////////////////////// 51 ///////////////////////////////////////////////////////////////////////////
53 /// <summary>RFC1738 URL Unescape a string</summary> 52 /// <summary>RFC1738 URL Unescape a string</summary>
54 /// <param name="data">a string to unescape</param> 53 /// <param name="data">a string to unescape</param>
55 /// <returns>an RFC1738 unescaped string</returns> 54 /// <returns>an RFC1738 unescaped string</returns>
56 private static string wasURLUnescapeDataString(string data) 55 private static string wasURLUnescapeDataString(string data)
57 { 56 {
58 return HttpUtility.UrlDecode(data); 57 return HttpUtility.UrlDecode(data);
59 } 58 }
60   59  
61 /////////////////////////////////////////////////////////////////////////// 60 ///////////////////////////////////////////////////////////////////////////
62 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 61 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
63 /////////////////////////////////////////////////////////////////////////// 62 ///////////////////////////////////////////////////////////////////////////
64 /// <summary>URI unescapes an RFC3986 URI escaped string</summary> 63 /// <summary>URI unescapes an RFC3986 URI escaped string</summary>
65 /// <param name="data">a string to unescape</param> 64 /// <param name="data">a string to unescape</param>
66 /// <returns>the resulting string</returns> 65 /// <returns>the resulting string</returns>
67 private static string wasURIUnescapeDataString(string data) 66 private static string wasURIUnescapeDataString(string data)
68 { 67 {
69 // Uri.UnescapeDataString can only handle 32766 characters at a time 68 // Uri.UnescapeDataString can only handle 32766 characters at a time
70 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766) 69 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766)
71 .Select(o => Uri.UnescapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766))))) 70 .Select(o => Uri.UnescapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766)))))
72 .ToArray()); 71 .ToArray());
73 } 72 }
74   73  
75 /////////////////////////////////////////////////////////////////////////// 74 ///////////////////////////////////////////////////////////////////////////
76 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 75 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
77 /////////////////////////////////////////////////////////////////////////// 76 ///////////////////////////////////////////////////////////////////////////
78 /// <summary>RFC3986 URI Escapes a string</summary> 77 /// <summary>RFC3986 URI Escapes a string</summary>
79 /// <param name="data">a string to escape</param> 78 /// <param name="data">a string to escape</param>
80 /// <returns>an RFC3986 escaped string</returns> 79 /// <returns>an RFC3986 escaped string</returns>
81 private static string wasURIEscapeDataString(string data) 80 private static string wasURIEscapeDataString(string data)
82 { 81 {
83 // Uri.EscapeDataString can only handle 32766 characters at a time 82 // Uri.EscapeDataString can only handle 32766 characters at a time
84 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766) 83 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766)
85 .Select(o => Uri.EscapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766))))) 84 .Select(o => Uri.EscapeDataString(data.Substring(o*32766, Math.Min(32766, data.Length - (o*32766)))))
86 .ToArray()); 85 .ToArray());
87 } 86 }
88   87  
89 /////////////////////////////////////////////////////////////////////////// 88 ///////////////////////////////////////////////////////////////////////////
90 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 89 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
91 /////////////////////////////////////////////////////////////////////////// 90 ///////////////////////////////////////////////////////////////////////////
92 /// <summary> 91 /// <summary>
93 /// Gets an array element at a given modulo index. 92 /// Gets an array element at a given modulo index.
94 /// </summary> 93 /// </summary>
95 /// <typeparam name="T">the array type</typeparam> 94 /// <typeparam name="T">the array type</typeparam>
96 /// <param name="index">a positive or negative index of the element</param> 95 /// <param name="index">a positive or negative index of the element</param>
97 /// <param name="data">the array</param> 96 /// <param name="data">the array</param>
98 /// <return>an array element</return> 97 /// <return>an array element</return>
99 public static T wasGetElementAt<T>(T[] data, int index) 98 public static T wasGetElementAt<T>(T[] data, int index)
100 { 99 {
101 switch (index < 0) 100 switch (index < 0)
102 { 101 {
103 case true: 102 case true:
104 return data[((index%data.Length) + data.Length)%data.Length]; 103 return data[((index%data.Length) + data.Length)%data.Length];
105 default: 104 default:
106 return data[index%data.Length]; 105 return data[index%data.Length];
107 } 106 }
108 } 107 }
109   108  
110 #region KEY-VALUE DATA 109 #region KEY-VALUE DATA
111   110  
112 /////////////////////////////////////////////////////////////////////////// 111 ///////////////////////////////////////////////////////////////////////////
113 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 112 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
114 /////////////////////////////////////////////////////////////////////////// 113 ///////////////////////////////////////////////////////////////////////////
115 /// <summary> 114 /// <summary>
116 /// Returns the value of a key from a key-value data string. 115 /// Returns the value of a key from a key-value data string.
117 /// </summary> 116 /// </summary>
118 /// <param name="key">the key of the value</param> 117 /// <param name="key">the key of the value</param>
119 /// <param name="data">the key-value data segment</param> 118 /// <param name="data">the key-value data segment</param>
120 /// <returns>true if the key was found in data</returns> 119 /// <returns>true if the key was found in data</returns>
121 private static string wasKeyValueGet(string key, string data) 120 private static string wasKeyValueGet(string key, string data)
122 { 121 {
123 return data.Split('&') 122 return data.Split('&')
124 .AsParallel() 123 .AsParallel()
125 .Select(o => o.Split('=').ToList()) 124 .Select(o => o.Split('=').ToList())
126 .Where(o => o.Count.Equals(2)) 125 .Where(o => o.Count.Equals(2))
127 .Select(o => new 126 .Select(o => new
128 { 127 {
129 k = o.First(), 128 k = o.First(),
130 v = o.Last() 129 v = o.Last()
131 }) 130 })
132 .Where(o => o.k.Equals(key)) 131 .Where(o => o.k.Equals(key))
133 .Select(o => o.v) 132 .Select(o => o.v)
134 .FirstOrDefault(); 133 .FirstOrDefault();
135 } 134 }
-   135  
136 #endregion 136 #endregion
137   137  
138 #region CRYPTOGRAPHY 138 #region CRYPTOGRAPHY
139   139  
140 /////////////////////////////////////////////////////////////////////////// 140 ///////////////////////////////////////////////////////////////////////////
141 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 141 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
142 /////////////////////////////////////////////////////////////////////////// 142 ///////////////////////////////////////////////////////////////////////////
143 /// <summary> 143 /// <summary>
144 /// Gets a sub-array from an array. 144 /// Gets a sub-array from an array.
145 /// </summary> 145 /// </summary>
146 /// <typeparam name="T">the array type</typeparam> 146 /// <typeparam name="T">the array type</typeparam>
147 /// <param name="data">the array</param> 147 /// <param name="data">the array</param>
148 /// <param name="start">the start index</param> 148 /// <param name="start">the start index</param>
149 /// <param name="stop">the stop index (-1 denotes the end)</param> 149 /// <param name="stop">the stop index (-1 denotes the end)</param>
150 /// <returns>the array slice between start and stop</returns> 150 /// <returns>the array slice between start and stop</returns>
151 public static T[] wasGetSubArray<T>(T[] data, int start, int stop) 151 public static T[] wasGetSubArray<T>(T[] data, int start, int stop)
152 { 152 {
153 if (stop.Equals(-1)) 153 if (stop.Equals(-1))
154 stop = data.Length - 1; 154 stop = data.Length - 1;
155 T[] result = new T[stop - start + 1]; 155 T[] result = new T[stop - start + 1];
156 Array.Copy(data, start, result, 0, stop - start + 1); 156 Array.Copy(data, start, result, 0, stop - start + 1);
157 return result; 157 return result;
158 } 158 }
159   159  
160 /////////////////////////////////////////////////////////////////////////// 160 ///////////////////////////////////////////////////////////////////////////
161 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 161 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
162 /////////////////////////////////////////////////////////////////////////// 162 ///////////////////////////////////////////////////////////////////////////
163 /// <summary> 163 /// <summary>
164 /// Delete a sub-array and return the result. 164 /// Delete a sub-array and return the result.
165 /// </summary> 165 /// </summary>
166 /// <typeparam name="T">the array type</typeparam> 166 /// <typeparam name="T">the array type</typeparam>
167 /// <param name="data">the array</param> 167 /// <param name="data">the array</param>
168 /// <param name="start">the start index</param> 168 /// <param name="start">the start index</param>
169 /// <param name="stop">the stop index (-1 denotes the end)</param> 169 /// <param name="stop">the stop index (-1 denotes the end)</param>
170 /// <returns>the array without elements between start and stop</returns> 170 /// <returns>the array without elements between start and stop</returns>
171 public static T[] wasDeleteSubArray<T>(T[] data, int start, int stop) 171 public static T[] wasDeleteSubArray<T>(T[] data, int start, int stop)
172 { 172 {
173 if (stop.Equals(-1)) 173 if (stop.Equals(-1))
174 stop = data.Length - 1; 174 stop = data.Length - 1;
175 T[] result = new T[data.Length - (stop - start) - 1]; 175 T[] result = new T[data.Length - (stop - start) - 1];
176 Array.Copy(data, 0, result, 0, start); 176 Array.Copy(data, 0, result, 0, start);
177 Array.Copy(data, stop + 1, result, start, data.Length - stop - 1); 177 Array.Copy(data, stop + 1, result, start, data.Length - stop - 1);
178 return result; 178 return result;
179 } 179 }
180   180  
181 /////////////////////////////////////////////////////////////////////////// 181 ///////////////////////////////////////////////////////////////////////////
182 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 182 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
183 /////////////////////////////////////////////////////////////////////////// 183 ///////////////////////////////////////////////////////////////////////////
184 /// <summary> 184 /// <summary>
185 /// Concatenate multiple arrays. 185 /// Concatenate multiple arrays.
186 /// </summary> 186 /// </summary>
187 /// <typeparam name="T">the array type</typeparam> 187 /// <typeparam name="T">the array type</typeparam>
188 /// <param name="arrays">multiple arrays</param> 188 /// <param name="arrays">multiple arrays</param>
189 /// <returns>a flat array with all arrays concatenated</returns> 189 /// <returns>a flat array with all arrays concatenated</returns>
190 public static T[] wasConcatenateArrays<T>(params T[][] arrays) 190 public static T[] wasConcatenateArrays<T>(params T[][] arrays)
191 { 191 {
192 int resultLength = 0; 192 int resultLength = 0;
193 foreach (T[] o in arrays) 193 foreach (T[] o in arrays)
194 { 194 {
195 resultLength += o.Length; 195 resultLength += o.Length;
196 } 196 }
197 T[] result = new T[resultLength]; 197 T[] result = new T[resultLength];
198 int offset = 0; 198 int offset = 0;
199 for (int x = 0; x < arrays.Length; x++) 199 for (int x = 0; x < arrays.Length; x++)
200 { 200 {
201 arrays[x].CopyTo(result, offset); 201 arrays[x].CopyTo(result, offset);
202 offset += arrays[x].Length; 202 offset += arrays[x].Length;
203 } 203 }
204 return result; 204 return result;
205 } 205 }
206   206  
207 /////////////////////////////////////////////////////////////////////////// 207 ///////////////////////////////////////////////////////////////////////////
208 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 208 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
209 /////////////////////////////////////////////////////////////////////////// 209 ///////////////////////////////////////////////////////////////////////////
210 /// <summary> 210 /// <summary>
211 /// Permutes an array in reverse a given number of times. 211 /// Permutes an array in reverse a given number of times.
212 /// </summary> 212 /// </summary>
213 /// <typeparam name="T">the array type</typeparam> 213 /// <typeparam name="T">the array type</typeparam>
214 /// <param name="input">the array</param> 214 /// <param name="input">the array</param>
215 /// <param name="times">the number of times to permute</param> 215 /// <param name="times">the number of times to permute</param>
216 /// <returns>the array with the elements permuted</returns> 216 /// <returns>the array with the elements permuted</returns>
217 private static T[] wasReversePermuteArrayElements<T>(T[] input, int times) 217 private static T[] wasReversePermuteArrayElements<T>(T[] input, int times)
218 { 218 {
219 if (times.Equals(0)) return input; 219 if (times.Equals(0)) return input;
220 T[] slice = new T[input.Length]; 220 T[] slice = new T[input.Length];
221 Array.Copy(input, 1, slice, 0, input.Length - 1); 221 Array.Copy(input, 1, slice, 0, input.Length - 1);
222 Array.Copy(input, 0, slice, input.Length - 1, 1); 222 Array.Copy(input, 0, slice, input.Length - 1, 1);
223 return wasReversePermuteArrayElements(slice, --times); 223 return wasReversePermuteArrayElements(slice, --times);
224 } 224 }
225   225  
226 /////////////////////////////////////////////////////////////////////////// 226 ///////////////////////////////////////////////////////////////////////////
227 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 227 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
228 /////////////////////////////////////////////////////////////////////////// 228 ///////////////////////////////////////////////////////////////////////////
229 /// <summary> 229 /// <summary>
230 /// Permutes an array forward a given number of times. 230 /// Permutes an array forward a given number of times.
231 /// </summary> 231 /// </summary>
232 /// <typeparam name="T">the array type</typeparam> 232 /// <typeparam name="T">the array type</typeparam>
233 /// <param name="input">the array</param> 233 /// <param name="input">the array</param>
234 /// <param name="times">the number of times to permute</param> 234 /// <param name="times">the number of times to permute</param>
235 /// <returns>the array with the elements permuted</returns> 235 /// <returns>the array with the elements permuted</returns>
236 private static T[] wasForwardPermuteArrayElements<T>(T[] input, int times) 236 private static T[] wasForwardPermuteArrayElements<T>(T[] input, int times)
237 { 237 {
238 if (times.Equals(0)) return input; 238 if (times.Equals(0)) return input;
239 T[] slice = new T[input.Length]; 239 T[] slice = new T[input.Length];
240 Array.Copy(input, input.Length - 1, slice, 0, 1); 240 Array.Copy(input, input.Length - 1, slice, 0, 1);
241 Array.Copy(input, 0, slice, 1, input.Length - 1); 241 Array.Copy(input, 0, slice, 1, input.Length - 1);
242 return wasForwardPermuteArrayElements(slice, --times); 242 return wasForwardPermuteArrayElements(slice, --times);
243 } 243 }
244   244  
245 /////////////////////////////////////////////////////////////////////////// 245 ///////////////////////////////////////////////////////////////////////////
246 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 246 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
247 /////////////////////////////////////////////////////////////////////////// 247 ///////////////////////////////////////////////////////////////////////////
248 /// <summary> 248 /// <summary>
249 /// Encrypt or decrypt a message given a set of rotors, plugs and a reflector. 249 /// Encrypt or decrypt a message given a set of rotors, plugs and a reflector.
250 /// </summary> 250 /// </summary>
251 /// <param name="message">the message to encyrpt or decrypt</param> 251 /// <param name="message">the message to encyrpt or decrypt</param>
252 /// <param name="rotors">any combination of: 1, 2, 3, 4, 5, 6, 7, 8, b, g</param> 252 /// <param name="rotors">any combination of: 1, 2, 3, 4, 5, 6, 7, 8, b, g</param>
253 /// <param name="plugs">the letter representing the start character for the rotor</param> 253 /// <param name="plugs">the letter representing the start character for the rotor</param>
254 /// <param name="reflector">any one of: B, b, C, c</param> 254 /// <param name="reflector">any one of: B, b, C, c</param>
255 /// <returns>either a decrypted or encrypted string</returns> 255 /// <returns>either a decrypted or encrypted string</returns>
256 private static string wasEnigma(string message, char[] rotors, char[] plugs, char reflector) 256 private static string wasEnigma(string message, char[] rotors, char[] plugs, char reflector)
257 { 257 {
258 Dictionary<char, char[]> def_rotors = new Dictionary<char, char[]> 258 Dictionary<char, char[]> def_rotors = new Dictionary<char, char[]>
259 { 259 {
260 { 260 {
261 '1', new[] 261 '1', new[]
262 { 262 {
263 'e', 'k', 'm', 'f', 'l', 263 'e', 'k', 'm', 'f', 'l',
264 'g', 'd', 'q', 'v', 'z', 264 'g', 'd', 'q', 'v', 'z',
265 'n', 't', 'o', 'w', 'y', 265 'n', 't', 'o', 'w', 'y',
266 'h', 'x', 'u', 's', 'p', 266 'h', 'x', 'u', 's', 'p',
267 'a', 'i', 'b', 'r', 'c', 267 'a', 'i', 'b', 'r', 'c',
268 'j' 268 'j'
269 } 269 }
270 }, 270 },
271 { 271 {
272 '2', new[] 272 '2', new[]
273 { 273 {
274 'a', 'j', 'd', 'k', 's', 274 'a', 'j', 'd', 'k', 's',
275 'i', 'r', 'u', 'x', 'b', 275 'i', 'r', 'u', 'x', 'b',
276 'l', 'h', 'w', 't', 'm', 276 'l', 'h', 'w', 't', 'm',
277 'c', 'q', 'g', 'z', 'n', 277 'c', 'q', 'g', 'z', 'n',
278 'p', 'y', 'f', 'v', 'o', 278 'p', 'y', 'f', 'v', 'o',
279 'e' 279 'e'
280 } 280 }
281 }, 281 },
282 { 282 {
283 '3', new[] 283 '3', new[]
284 { 284 {
285 'b', 'd', 'f', 'h', 'j', 285 'b', 'd', 'f', 'h', 'j',
286 'l', 'c', 'p', 'r', 't', 286 'l', 'c', 'p', 'r', 't',
287 'x', 'v', 'z', 'n', 'y', 287 'x', 'v', 'z', 'n', 'y',
288 'e', 'i', 'w', 'g', 'a', 288 'e', 'i', 'w', 'g', 'a',
289 'k', 'm', 'u', 's', 'q', 289 'k', 'm', 'u', 's', 'q',
290 'o' 290 'o'
291 } 291 }
292 }, 292 },
293 { 293 {
294 '4', new[] 294 '4', new[]
295 { 295 {
296 'e', 's', 'o', 'v', 'p', 296 'e', 's', 'o', 'v', 'p',
297 'z', 'j', 'a', 'y', 'q', 297 'z', 'j', 'a', 'y', 'q',
298 'u', 'i', 'r', 'h', 'x', 298 'u', 'i', 'r', 'h', 'x',
299 'l', 'n', 'f', 't', 'g', 299 'l', 'n', 'f', 't', 'g',
300 'k', 'd', 'c', 'm', 'w', 300 'k', 'd', 'c', 'm', 'w',
301 'b' 301 'b'
302 } 302 }
303 }, 303 },
304 { 304 {
305 '5', new[] 305 '5', new[]
306 { 306 {
307 'v', 'z', 'b', 'r', 'g', 307 'v', 'z', 'b', 'r', 'g',
308 'i', 't', 'y', 'u', 'p', 308 'i', 't', 'y', 'u', 'p',
309 's', 'd', 'n', 'h', 'l', 309 's', 'd', 'n', 'h', 'l',
310 'x', 'a', 'w', 'm', 'j', 310 'x', 'a', 'w', 'm', 'j',
311 'q', 'o', 'f', 'e', 'c', 311 'q', 'o', 'f', 'e', 'c',
312 'k' 312 'k'
313 } 313 }
314 }, 314 },
315 { 315 {
316 '6', new[] 316 '6', new[]
317 { 317 {
318 'j', 'p', 'g', 'v', 'o', 318 'j', 'p', 'g', 'v', 'o',
319 'u', 'm', 'f', 'y', 'q', 319 'u', 'm', 'f', 'y', 'q',
320 'b', 'e', 'n', 'h', 'z', 320 'b', 'e', 'n', 'h', 'z',
321 'r', 'd', 'k', 'a', 's', 321 'r', 'd', 'k', 'a', 's',
322 'x', 'l', 'i', 'c', 't', 322 'x', 'l', 'i', 'c', 't',
323 'w' 323 'w'
324 } 324 }
325 }, 325 },
326 { 326 {
327 '7', new[] 327 '7', new[]
328 { 328 {
329 'n', 'z', 'j', 'h', 'g', 329 'n', 'z', 'j', 'h', 'g',
330 'r', 'c', 'x', 'm', 'y', 330 'r', 'c', 'x', 'm', 'y',
331 's', 'w', 'b', 'o', 'u', 331 's', 'w', 'b', 'o', 'u',
332 'f', 'a', 'i', 'v', 'l', 332 'f', 'a', 'i', 'v', 'l',
333 'p', 'e', 'k', 'q', 'd', 333 'p', 'e', 'k', 'q', 'd',
334 't' 334 't'
335 } 335 }
336 }, 336 },
337 { 337 {
338 '8', new[] 338 '8', new[]
339 { 339 {
340 'f', 'k', 'q', 'h', 't', 340 'f', 'k', 'q', 'h', 't',
341 'l', 'x', 'o', 'c', 'b', 341 'l', 'x', 'o', 'c', 'b',
342 'j', 's', 'p', 'd', 'z', 342 'j', 's', 'p', 'd', 'z',
343 'r', 'a', 'm', 'e', 'w', 343 'r', 'a', 'm', 'e', 'w',
344 'n', 'i', 'u', 'y', 'g', 344 'n', 'i', 'u', 'y', 'g',
345 'v' 345 'v'
346 } 346 }
347 }, 347 },
348 { 348 {
349 'b', new[] 349 'b', new[]
350 { 350 {
351 'l', 'e', 'y', 'j', 'v', 351 'l', 'e', 'y', 'j', 'v',
352 'c', 'n', 'i', 'x', 'w', 352 'c', 'n', 'i', 'x', 'w',
353 'p', 'b', 'q', 'm', 'd', 353 'p', 'b', 'q', 'm', 'd',
354 'r', 't', 'a', 'k', 'z', 354 'r', 't', 'a', 'k', 'z',
355 'g', 'f', 'u', 'h', 'o', 355 'g', 'f', 'u', 'h', 'o',
356 's' 356 's'
357 } 357 }
358 }, 358 },
359 { 359 {
360 'g', new[] 360 'g', new[]
361 { 361 {
362 'f', 's', 'o', 'k', 'a', 362 'f', 's', 'o', 'k', 'a',
363 'n', 'u', 'e', 'r', 'h', 363 'n', 'u', 'e', 'r', 'h',
364 'm', 'b', 't', 'i', 'y', 364 'm', 'b', 't', 'i', 'y',
365 'c', 'w', 'l', 'q', 'p', 365 'c', 'w', 'l', 'q', 'p',
366 'z', 'x', 'v', 'g', 'j', 366 'z', 'x', 'v', 'g', 'j',
367 'd' 367 'd'
368 } 368 }
369 } 369 }
370 }; 370 };
371   371  
372 Dictionary<char, char[]> def_reflectors = new Dictionary<char, char[]> 372 Dictionary<char, char[]> def_reflectors = new Dictionary<char, char[]>
373 { 373 {
374 { 374 {
375 'B', new[] 375 'B', new[]
376 { 376 {
377 'a', 'y', 'b', 'r', 'c', 'u', 'd', 'h', 377 'a', 'y', 'b', 'r', 'c', 'u', 'd', 'h',
378 'e', 'q', 'f', 's', 'g', 'l', 'i', 'p', 378 'e', 'q', 'f', 's', 'g', 'l', 'i', 'p',
379 'j', 'x', 'k', 'n', 'm', 'o', 't', 'z', 379 'j', 'x', 'k', 'n', 'm', 'o', 't', 'z',
380 'v', 'w' 380 'v', 'w'
381 } 381 }
382 }, 382 },
383 { 383 {
384 'b', new[] 384 'b', new[]
385 { 385 {
386 'a', 'e', 'b', 'n', 'c', 'k', 'd', 'q', 386 'a', 'e', 'b', 'n', 'c', 'k', 'd', 'q',
387 'f', 'u', 'g', 'y', 'h', 'w', 'i', 'j', 387 'f', 'u', 'g', 'y', 'h', 'w', 'i', 'j',
388 'l', 'o', 'm', 'p', 'r', 'x', 's', 'z', 388 'l', 'o', 'm', 'p', 'r', 'x', 's', 'z',
389 't', 'v' 389 't', 'v'
390 } 390 }
391 }, 391 },
392 { 392 {
393 'C', new[] 393 'C', new[]
394 { 394 {
395 'a', 'f', 'b', 'v', 'c', 'p', 'd', 'j', 395 'a', 'f', 'b', 'v', 'c', 'p', 'd', 'j',
396 'e', 'i', 'g', 'o', 'h', 'y', 'k', 'r', 396 'e', 'i', 'g', 'o', 'h', 'y', 'k', 'r',
397 'l', 'z', 'm', 'x', 'n', 'w', 't', 'q', 397 'l', 'z', 'm', 'x', 'n', 'w', 't', 'q',
398 's', 'u' 398 's', 'u'
399 } 399 }
400 }, 400 },
401 { 401 {
402 'c', new[] 402 'c', new[]
403 { 403 {
404 'a', 'r', 'b', 'd', 'c', 'o', 'e', 'j', 404 'a', 'r', 'b', 'd', 'c', 'o', 'e', 'j',
405 'f', 'n', 'g', 't', 'h', 'k', 'i', 'v', 405 'f', 'n', 'g', 't', 'h', 'k', 'i', 'v',
406 'l', 'm', 'p', 'w', 'q', 'z', 's', 'x', 406 'l', 'm', 'p', 'w', 'q', 'z', 's', 'x',
407 'u', 'y' 407 'u', 'y'
408 } 408 }
409 } 409 }
410 }; 410 };
411   411  
412 // Setup rotors from plugs. 412 // Setup rotors from plugs.
413 foreach (char rotor in rotors) 413 foreach (char rotor in rotors)
414 { 414 {
415 char plug = plugs[Array.IndexOf(rotors, rotor)]; 415 char plug = plugs[Array.IndexOf(rotors, rotor)];
416 int i = Array.IndexOf(def_rotors[rotor], plug); 416 int i = Array.IndexOf(def_rotors[rotor], plug);
417 if (i.Equals(0)) continue; 417 if (i.Equals(0)) continue;
418 def_rotors[rotor] = wasConcatenateArrays(new[] {plug}, 418 def_rotors[rotor] = wasConcatenateArrays(new[] {plug},
419 wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i, i), i, -1), 419 wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i, i), i, -1),
420 wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i + 1, -1), 0, i - 1)); 420 wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i + 1, -1), 0, i - 1));
421 } 421 }
422   422  
423 StringBuilder result = new StringBuilder(); 423 StringBuilder result = new StringBuilder();
424 foreach (char c in message) 424 foreach (char c in message)
425 { 425 {
426 if (!char.IsLetter(c)) 426 if (!char.IsLetter(c))
427 { 427 {
428 result.Append(c); 428 result.Append(c);
429 continue; 429 continue;
430 } 430 }
431   431  
432 // Normalize to lower. 432 // Normalize to lower.
433 char l = char.ToLower(c); 433 char l = char.ToLower(c);
434   434  
435 Action<char[]> rotate = o => 435 Action<char[]> rotate = o =>
436 { 436 {
437 int i = o.Length - 1; 437 int i = o.Length - 1;
438 do 438 do
439 { 439 {
440 def_rotors[o[0]] = wasForwardPermuteArrayElements(def_rotors[o[0]], 1); 440 def_rotors[o[0]] = wasForwardPermuteArrayElements(def_rotors[o[0]], 1);
441 if (i.Equals(0)) 441 if (i.Equals(0))
442 { 442 {
443 rotors = wasReversePermuteArrayElements(o, 1); 443 rotors = wasReversePermuteArrayElements(o, 1);
444 continue; 444 continue;
445 } 445 }
446 l = wasGetElementAt(def_rotors[o[1]], Array.IndexOf(def_rotors[o[0]], l) - 1); 446 l = wasGetElementAt(def_rotors[o[1]], Array.IndexOf(def_rotors[o[0]], l) - 1);
447 o = wasReversePermuteArrayElements(o, 1); 447 o = wasReversePermuteArrayElements(o, 1);
448 } while (--i > -1); 448 } while (--i > -1);
449 }; 449 };
450   450  
451 // Forward pass through the Enigma's rotors. 451 // Forward pass through the Enigma's rotors.
452 rotate.Invoke(rotors); 452 rotate.Invoke(rotors);
453   453  
454 // Reflect 454 // Reflect
455 int x = Array.IndexOf(def_reflectors[reflector], l); 455 int x = Array.IndexOf(def_reflectors[reflector], l);
456 l = (x + 1)%2 == 0 ? def_reflectors[reflector][x - 1] : def_reflectors[reflector][x + 1]; 456 l = (x + 1)%2 == 0 ? def_reflectors[reflector][x - 1] : def_reflectors[reflector][x + 1];
457   457  
458 // Reverse the order of the rotors. 458 // Reverse the order of the rotors.
459 Array.Reverse(rotors); 459 Array.Reverse(rotors);
460   460  
461 // Reverse pass through the Enigma's rotors. 461 // Reverse pass through the Enigma's rotors.
462 rotate.Invoke(rotors); 462 rotate.Invoke(rotors);
463   463  
464 if (char.IsUpper(c)) 464 if (char.IsUpper(c))
465 { 465 {
466 l = char.ToUpper(l); 466 l = char.ToUpper(l);
467 } 467 }
468 result.Append(l); 468 result.Append(l);
469 } 469 }
470   470  
471 return result.ToString(); 471 return result.ToString();
472 } 472 }
473   473  
474 /////////////////////////////////////////////////////////////////////////// 474 ///////////////////////////////////////////////////////////////////////////
475 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 475 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
476 /////////////////////////////////////////////////////////////////////////// 476 ///////////////////////////////////////////////////////////////////////////
477 /// <summary> 477 /// <summary>
478 /// Expand the VIGENRE key to the length of the input. 478 /// Expand the VIGENRE key to the length of the input.
479 /// </summary> 479 /// </summary>
480 /// <param name="input">the input to expand to</param> 480 /// <param name="input">the input to expand to</param>
481 /// <param name="enc_key">the key to expand</param> 481 /// <param name="enc_key">the key to expand</param>
482 /// <returns>the expanded key</returns> 482 /// <returns>the expanded key</returns>
483 private static string wasVigenereExpandKey(string input, string enc_key) 483 private static string wasVigenereExpandKey(string input, string enc_key)
484 { 484 {
485 string exp_key = string.Empty; 485 string exp_key = string.Empty;
486 int i = 0, j = 0; 486 int i = 0, j = 0;
487 do 487 do
488 { 488 {
489 char p = input[i]; 489 char p = input[i];
490 if (!char.IsLetter(p)) 490 if (!char.IsLetter(p))
491 { 491 {
492 exp_key += p; 492 exp_key += p;
493 ++i; 493 ++i;
494 continue; 494 continue;
495 } 495 }
496 int m = j%enc_key.Length; 496 int m = j%enc_key.Length;
497 exp_key += enc_key[m]; 497 exp_key += enc_key[m];
498 ++j; 498 ++j;
499 ++i; 499 ++i;
500 } while (i < input.Length); 500 } while (i < input.Length);
501 return exp_key; 501 return exp_key;
502 } 502 }
503   503  
504 /////////////////////////////////////////////////////////////////////////// 504 ///////////////////////////////////////////////////////////////////////////
505 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 505 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
506 /////////////////////////////////////////////////////////////////////////// 506 ///////////////////////////////////////////////////////////////////////////
507 /// <summary> 507 /// <summary>
508 /// Encrypt using VIGENERE. 508 /// Encrypt using VIGENERE.
509 /// </summary> 509 /// </summary>
510 /// <param name="input">the input to encrypt</param> 510 /// <param name="input">the input to encrypt</param>
511 /// <param name="enc_key">the key to encrypt with</param> 511 /// <param name="enc_key">the key to encrypt with</param>
512 /// <returns>the encrypted input</returns> 512 /// <returns>the encrypted input</returns>
513 private static string wasEncryptVIGENERE(string input, string enc_key) 513 private static string wasEncryptVIGENERE(string input, string enc_key)
514 { 514 {
515 char[] a = 515 char[] a =
516 { 516 {
517 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 517 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
518 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 518 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
519 }; 519 };
520   520  
521 enc_key = wasVigenereExpandKey(input, enc_key); 521 enc_key = wasVigenereExpandKey(input, enc_key);
522 string result = string.Empty; 522 string result = string.Empty;
523 int i = 0; 523 int i = 0;
524 do 524 do
525 { 525 {
526 char p = input[i]; 526 char p = input[i];
527 if (!char.IsLetter(p)) 527 if (!char.IsLetter(p))
528 { 528 {
529 result += p; 529 result += p;
530 ++i; 530 ++i;
531 continue; 531 continue;
532 } 532 }
533 char q = 533 char q =
534 wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i]))[ 534 wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i]))[
535 Array.IndexOf(a, char.ToLowerInvariant(p))]; 535 Array.IndexOf(a, char.ToLowerInvariant(p))];
536 if (char.IsUpper(p)) 536 if (char.IsUpper(p))
537 { 537 {
538 q = char.ToUpperInvariant(q); 538 q = char.ToUpperInvariant(q);
539 } 539 }
540 result += q; 540 result += q;
541 ++i; 541 ++i;
542 } while (i < input.Length); 542 } while (i < input.Length);
543 return result; 543 return result;
544 } 544 }
545   545  
546 /////////////////////////////////////////////////////////////////////////// 546 ///////////////////////////////////////////////////////////////////////////
547 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 547 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
548 /////////////////////////////////////////////////////////////////////////// 548 ///////////////////////////////////////////////////////////////////////////
549 /// <summary> 549 /// <summary>
550 /// Decrypt using VIGENERE. 550 /// Decrypt using VIGENERE.
551 /// </summary> 551 /// </summary>
552 /// <param name="input">the input to decrypt</param> 552 /// <param name="input">the input to decrypt</param>
553 /// <param name="enc_key">the key to decrypt with</param> 553 /// <param name="enc_key">the key to decrypt with</param>
554 /// <returns>the decrypted input</returns> 554 /// <returns>the decrypted input</returns>
555 private static string wasDecryptVIGENERE(string input, string enc_key) 555 private static string wasDecryptVIGENERE(string input, string enc_key)
556 { 556 {
557 char[] a = 557 char[] a =
558 { 558 {
559 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 559 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
560 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 560 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
561 }; 561 };
562   562  
563 enc_key = wasVigenereExpandKey(input, enc_key); 563 enc_key = wasVigenereExpandKey(input, enc_key);
564 string result = string.Empty; 564 string result = string.Empty;
565 int i = 0; 565 int i = 0;
566 do 566 do
567 { 567 {
568 char p = input[i]; 568 char p = input[i];
569 if (!char.IsLetter(p)) 569 if (!char.IsLetter(p))
570 { 570 {
571 result += p; 571 result += p;
572 ++i; 572 ++i;
573 continue; 573 continue;
574 } 574 }
575 char q = 575 char q =
576 a[ 576 a[
577 Array.IndexOf(wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i])), 577 Array.IndexOf(wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i])),
578 char.ToLowerInvariant(p))]; 578 char.ToLowerInvariant(p))];
579 if (char.IsUpper(p)) 579 if (char.IsUpper(p))
580 { 580 {
581 q = char.ToUpperInvariant(q); 581 q = char.ToUpperInvariant(q);
582 } 582 }
583 result += q; 583 result += q;
584 ++i; 584 ++i;
585 } while (i < input.Length); 585 } while (i < input.Length);
586 return result; 586 return result;
587 } 587 }
588   588  
589 /////////////////////////////////////////////////////////////////////////// 589 ///////////////////////////////////////////////////////////////////////////
590 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // 590 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
591 /////////////////////////////////////////////////////////////////////////// 591 ///////////////////////////////////////////////////////////////////////////
592 /// <summary> 592 /// <summary>
593 /// An implementation of the ATBASH cypher for latin alphabets. 593 /// An implementation of the ATBASH cypher for latin alphabets.
594 /// </summary> 594 /// </summary>
595 /// <param name="data">the data to encrypt or decrypt</param> 595 /// <param name="data">the data to encrypt or decrypt</param>
596 /// <returns>the encrypted or decrypted data</returns> 596 /// <returns>the encrypted or decrypted data</returns>
597 private static string wasATBASH(string data) 597 private static string wasATBASH(string data)
598 { 598 {
599 char[] a = 599 char[] a =
600 { 600 {
601 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 601 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
602 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 602 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
603 }; 603 };
604   604  
605 char[] input = data.ToArray(); 605 char[] input = data.ToArray();
606   606  
607 Parallel.ForEach(Enumerable.Range(0, data.Length), i => 607 Parallel.ForEach(Enumerable.Range(0, data.Length), i =>
608 { 608 {
609 char e = input[i]; 609 char e = input[i];
610 if (!char.IsLetter(e)) return; 610 if (!char.IsLetter(e)) return;
611 int x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e)); 611 int x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e));
612 if (!char.IsUpper(e)) 612 if (!char.IsUpper(e))
613 { 613 {
614 input[i] = a[x]; 614 input[i] = a[x];
615 return; 615 return;
616 } 616 }
617 input[i] = char.ToUpperInvariant(a[x]); 617 input[i] = char.ToUpperInvariant(a[x]);
618 }); 618 });
619   619  
620 return new string(input); 620 return new string(input);
621 } 621 }
622   622  
623 #endregion 623 #endregion
624   624  
625 /// <summary> 625 /// <summary>
626 /// Corrade's input filter function. 626 /// Corrade's input filter function.
627 /// </summary> 627 /// </summary>
628 private static readonly Func<string, string> wasInput = o => 628 private static readonly Func<string, string> wasInput = o =>
629 { 629 {
630 if (string.IsNullOrEmpty(o)) return string.Empty; 630 if (string.IsNullOrEmpty(o)) return string.Empty;
631   631  
632 foreach (Filter filter in vassalConfiguration.InputFilters) 632 foreach (Filter filter in vassalConfiguration.InputFilters)
633 { 633 {
634 switch (filter) 634 switch (filter)
635 { 635 {
636 case Filter.RFC1738: 636 case Filter.RFC1738:
637 o = wasURLUnescapeDataString(o); 637 o = wasURLUnescapeDataString(o);
638 break; 638 break;
639 case Filter.RFC3986: 639 case Filter.RFC3986:
640 o = wasURIUnescapeDataString(o); 640 o = wasURIUnescapeDataString(o);
641 break; 641 break;
642 case Filter.ENIGMA: 642 case Filter.ENIGMA:
643 o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(), 643 o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
644 vassalConfiguration.ENIGMA.plugs.ToArray(), 644 vassalConfiguration.ENIGMA.plugs.ToArray(),
645 vassalConfiguration.ENIGMA.reflector); 645 vassalConfiguration.ENIGMA.reflector);
646 break; 646 break;
647 case Filter.VIGENERE: 647 case Filter.VIGENERE:
648 o = wasDecryptVIGENERE(o, vassalConfiguration.VIGENERESecret); 648 o = wasDecryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
649 break; 649 break;
650 case Filter.ATBASH: 650 case Filter.ATBASH:
651 o = wasATBASH(o); 651 o = wasATBASH(o);
652 break; 652 break;
653 case Filter.BASE64: 653 case Filter.BASE64:
654 o = Encoding.UTF8.GetString(Convert.FromBase64String(o)); 654 o = Encoding.UTF8.GetString(Convert.FromBase64String(o));
655 break; 655 break;
656 } 656 }
657 } 657 }
658 return o; 658 return o;
659 }; 659 };
660   660  
661 /// <summary> 661 /// <summary>
662 /// Corrade's output filter function. 662 /// Corrade's output filter function.
663 /// </summary> 663 /// </summary>
664 private static readonly Func<string, string> wasOutput = o => 664 private static readonly Func<string, string> wasOutput = o =>
665 { 665 {
666 if (string.IsNullOrEmpty(o)) return string.Empty; 666 if (string.IsNullOrEmpty(o)) return string.Empty;
667   667  
668 foreach (Filter filter in vassalConfiguration.OutputFilters) 668 foreach (Filter filter in vassalConfiguration.OutputFilters)
669 { 669 {
670 switch (filter) 670 switch (filter)
671 { 671 {
672 case Filter.RFC1738: 672 case Filter.RFC1738:
673 o = wasURLEscapeDataString(o); 673 o = wasURLEscapeDataString(o);
674 break; 674 break;
675 case Filter.RFC3986: 675 case Filter.RFC3986:
676 o = wasURIEscapeDataString(o); 676 o = wasURIEscapeDataString(o);
677 break; 677 break;
678 case Filter.ENIGMA: 678 case Filter.ENIGMA:
679 o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(), 679 o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
680 vassalConfiguration.ENIGMA.plugs.ToArray(), 680 vassalConfiguration.ENIGMA.plugs.ToArray(),
681 vassalConfiguration.ENIGMA.reflector); 681 vassalConfiguration.ENIGMA.reflector);
682 break; 682 break;
683 case Filter.VIGENERE: 683 case Filter.VIGENERE:
684 o = wasEncryptVIGENERE(o, vassalConfiguration.VIGENERESecret); 684 o = wasEncryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
685 break; 685 break;
686 case Filter.ATBASH: 686 case Filter.ATBASH:
687 o = wasATBASH(o); 687 o = wasATBASH(o);
688 break; 688 break;
689 case Filter.BASE64: 689 case Filter.BASE64:
690 o = Convert.ToBase64String(Encoding.UTF8.GetBytes(o)); 690 o = Convert.ToBase64String(Encoding.UTF8.GetBytes(o));
691 break; 691 break;
692 } 692 }
693 } 693 }
694 return o; 694 return o;
695 }; 695 };
696   696  
697 /////////////////////////////////////////////////////////////////////////// 697 ///////////////////////////////////////////////////////////////////////////
698 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 698 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
699 /////////////////////////////////////////////////////////////////////////// 699 ///////////////////////////////////////////////////////////////////////////
700 /// <summary>Escapes a dictionary's keys and values for sending as POST data.</summary> 700 /// <summary>Escapes a dictionary's keys and values for sending as POST data.</summary>
701 /// <param name="data">A dictionary containing keys and values to be escaped</param> 701 /// <param name="data">A dictionary containing keys and values to be escaped</param>
702 private static Dictionary<string, string> wasKeyValueEscape(Dictionary<string, string> data) 702 private static Dictionary<string, string> wasKeyValueEscape(Dictionary<string, string> data)
703 { 703 {
704 return data.AsParallel().ToDictionary(o => wasOutput(o.Key), p => wasOutput(p.Value)); 704 return data.AsParallel().ToDictionary(o => wasOutput(o.Key), p => wasOutput(p.Value));
705 } 705 }
706   706  
707 /////////////////////////////////////////////////////////////////////////// 707 ///////////////////////////////////////////////////////////////////////////
708 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 708 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
709 /////////////////////////////////////////////////////////////////////////// 709 ///////////////////////////////////////////////////////////////////////////
710 /// <summary> 710 /// <summary>
711 /// Converts a list of string to a comma-separated values string. 711 /// Converts a list of string to a comma-separated values string.
712 /// </summary> 712 /// </summary>
713 /// <param name="l">a list of strings</param> 713 /// <param name="l">a list of strings</param>
714 /// <returns>a commma-separated list of values</returns> 714 /// <returns>a commma-separated list of values</returns>
715 /// <remarks>compliant with RFC 4180</remarks> 715 /// <remarks>compliant with RFC 4180</remarks>
716 public static string wasEnumerableToCSV(IEnumerable<string> l) 716 public static string wasEnumerableToCSV(IEnumerable<string> l)
717 { 717 {
718 string[] csv = l.Select(o => o.Clone() as string).ToArray(); 718 string[] csv = l.Select(o => o.Clone() as string).ToArray();
719 Parallel.ForEach(csv.Select((v, i) => new {i, v}), o => 719 Parallel.ForEach(csv.Select((v, i) => new {i, v}), o =>
720 { 720 {
721 string cell = o.v.Replace("\"", "\"\""); 721 string cell = o.v.Replace("\"", "\"\"");
722 switch (new[] {'"', ' ', ',', '\r', '\n'}.Any(p => cell.Contains(p))) 722 switch (new[] {'"', ' ', ',', '\r', '\n'}.Any(p => cell.Contains(p)))
723 { 723 {
724 case true: 724 case true:
725 csv[o.i] = "\"" + cell + "\""; 725 csv[o.i] = "\"" + cell + "\"";
726 break; 726 break;
727 default: 727 default:
728 csv[o.i] = cell; 728 csv[o.i] = cell;
729 break; 729 break;
730 } 730 }
731 }); 731 });
732 return String.Join(",", csv); 732 return String.Join(",", csv);
733 } 733 }
734   734  
735 /////////////////////////////////////////////////////////////////////////// 735 ///////////////////////////////////////////////////////////////////////////
736 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 736 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
737 /////////////////////////////////////////////////////////////////////////// 737 ///////////////////////////////////////////////////////////////////////////
738 /// <summary> 738 /// <summary>
739 /// Converts a comma-separated list of values to a list of strings. 739 /// Converts a comma-separated list of values to a list of strings.
740 /// </summary> 740 /// </summary>
741 /// <param name="csv">a comma-separated list of values</param> 741 /// <param name="csv">a comma-separated list of values</param>
742 /// <returns>a list of strings</returns> 742 /// <returns>a list of strings</returns>
743 /// <remarks>compliant with RFC 4180</remarks> 743 /// <remarks>compliant with RFC 4180</remarks>
744 public static IEnumerable<string> wasCSVToEnumerable(string csv) 744 public static IEnumerable<string> wasCSVToEnumerable(string csv)
745 { 745 {
746 Stack<char> s = new Stack<char>(); 746 Stack<char> s = new Stack<char>();
747 StringBuilder m = new StringBuilder(); 747 StringBuilder m = new StringBuilder();
748 for (int i = 0; i < csv.Length; ++i) 748 for (int i = 0; i < csv.Length; ++i)
749 { 749 {
750 switch (csv[i]) 750 switch (csv[i])
751 { 751 {
752 case ',': 752 case ',':
753 if (!s.Any() || !s.Peek().Equals('"')) 753 if (!s.Any() || !s.Peek().Equals('"'))
754 { 754 {
755 yield return m.ToString(); 755 yield return m.ToString();
756 m = new StringBuilder(); 756 m = new StringBuilder();
757 continue; 757 continue;
758 } 758 }
759 m.Append(csv[i]); 759 m.Append(csv[i]);
760 continue; 760 continue;
761 case '"': 761 case '"':
762 if (i + 1 < csv.Length && csv[i].Equals(csv[i + 1])) 762 if (i + 1 < csv.Length && csv[i].Equals(csv[i + 1]))
763 { 763 {
764 m.Append(csv[i]); 764 m.Append(csv[i]);
765 ++i; 765 ++i;
766 continue; 766 continue;
767 } 767 }
768 if (!s.Any() || !s.Peek().Equals(csv[i])) 768 if (!s.Any() || !s.Peek().Equals(csv[i]))
769 { 769 {
770 s.Push(csv[i]); 770 s.Push(csv[i]);
771 continue; 771 continue;
772 } 772 }
773 s.Pop(); 773 s.Pop();
774 continue; 774 continue;
775 } 775 }
776 m.Append(csv[i]); 776 m.Append(csv[i]);
777 } 777 }
778   778  
779 yield return m.ToString(); 779 yield return m.ToString();
780 } 780 }
781   781  
782 /////////////////////////////////////////////////////////////////////////// 782 ///////////////////////////////////////////////////////////////////////////
783 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 783 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
784 /////////////////////////////////////////////////////////////////////////// 784 ///////////////////////////////////////////////////////////////////////////
785 /// <summary> 785 /// <summary>
786 /// Serialises a dictionary to key-value data. 786 /// Serialises a dictionary to key-value data.
787 /// </summary> 787 /// </summary>
788 /// <param name="data">a dictionary</param> 788 /// <param name="data">a dictionary</param>
789 /// <returns>a key-value data encoded string</returns> 789 /// <returns>a key-value data encoded string</returns>
790 private static string wasKeyValueEncode(Dictionary<string, string> data) 790 private static string wasKeyValueEncode(Dictionary<string, string> data)
791 { 791 {
792 return String.Join("&", data.AsParallel().Select(o => String.Join("=", o.Key, o.Value))); 792 return String.Join("&", data.AsParallel().Select(o => String.Join("=", o.Key, o.Value)));
793 } 793 }
794   794  
795 /////////////////////////////////////////////////////////////////////////// 795 ///////////////////////////////////////////////////////////////////////////
796 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 796 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
797 /////////////////////////////////////////////////////////////////////////// 797 ///////////////////////////////////////////////////////////////////////////
798 /// <summary> 798 /// <summary>
799 /// Sends a post request to an URL with set key-value pairs. 799 /// Sends a post request to an URL with set key-value pairs.
800 /// </summary> 800 /// </summary>
801 /// <param name="URL">the url to send the message to</param> 801 /// <param name="URL">the url to send the message to</param>
802 /// <param name="message">key-value pairs to send</param> 802 /// <param name="message">key-value pairs to send</param>
803 /// <param name="millisecondsTimeout">the time in milliseconds for the request to timeout</param> 803 /// <param name="millisecondsTimeout">the time in milliseconds for the request to timeout</param>
804 private static string wasPOST(string URL, Dictionary<string, string> message, uint millisecondsTimeout) 804 private static string wasPOST(string URL, Dictionary<string, string> message, uint millisecondsTimeout)
805 { 805 {
806 try 806 try
807 { 807 {
808 HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL); 808 HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL);
809 request.UserAgent = VASSAL_CONSTANTS.USER_AGENT; 809 request.UserAgent = VASSAL_CONSTANTS.USER_AGENT;
810 request.Proxy = WebRequest.DefaultWebProxy; 810 request.Proxy = WebRequest.DefaultWebProxy;
811 request.Timeout = (int) millisecondsTimeout; 811 request.Timeout = (int) millisecondsTimeout;
812 request.AllowAutoRedirect = true; 812 request.AllowAutoRedirect = true;
813 request.AllowWriteStreamBuffering = true; 813 request.AllowWriteStreamBuffering = true;
814 request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; 814 request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
815 request.Method = WebRequestMethods.Http.Post; 815 request.Method = WebRequestMethods.Http.Post;
816 // set the content type based on chosen output filers 816 // set the content type based on chosen output filers
817 switch (vassalConfiguration.OutputFilters.Last()) 817 switch (vassalConfiguration.OutputFilters.Last())
818 { 818 {
819 case Filter.RFC1738: 819 case Filter.RFC1738:
820 request.ContentType = VASSAL_CONSTANTS.CONTENT_TYPE.WWW_FORM_URLENCODED; 820 request.ContentType = VASSAL_CONSTANTS.CONTENT_TYPE.WWW_FORM_URLENCODED;
821 break; 821 break;
822 default: 822 default:
823 request.ContentType = VASSAL_CONSTANTS.CONTENT_TYPE.TEXT_PLAIN; 823 request.ContentType = VASSAL_CONSTANTS.CONTENT_TYPE.TEXT_PLAIN;
824 break; 824 break;
825 } 825 }
826 // send request 826 // send request
827 using (Stream requestStream = request.GetRequestStream()) 827 using (Stream requestStream = request.GetRequestStream())
828 { 828 {
829 using (StreamWriter dataStream = new StreamWriter(requestStream)) 829 using (StreamWriter dataStream = new StreamWriter(requestStream))
830 { 830 {
831 dataStream.Write(wasKeyValueEncode(message)); 831 dataStream.Write(wasKeyValueEncode(message));
832 } 832 }
833 } 833 }
834 // read response 834 // read response
835 using (HttpWebResponse response = (HttpWebResponse) request.GetResponse()) 835 using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
836 { 836 {
837 using (Stream responseStream = response.GetResponseStream()) 837 using (Stream responseStream = response.GetResponseStream())
838 { 838 {
839 if (responseStream != null) 839 if (responseStream != null)
840 { 840 {
841 using ( 841 using (
842 StreamReader streamReader = new StreamReader(responseStream)) 842 StreamReader streamReader = new StreamReader(responseStream))
843 { 843 {
844 return streamReader.ReadToEnd(); 844 return streamReader.ReadToEnd();
845 } 845 }
846 } 846 }
847 } 847 }
848 } 848 }
849 } 849 }
850 catch (Exception) 850 catch (Exception)
851 { 851 {
852   852  
853 } 853 }
854   854  
855 return null; 855 return null;
856 } 856 }
857   857  
858 /// <summary> 858 /// <summary>
859 /// Constants used by Corrade. 859 /// Constants used by Corrade.
860 /// </summary> 860 /// </summary>
861 public struct VASSAL_CONSTANTS 861 public struct VASSAL_CONSTANTS
862 { 862 {
863 /// <summary> 863 /// <summary>
864 /// Copyright. 864 /// Copyright.
865 /// </summary> 865 /// </summary>
866 public const string COPYRIGHT = @"(c) Copyright 2013 Wizardry and Steamworks"; 866 public const string COPYRIGHT = @"(c) Copyright 2013 Wizardry and Steamworks";
867   867  
868 public const string WIZARDRY_AND_STEAMWORKS = @"Wizardry and Steamworks"; 868 public const string WIZARDRY_AND_STEAMWORKS = @"Wizardry and Steamworks";
869 public const string VASSAL = @"Vassal"; 869 public const string VASSAL = @"Vassal";
870 public const string WIZARDRY_AND_STEAMWORKS_WEBSITE = @"http://grimore.org"; 870 public const string WIZARDRY_AND_STEAMWORKS_WEBSITE = @"http://grimore.org";
871   871  
872 /// <summary> 872 /// <summary>
873 /// Vassal version. 873 /// Vassal version.
874 /// </summary> 874 /// </summary>
875 public static readonly string VASSAL_VERSION = Assembly.GetEntryAssembly().GetName().Version.ToString(); 875 public static readonly string VASSAL_VERSION = Assembly.GetEntryAssembly().GetName().Version.ToString();
876   876  
877 /// <summary> 877 /// <summary>
878 /// Corrade user agent. 878 /// Corrade user agent.
879 /// </summary> 879 /// </summary>
880 public static readonly string USER_AGENT = 880 public static readonly string USER_AGENT =
881 $"{VASSAL}/{VASSAL_VERSION} ({WIZARDRY_AND_STEAMWORKS_WEBSITE})"; 881 $"{VASSAL}/{VASSAL_VERSION} ({WIZARDRY_AND_STEAMWORKS_WEBSITE})";
882   882  
883 /// <summary> 883 /// <summary>
884 /// Vassal compile date. 884 /// Vassal compile date.
885 /// </summary> 885 /// </summary>
886 public static readonly string VASSAL_COMPILE_DATE = new DateTime(2000, 1, 1).Add(new TimeSpan( 886 public static readonly string VASSAL_COMPILE_DATE = new DateTime(2000, 1, 1).Add(new TimeSpan(
887 TimeSpan.TicksPerDay*Assembly.GetEntryAssembly().GetName().Version.Build + // days since 1 January 2000 887 TimeSpan.TicksPerDay*Assembly.GetEntryAssembly().GetName().Version.Build + // days since 1 January 2000
888 TimeSpan.TicksPerSecond*2*Assembly.GetEntryAssembly().GetName().Version.Revision)).ToLongDateString(); 888 TimeSpan.TicksPerSecond*2*Assembly.GetEntryAssembly().GetName().Version.Revision)).ToLongDateString();
889   889  
890 /// <summary> 890 /// <summary>
891 /// Vassal configuration file. 891 /// Vassal configuration file.
892 /// </summary> 892 /// </summary>
893 public static readonly string VASSAL_CONFIGURATION_FILE = @"Vassal.ini"; 893 public static readonly string VASSAL_CONFIGURATION_FILE = @"Vassal.ini";
894   894  
895 /// <summary> 895 /// <summary>
896 /// Vassal regions file. 896 /// Vassal regions file.
897 /// </summary> 897 /// </summary>
898 public static readonly string VASSAL_REGIONS = @"Regions.csv"; 898 public static readonly string VASSAL_REGIONS = @"Regions.csv";
899   899  
900 /// <summary> 900 /// <summary>
901 /// Conten-types that Corrade can send and receive. 901 /// Conten-types that Corrade can send and receive.
902 /// </summary> 902 /// </summary>
903 public struct CONTENT_TYPE 903 public struct CONTENT_TYPE
904 { 904 {
905 public const string TEXT_PLAIN = @"text/plain"; 905 public const string TEXT_PLAIN = @"text/plain";
906 public const string WWW_FORM_URLENCODED = @"application/x-www-form-urlencoded"; 906 public const string WWW_FORM_URLENCODED = @"application/x-www-form-urlencoded";
907 } 907 }
908 } 908 }
909   909  
910 private static readonly System.Action updateCurrentRegionName = () => 910 private static readonly System.Action updateCurrentRegionName = () =>
911 { 911 {
912 try 912 try
913 { 913 {
914 string result = wasPOST(vassalConfiguration.HTTPServerURL, 914 string result = wasPOST(vassalConfiguration.HTTPServerURL,
915 wasKeyValueEscape(new Dictionary<string, string> 915 wasKeyValueEscape(new Dictionary<string, string>
916 { 916 {
917 {"command", "getregiondata"}, 917 {"command", "getregiondata"},
918 {"group", vassalConfiguration.Group}, 918 {"group", vassalConfiguration.Group},
919 {"password", vassalConfiguration.Password}, 919 {"password", vassalConfiguration.Password},
920 {"data", "Name"} 920 {"data", "Name"}
921 }), 60000); 921 }), 60000);
922 bool success; 922 bool success;
923 if (string.IsNullOrEmpty(result) || 923 if (string.IsNullOrEmpty(result) ||
924 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 924 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
925 { 925 {
926 vassalForm.BeginInvoke((MethodInvoker)(() => 926 vassalForm.BeginInvoke((MethodInvoker) (() =>
927 { 927 {
928 vassalForm.StatusText.Text = @"Failed to query Corrade for current region."; 928 vassalForm.StatusText.Text = @"Failed to query Corrade for current region.";
929 })); 929 }));
930 return; 930 return;
931 } 931 }
932 switch (success) 932 switch (success)
933 { 933 {
934 case true: 934 case true:
935 vassalForm.BeginInvoke((MethodInvoker)(() => 935 vassalForm.BeginInvoke((MethodInvoker) (() =>
936 { 936 {
937 vassalForm.CurrentRegionAt.Visible = true; 937 vassalForm.CurrentRegionAt.Visible = true;
938 vassalForm.CurrentRegionName.Visible = true; 938 vassalForm.CurrentRegionName.Visible = true;
939 vassalForm.CurrentRegionName.Text = 939 vassalForm.CurrentRegionName.Text =
940 wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).Last(); 940 wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).Last();
941 })); 941 }));
942 break; 942 break;
943 default: 943 default:
944 vassalForm.BeginInvoke((MethodInvoker)(() => 944 vassalForm.BeginInvoke((MethodInvoker) (() =>
945 { 945 {
946 vassalForm.CurrentRegionAt.Visible = false; 946 vassalForm.CurrentRegionAt.Visible = false;
947 vassalForm.CurrentRegionName.Visible = false; 947 vassalForm.CurrentRegionName.Visible = false;
948 vassalForm.StatusText.Text = @"Error getting current region: " + 948 vassalForm.StatusText.Text = @"Error getting current region: " +
949 wasInput(wasKeyValueGet("error", result)); 949 wasInput(wasKeyValueGet("error", result));
950 })); 950 }));
951 break; 951 break;
952 } 952 }
953 } 953 }
954 catch (Exception ex) 954 catch (Exception ex)
955 { 955 {
956 vassalForm.BeginInvoke((MethodInvoker)(() => 956 vassalForm.BeginInvoke((MethodInvoker) (() =>
957 { 957 {
958 vassalForm.StatusText.Text = 958 vassalForm.StatusText.Text =
959 @"Error getting current region: " + 959 @"Error getting current region: " +
960 ex.Message; 960 ex.Message;
961 })); 961 }));
962 } 962 }
963 }; 963 };
964   964  
965 public Vassal() 965 public Vassal()
966 { 966 {
967 InitializeComponent(); 967 InitializeComponent();
968 vassalForm = this; 968 vassalForm = this;
969 } 969 }
970   970  
971 private void RegionSelected(object sender, EventArgs e) 971 private void RegionSelected(object sender, EventArgs e)
972 { 972 {
-   973 string selectedRegionName = string.Empty;
-   974 Vector3 selectedRegionPosition = Vector3.Zero;
973 ListViewItem listViewItem = null; 975 bool startTeleport = false;
974 vassalForm.Invoke((MethodInvoker) (() => 976 vassalForm.Invoke((MethodInvoker) (() =>
975 { 977 {
976 listViewItem = LoadedRegions.SelectedItem as ListViewItem; 978 ListViewItem listViewItem = LoadedRegions.SelectedItem as ListViewItem;
-   979 switch (listViewItem != null && LoadedRegions.SelectedIndex != -1)
-   980 {
-   981 case true:
-   982 selectedRegionName = listViewItem.Text;
-   983 selectedRegionPosition = (Vector3)listViewItem.Tag;
-   984 startTeleport = true;
-   985 break;
-   986 default:
-   987 startTeleport = false;
-   988 break;
-   989 }
977 })); 990 }));
978   991  
-   992 if (!startTeleport) return;
-   993
-   994  
-   995 // Announce teleport.
979 switch (listViewItem != null) 996 vassalForm.Invoke((MethodInvoker)(() =>
980 { 997 {
981 case true: 998 vassalForm.RegionTeleportGroup.Enabled = false;
982 vassalForm.Invoke((MethodInvoker) (() => -  
983 { 999 vassalForm.StatusProgress.Value = 0;
984 vassalForm.StatusText.Text = @"Teleporting to " + -  
985 listViewItem.Text; -  
986 })); -  
987 break; -  
988 default: -  
989 return; 1000 vassalForm.StatusText.Text = @"Teleporting to " + selectedRegionName;
990 } 1001 }));
991   1002  
992 new Thread(() => 1003 new Thread(() =>
993 { 1004 {
994 lock (ClientInstanceTeleportLock) 1005 Monitor.Enter(ClientInstanceTeleportLock);
-   1006 try
995 { 1007 {
996 try 1008 int elapsedSeconds = 0;
-   1009 System.Timers.Timer teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
-   1010 teleportTimer.Elapsed += (o, p) =>
997 { 1011 {
998 vassalForm.Invoke((MethodInvoker) (() => 1012 vassalForm.Invoke((MethodInvoker) (() =>
999 { 1013 {
1000 vassalForm.RegionTeleportGroup.Enabled = false; 1014 vassalForm.StatusProgress.Value =
-   1015 Math.Min(
-   1016 (int)
-   1017 (100d*
-   1018 (TimeSpan.FromSeconds(++elapsedSeconds).TotalMilliseconds/
1001 vassalForm.StatusProgress.Value = 0; 1019 vassalConfiguration.TeleportTimeout)), 100);
1002 })); 1020 }));
-   1021 };
-   1022 teleportTimer.Start();
-   1023 string result = null;
-   1024 ManualResetEvent receivedPOST = new ManualResetEvent(false);
-   1025 new Thread(() =>
-   1026 {
-   1027 result = wasInput(wasPOST(vassalConfiguration.HTTPServerURL,
-   1028 wasKeyValueEscape(new Dictionary<string, string>
-   1029 {
-   1030 {"command", "teleport"},
-   1031 {"group", vassalConfiguration.Group},
-   1032 {"password", vassalConfiguration.Password},
-   1033 {"region", selectedRegionName},
-   1034 {"position", selectedRegionPosition.ToString()},
-   1035 {"fly", "True"}
-   1036 }), vassalConfiguration.TeleportTimeout));
1003 int elapsedSeconds = 0; 1037 receivedPOST.Set();
-   1038 }) {IsBackground = true}.Start();
1004 System.Timers.Timer teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds); 1039 receivedPOST.WaitOne((int) vassalConfiguration.TeleportTimeout, false);
1005 teleportTimer.Elapsed += (o, p) => 1040 teleportTimer.Stop();
-   1041 switch (!string.IsNullOrEmpty(result) && wasKeyValueGet("success", result) == "True")
1006 { 1042 {
-   1043 case true:
1007 vassalForm.Invoke((MethodInvoker) (() => 1044 vassalForm.Invoke((MethodInvoker) (() =>
1008 { 1045 {
1009 vassalForm.StatusProgress.Value = 1046 vassalForm.StatusText.Text = @"Now at " + selectedRegionName;
1010 Math.Min( -  
1011 (int) -  
1012 (100d* -  
1013 (TimeSpan.FromSeconds(++elapsedSeconds).TotalMilliseconds/ -  
1014 vassalConfiguration.TeleportTimeout)), 100); 1047 vassalForm.CurrentRegionName.Text = selectedRegionName;
1015 })); 1048 }));
1016 }; -  
1017 teleportTimer.Start(); -  
1018 string result = null; -  
1019 ManualResetEvent receivedPOST = new ManualResetEvent(false); -  
1020 new Thread(() => -  
1021 { -  
1022 result = wasInput(wasPOST(vassalConfiguration.HTTPServerURL, -  
1023 wasKeyValueEscape(new Dictionary<string, string> -  
1024 { -  
1025 {"command", "teleport"}, -  
1026 {"group", vassalConfiguration.Group}, -  
1027 {"password", vassalConfiguration.Password}, -  
1028 {"region", listViewItem.Text}, -  
1029 {"position", ((Vector3) listViewItem.Tag).ToString()}, -  
1030 {"fly", "True"} -  
1031 }), vassalConfiguration.TeleportTimeout)); -  
1032 receivedPOST.Set(); -  
1033 }) {IsBackground = true}.Start(); -  
1034 receivedPOST.WaitOne((int) vassalConfiguration.TeleportTimeout, false); -  
1035 teleportTimer.Stop(); -  
1036 switch (!string.IsNullOrEmpty(result) && wasKeyValueGet("success", result) == "True") -  
1037 { -  
1038 case true: -  
1039 vassalForm.Invoke((MethodInvoker) (() => -  
1040 { -  
1041 vassalForm.StatusText.Text = @"Now at " + listViewItem.Text; -  
1042 })); -  
1043 break; 1049 break;
1044 default: 1050 default:
1045 switch (!string.IsNullOrEmpty(result)) 1051 switch (!string.IsNullOrEmpty(result))
1046 { -  
1047 case true: -  
1048 vassalForm.Invoke((MethodInvoker) (() => -  
1049 { -  
1050 vassalForm.StatusText.Text = @"Failed teleporting to " + listViewItem.Text + -  
1051 @": " + -  
1052 wasKeyValueGet("error", result); -  
1053 })); -  
1054 break; -  
1055 default: -  
1056 vassalForm.Invoke((MethodInvoker) (() => -  
1057 { -  
1058 vassalForm.StatusText.Text = @"Failed teleporting to " + listViewItem.Text; -  
1059 })); -  
1060 break; -  
1061 } -  
1062 break; -  
1063 } -  
1064 } -  
1065 catch (Exception ex) -  
1066 { -  
1067 vassalForm.Invoke((MethodInvoker) (() => -  
1068 { -  
1069 vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message; -  
1070 })); -  
1071 } -  
1072 finally -  
1073 { -  
1074 vassalForm.Invoke((MethodInvoker) (() => -  
1075 { -  
1076 vassalForm.StatusProgress.Value = 100; -  
1077 vassalForm.RegionTeleportGroup.Enabled = true; -  
1078 // Set the map image to the loading spinner. -  
1079 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly(); -  
1080 System.IO.Stream file = -  
1081 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif"); -  
1082 switch (file != null) -  
1083 { 1052 {
1084 case true: 1053 case true:
1085 vassalForm.Invoke((MethodInvoker)(() => 1054 vassalForm.Invoke((MethodInvoker) (() =>
-   1055 {
-   1056 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName +
-   1057 @": " +
-   1058 wasKeyValueGet("error", result);
-   1059 }));
-   1060 break;
-   1061 default:
-   1062 vassalForm.Invoke((MethodInvoker) (() =>
1086 { 1063 {
1087 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage; 1064 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName;
1088 RegionAvatarsMap.Image = Image.FromStream(file); -  
1089 RegionAvatarsMap.Refresh(); -  
1090 })); 1065 }));
1091 break; 1066 break;
1092 } 1067 }
1093 // Clear the top scripts table. -  
1094 TopScriptsGridView.Rows.Clear(); -  
1095 // Clear the top colliders table. -  
1096 TopCollidersGridView.Rows.Clear(); -  
1097 })); 1068 break;
1098 updateCurrentRegionName.BeginInvoke(updateCurrentRegionName.EndInvoke, null); -  
1099 } 1069 }
1100 } 1070 }
-   1071 catch (Exception ex)
-   1072 {
-   1073 vassalForm.Invoke((MethodInvoker) (() =>
-   1074 {
-   1075 vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message;
-   1076 }));
-   1077 }
-   1078 finally
-   1079 {
-   1080 Monitor.Exit(ClientInstanceTeleportLock);
-   1081 vassalForm.Invoke((MethodInvoker) (() =>
-   1082 {
-   1083 vassalForm.StatusProgress.Value = 100;
-   1084 vassalForm.RegionTeleportGroup.Enabled = true;
-   1085 // Set the map image to the loading spinner.
-   1086 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
-   1087 System.IO.Stream file =
-   1088 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
-   1089 switch (file != null)
-   1090 {
-   1091 case true:
-   1092 vassalForm.Invoke((MethodInvoker) (() =>
-   1093 {
-   1094 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
-   1095 RegionAvatarsMap.Image = Image.FromStream(file);
-   1096 RegionAvatarsMap.Refresh();
-   1097 }));
-   1098 break;
-   1099 }
-   1100 // Clear the top scripts table.
-   1101 TopScriptsGridView.Rows.Clear();
-   1102 // Clear the top colliders table.
-   1103 TopCollidersGridView.Rows.Clear();
-   1104 // Invalidate data for overview tab.
-   1105 vassalForm.CurrentRegionAt.Visible = false;
-   1106 vassalForm.CurrentRegionName.Visible = false;
-   1107 Agents.Text = string.Empty;
-   1108 Agents.Enabled = false;
-   1109 LastLag.Text = string.Empty;
-   1110 LastLag.Enabled = false;
-   1111 Dilation.Text = string.Empty;
-   1112 Dilation.Enabled = false;
-   1113 FPS.Text = string.Empty;
-   1114 FPS.Enabled = false;
-   1115 PhysicsFPS.Text = string.Empty;
-   1116 PhysicsFPS.Enabled = false;
-   1117 ActiveScripts.Text = string.Empty;
-   1118 ActiveScripts.Enabled = false;
-   1119 ScriptTime.Text = string.Empty;
-   1120 ScriptTime.Enabled = false;
-   1121 Objects.Text = string.Empty;
-   1122 Objects.Enabled = false;
-   1123 }));
-   1124 }
1101 }).Start(); 1125 }).Start();
1102 1126  
1103 } 1127 }
1104   1128  
1105 private void SettingsRequested(object sender, EventArgs e) 1129 private void SettingsRequested(object sender, EventArgs e)
1106 { 1130 {
1107 SettingsForm settingsForm = new SettingsForm {TopMost = true}; 1131 SettingsForm settingsForm = new SettingsForm {TopMost = true};
1108 settingsForm.Show(); 1132 settingsForm.Show();
1109 } 1133 }
1110   1134  
1111 private void VassalShown(object sender, EventArgs e) 1135 private void VassalShown(object sender, EventArgs e)
1112 { 1136 {
-   1137 // Set the version
-   1138 vassalForm.Version.Text = @"v" + VASSAL_CONSTANTS.VASSAL_VERSION;
-   1139  
1113 // Get the configuration file settings if it exists. 1140 // Get the configuration file settings if it exists.
1114 if (File.Exists(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE)) 1141 if (File.Exists(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE))
1115 { 1142 {
1116 VassalConfiguration.Load(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE, ref vassalConfiguration); 1143 VassalConfiguration.Load(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE, ref vassalConfiguration);
1117 } 1144 }
1118   1145  
1119 // Get all the regions if they exist. 1146 // Get all the regions if they exist.
1120 if (File.Exists(VASSAL_CONSTANTS.VASSAL_REGIONS)) 1147 if (File.Exists(VASSAL_CONSTANTS.VASSAL_REGIONS))
1121 { 1148 {
1122 Vector3 localPosition; 1149 Vector3 localPosition;
1123 ConfiguredRegions = 1150 List<KeyValuePair<string, Vector3>> ConfiguredRegions = new List<KeyValuePair<string, Vector3>>(
1124 File.ReadAllLines(VASSAL_CONSTANTS.VASSAL_REGIONS) 1151 File.ReadAllLines(VASSAL_CONSTANTS.VASSAL_REGIONS)
1125 .Select(o => new List<string>(wasCSVToEnumerable(o))) 1152 .Select(o => new List<string>(wasCSVToEnumerable(o)))
1126 .Where(o => o.Count == 2) 1153 .Where(o => o.Count == 2)
1127 .ToDictionary(o => o.First(), 1154 .ToDictionary(o => o.First(),
1128 p => 1155 p =>
1129 Vector3.TryParse(p.Last(), out localPosition) 1156 Vector3.TryParse(p.Last(), out localPosition)
1130 ? localPosition 1157 ? localPosition
1131 : Vector3.Zero).OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value); 1158 : Vector3.Zero).OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value));
-   1159 // Populate the loaded regions.
1132 LoadedRegions.Items.Clear(); 1160 LoadedRegions.Items.Clear();
1133 LoadedRegions.Items.AddRange( 1161 LoadedRegions.Items.AddRange(
1134 ConfiguredRegions.Select(o => (object)new ListViewItem {Text = o.Key, Tag = o.Value}) 1162 ConfiguredRegions.Select(o => (object) new ListViewItem {Text = o.Key, Tag = o.Value})
1135 .ToArray()); 1163 .ToArray());
1136 } 1164 // Populate the batch restart grid view.
1137   -  
1138 // Update the current region in case the configuration is initialized. 1165 BatchRestartGridView.Rows.Clear();
1139 if (!vassalConfiguration.Equals(default(VassalConfiguration))) 1166 foreach (KeyValuePair<string, Vector3> data in ConfiguredRegions)
1140 { 1167 {
1141 updateCurrentRegionName.BeginInvoke(updateCurrentRegionName.EndInvoke, null); 1168 BatchRestartGridView.Rows.Add(data.Key, data.Value.ToString());
-   1169 }
1142 } 1170 }
1143   1171  
1144 // Set the map image to the loading spinner. 1172 // Set the map image to the loading spinner.
1145 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly(); 1173 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
1146 System.IO.Stream file = 1174 System.IO.Stream file =
1147 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif"); 1175 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
1148 switch (file != null) 1176 switch (file != null)
1149 { 1177 {
1150 case true: 1178 case true:
1151 vassalForm.Invoke((MethodInvoker)(() => 1179 vassalForm.Invoke((MethodInvoker) (() =>
1152 { 1180 {
1153 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage; 1181 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
1154 RegionAvatarsMap.Image = Image.FromStream(file); 1182 RegionAvatarsMap.Image = Image.FromStream(file);
1155 RegionAvatarsMap.Refresh(); 1183 RegionAvatarsMap.Refresh();
1156 })); 1184 }));
1157 break; 1185 break;
1158 } 1186 }
1159   1187  
1160 // Start the overview timer. 1188 // Start the overview timer.
1161 overviewTabTimer.Elapsed += (o, p) => 1189 overviewTabTimer.Elapsed += (o, p) =>
1162 { 1190 {
1163 if (!Monitor.TryEnter(ClientInstanceTeleportLock)) 1191 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1164 return; 1192 return;
1165   1193  
1166 try 1194 try
1167 { 1195 {
1168 // Do not do anything in case the tab is not selected. 1196 // Do not do anything in case the tab is not selected.
1169 vassalForm.Invoke((MethodInvoker) (() => 1197 vassalForm.Invoke((MethodInvoker) (() =>
1170 { 1198 {
1171 if (!Tabs.SelectedTab.Equals(OverviewTab)) 1199 if (!Tabs.SelectedTab.Equals(OverviewTab))
1172 throw new Exception(); 1200 throw new Exception();
1173 })); 1201 }));
1174   1202  
1175 // Get the statistics. 1203 // Get the statistics.
1176 string result = wasPOST(vassalConfiguration.HTTPServerURL, 1204 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1177 wasKeyValueEscape(new Dictionary<string, string> 1205 wasKeyValueEscape(new Dictionary<string, string>
1178 { 1206 {
1179 {"command", "getregiondata"}, 1207 {"command", "getregiondata"},
1180 {"group", vassalConfiguration.Group}, 1208 {"group", vassalConfiguration.Group},
1181 {"password", vassalConfiguration.Password}, 1209 {"password", vassalConfiguration.Password},
1182 { 1210 {
1183 "data", wasEnumerableToCSV(new[] 1211 "data", wasEnumerableToCSV(new[]
1184 { 1212 {
1185 "Agents", 1213 "Agents",
1186 "LastLag", 1214 "LastLag",
1187 "Dilation", 1215 "Dilation",
1188 "FPS", 1216 "FPS",
1189 "PhysicsFPS", 1217 "PhysicsFPS",
1190 "ActiveScripts", 1218 "ActiveScripts",
1191 "ScriptTime", 1219 "ScriptTime",
1192 "Objects" 1220 "Objects",
-   1221 "Name"
1193 }) 1222 })
1194 } 1223 }
1195 }), vassalConfiguration.DataTimeout); 1224 }), vassalConfiguration.DataTimeout);
1196   1225  
1197 bool success; 1226 bool success;
1198 if (string.IsNullOrEmpty(result) || 1227 if (string.IsNullOrEmpty(result) ||
1199 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1228 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1200 throw new Exception(); 1229 throw new Exception();
1201   1230  
1202 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList(); 1231 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1203 if (data.Count.Equals(0)) 1232 if (data.Count.Equals(0))
1204 throw new Exception(); 1233 throw new Exception();
1205   1234  
1206 vassalForm.Invoke((MethodInvoker) (() => 1235 vassalForm.Invoke((MethodInvoker) (() =>
1207 { 1236 {
-   1237 // Show the region name.
-   1238 vassalForm.CurrentRegionName.Text = data[data.IndexOf("Name") + 1];
-   1239 vassalForm.CurrentRegionAt.Visible = true;
-   1240 vassalForm.CurrentRegionName.Visible = true;
-   1241  
-   1242 // Populate the overview tab.
1208 Agents.Text = data[data.IndexOf("Agents") + 1]; 1243 Agents.Text = data[data.IndexOf("Agents") + 1];
-   1244 Agents.Enabled = true;
1209 LastLag.Text = data[data.IndexOf("LastLag") + 1]; 1245 LastLag.Text = data[data.IndexOf("LastLag") + 1];
-   1246 LastLag.Enabled = true;
1210 Dilation.Text = data[data.IndexOf("Dilation") + 1]; 1247 Dilation.Text = data[data.IndexOf("Dilation") + 1];
-   1248 Dilation.Enabled = true;
1211 FPS.Text = data[data.IndexOf("FPS") + 1]; 1249 FPS.Text = data[data.IndexOf("FPS") + 1];
-   1250 FPS.Enabled = true;
1212 PhysicsFPS.Text = data[data.IndexOf("PhysicsFPS") + 1]; 1251 PhysicsFPS.Text = data[data.IndexOf("PhysicsFPS") + 1];
-   1252 PhysicsFPS.Enabled = true;
1213 ActiveScripts.Text = data[data.IndexOf("ActiveScripts") + 1]; 1253 ActiveScripts.Text = data[data.IndexOf("ActiveScripts") + 1];
-   1254 ActiveScripts.Enabled = true;
1214 ScriptTime.Text = data[data.IndexOf("ScriptTime") + 1]; 1255 ScriptTime.Text = data[data.IndexOf("ScriptTime") + 1];
-   1256 ScriptTime.Enabled = true;
1215 Objects.Text = data[data.IndexOf("Objects") + 1]; 1257 Objects.Text = data[data.IndexOf("Objects") + 1];
-   1258 Objects.Enabled = true;
1216 })); 1259 }));
1217 1260  
1218 // Get the map image. 1261 // Get the map image.
1219 result = wasPOST(vassalConfiguration.HTTPServerURL, 1262 result = wasPOST(vassalConfiguration.HTTPServerURL,
1220 wasKeyValueEscape(new Dictionary<string, string> 1263 wasKeyValueEscape(new Dictionary<string, string>
1221 { 1264 {
1222 {"command", "getgridregiondata"}, 1265 {"command", "getgridregiondata"},
1223 {"group", vassalConfiguration.Group}, 1266 {"group", vassalConfiguration.Group},
1224 {"password", vassalConfiguration.Password}, 1267 {"password", vassalConfiguration.Password},
1225 { "data", "MapImageID"} 1268 {"data", "MapImageID"}
1226 }), vassalConfiguration.DataTimeout); 1269 }), vassalConfiguration.DataTimeout);
1227 1270  
1228 if (string.IsNullOrEmpty(result) || 1271 if (string.IsNullOrEmpty(result) ||
1229 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1272 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1230 throw new Exception(); 1273 throw new Exception();
1231   1274  
1232 data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList(); 1275 data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1233 if (!data.Count.Equals(2)) 1276 if (!data.Count.Equals(2))
1234 throw new Exception(); 1277 throw new Exception();
1235 result = wasPOST(vassalConfiguration.HTTPServerURL, 1278 result = wasPOST(vassalConfiguration.HTTPServerURL,
1236 wasKeyValueEscape(new Dictionary<string, string> 1279 wasKeyValueEscape(new Dictionary<string, string>
1237 { 1280 {
1238 {"command", "download"}, 1281 {"command", "download"},
1239 {"group", vassalConfiguration.Group}, 1282 {"group", vassalConfiguration.Group},
1240 {"password", vassalConfiguration.Password}, 1283 {"password", vassalConfiguration.Password},
1241 {"item", data.Last() }, 1284 {"item", data.Last()},
1242 {"type", "Texture" }, 1285 {"type", "Texture"},
1243 {"format", "Jpeg" }, 1286 {"format", "Jpeg"},
1244 }), vassalConfiguration.DataTimeout); 1287 }), vassalConfiguration.DataTimeout);
1245 if (string.IsNullOrEmpty(result) || 1288 if (string.IsNullOrEmpty(result) ||
1246 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1289 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1247 throw new Exception(); 1290 throw new Exception();
1248 byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result))); 1291 byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
1249 Image mapImage; 1292 Image mapImage;
1250 using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length)) 1293 using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
1251 { 1294 {
1252 mapImage = Image.FromStream(memoryStream); 1295 mapImage = Image.FromStream(memoryStream);
1253 } 1296 }
1254   1297  
1255 // Get the avatar positions. 1298 // Get the avatar positions.
1256 result = wasPOST(vassalConfiguration.HTTPServerURL, 1299 result = wasPOST(vassalConfiguration.HTTPServerURL,
1257 wasKeyValueEscape(new Dictionary<string, string> 1300 wasKeyValueEscape(new Dictionary<string, string>
1258 { 1301 {
1259 {"command", "getavatarpositions"}, 1302 {"command", "getavatarpositions"},
1260 {"group", vassalConfiguration.Group}, 1303 {"group", vassalConfiguration.Group},
1261 {"password", vassalConfiguration.Password}, 1304 {"password", vassalConfiguration.Password},
1262 { "entity", "region"} 1305 {"entity", "region"}
1263 }), vassalConfiguration.DataTimeout); 1306 }), vassalConfiguration.DataTimeout);
1264   1307  
1265 if (string.IsNullOrEmpty(result) || 1308 if (string.IsNullOrEmpty(result) ||
1266 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1309 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1267 throw new Exception(); 1310 throw new Exception();
1268   1311  
1269 // Every thrid element represents a Vecto3 of the avatar position. 1312 // Every thrid element represents a Vecto3 of the avatar position.
-   1313 data =
1270 data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).Skip(2).Where((x, i) => i % 3 == 0).ToList(); 1314 wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
-   1315 .Skip(2)
-   1316 .Where((x, i) => i%3 == 0)
-   1317 .ToList();
1271   1318  
1272 // Draw the avatars onto the map. 1319 // Draw the avatars onto the map.
1273 Graphics mapGraphics = Graphics.FromImage(mapImage); 1320 Graphics mapGraphics = Graphics.FromImage(mapImage);
1274 Vector3 position; 1321 Vector3 position;
1275 foreach (string vector in data) 1322 foreach (string vector in data)
1276 { 1323 {
1277 switch (Vector3.TryParse(vector, out position)) 1324 switch (Vector3.TryParse(vector, out position))
1278 { 1325 {
1279 case true: 1326 case true:
-   1327 mapGraphics.FillEllipse(Brushes.Chartreuse,
1280 mapGraphics.FillEllipse(Brushes.Chartreuse, new Rectangle((int)position.X, (int)position.Y, 4, 4)); 1328 new Rectangle((int) position.X, (int) position.Y, 4, 4));
1281 break; 1329 break;
1282 } 1330 }
1283 } 1331 }
1284 mapGraphics.DrawImage(mapImage, new Point(0, 0)); 1332 mapGraphics.DrawImage(mapImage, new Point(0, 0));
1285   1333  
1286 vassalForm.Invoke((MethodInvoker) (() => 1334 vassalForm.Invoke((MethodInvoker) (() =>
1287 { 1335 {
1288 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.StretchImage; 1336 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.StretchImage;
1289 RegionAvatarsMap.Image = mapImage; 1337 RegionAvatarsMap.Image = mapImage;
1290 RegionAvatarsMap.Refresh(); 1338 RegionAvatarsMap.Refresh();
1291 })); 1339 }));
1292 } 1340 }
1293 catch (Exception) 1341 catch (Exception)
1294 { 1342 {
1295   1343  
1296 } 1344 }
1297 finally 1345 finally
1298 { 1346 {
1299 Monitor.Exit(ClientInstanceTeleportLock); 1347 Monitor.Exit(ClientInstanceTeleportLock);
1300 } 1348 }
1301 1349  
1302 }; 1350 };
1303 overviewTabTimer.Start(); 1351 overviewTabTimer.Start();
1304   1352  
1305 // Start the top scores timer. 1353 // Start the top scores timer.
1306 topScriptsTabTimer.Elapsed += (o, p) => 1354 topScriptsTabTimer.Elapsed += (o, p) =>
1307 { 1355 {
1308 if (!Monitor.TryEnter(ClientInstanceTeleportLock)) 1356 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1309 return; 1357 return;
1310   1358  
1311 try 1359 try
1312 { 1360 {
1313 // Do not do anything in case the tab is not selected. 1361 // Do not do anything in case the tab is not selected.
1314 vassalForm.Invoke((MethodInvoker) (() => 1362 vassalForm.Invoke((MethodInvoker) (() =>
1315 { 1363 {
1316 if (!Tabs.SelectedTab.Equals(TopScriptsTab)) 1364 if (!Tabs.SelectedTab.Equals(TopScriptsTab))
1317 throw new Exception(); 1365 throw new Exception();
1318 })); 1366 }));
1319   1367  
1320 // Get the statistics. 1368 // Get the statistics.
1321 string result = wasPOST(vassalConfiguration.HTTPServerURL, 1369 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1322 wasKeyValueEscape(new Dictionary<string, string> 1370 wasKeyValueEscape(new Dictionary<string, string>
1323 { 1371 {
1324 {"command", "getregiontop"}, 1372 {"command", "getregiontop"},
1325 {"group", vassalConfiguration.Group}, 1373 {"group", vassalConfiguration.Group},
1326 {"password", vassalConfiguration.Password}, 1374 {"password", vassalConfiguration.Password},
1327 {"type", "scripts"} 1375 {"type", "scripts"}
1328 }), vassalConfiguration.DataTimeout); 1376 }), vassalConfiguration.DataTimeout);
1329   1377  
1330 bool success; 1378 bool success;
1331 if (string.IsNullOrEmpty(result) || 1379 if (string.IsNullOrEmpty(result) ||
1332 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1380 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1333 throw new Exception(); 1381 throw new Exception();
1334   1382  
1335 HashSet<List<string>> data = 1383 HashSet<List<string>> data =
1336 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))) 1384 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1337 .Select((x, i) => new {Index = i, Value = x}) 1385 .Select((x, i) => new {Index = i, Value = x})
1338 .GroupBy(x => x.Index/5) 1386 .GroupBy(x => x.Index/5)
1339 .Select(x => x.Select(v => v.Value).ToList())); 1387 .Select(x => x.Select(v => v.Value).ToList()));
1340 if (data.Count.Equals(0)) 1388 if (data.Count.Equals(0))
1341 throw new Exception(); 1389 throw new Exception();
1342   1390  
1343 vassalForm.Invoke((MethodInvoker) (() => 1391 vassalForm.Invoke((MethodInvoker) (() =>
1344 { 1392 {
-   1393 // Remove rows that are not in the data update.
-   1394 foreach (
-   1395 int index in
1345 switch (!TopScriptsGridView.Rows.Count.Equals(0)) 1396 TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>()
-   1397 .Where(
-   1398 topScriptsRow =>
-   1399 !data.Any(q => q[2].Equals(topScriptsRow.Cells["TopScriptsUUID"].Value)))
-   1400 .Select(q => q.Index))
1346 { 1401 {
-   1402 TopScriptsGridView.Rows.RemoveAt(index);
1347 case true: 1403 }
-   1404 // Now update or add new data.
1348 foreach (DataGridViewRow topScriptsRow in (IEnumerable)TopScriptsGridView.Rows) 1405 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5)))
1349 { 1406 {
-   1407 DataGridViewRow row =
1350 List<string> updateRowData = 1408 TopScriptsGridView.Rows.AsParallel()
1351 data.AsParallel() 1409 .Cast<DataGridViewRow>()
1352 .FirstOrDefault(q => q[2].Equals(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString())); 1410 .FirstOrDefault(q => q.Cells["TopScriptsUUID"].Value.Equals(dataComponents[2]));
1353 switch (updateRowData != null && updateRowData.Count.Equals(5)) 1411 switch (row != null)
1354 { 1412 {
1355 case true: 1413 case true: // the row exists, so update it.
1356 topScriptsRow.Cells["TopScriptsScore"].Value = updateRowData[0]; 1414 row.Cells["TopScriptsScore"].Value = dataComponents[0];
1357 topScriptsRow.Cells["TopScriptsTaskName"].Value = updateRowData[1]; 1415 row.Cells["TopScriptsTaskName"].Value = dataComponents[1];
1358 topScriptsRow.Cells["TopScriptsUUID"].Value = updateRowData[2]; 1416 row.Cells["TopScriptsUUID"].Value = dataComponents[2];
1359 topScriptsRow.Cells["TopScriptsOwner"].Value = updateRowData[3]; 1417 row.Cells["TopScriptsOwner"].Value = dataComponents[3];
1360 topScriptsRow.Cells["TopScriptsPosition"].Value = updateRowData[4]; 1418 row.Cells["TopScriptsPosition"].Value = dataComponents[4];
1361 break; -  
1362 } -  
1363 } -  
1364 break; 1419 break;
1365 default: -  
1366 foreach (List<string> updateRowData in data) 1420 case false: // the row dosn't exist, so add it.
1367 { -  
1368 TopScriptsGridView.Rows.Add(updateRowData[0], updateRowData[1], updateRowData[2], 1421 TopScriptsGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2],
1369 updateRowData[3], updateRowData[4]); 1422 dataComponents[3], dataComponents[4]);
1370 } 1423 break;
1371 break; 1424 }
1372 } 1425 }
1373 -  
1374 })); 1426 }));
1375 } 1427 }
1376 catch (Exception) 1428 catch (Exception)
1377 { 1429 {
1378   1430  
1379 } 1431 }
1380 finally 1432 finally
1381 { 1433 {
1382 Monitor.Exit(ClientInstanceTeleportLock); 1434 Monitor.Exit(ClientInstanceTeleportLock);
1383 } 1435 }
1384 }; 1436 };
1385 topScriptsTabTimer.Start(); 1437 topScriptsTabTimer.Start();
1386   1438  
1387 // Start the top colliders timer. 1439 // Start the top colliders timer.
1388 topCollidersTabTimer.Elapsed += (o, p) => 1440 topCollidersTabTimer.Elapsed += (o, p) =>
1389 { 1441 {
1390 if (!Monitor.TryEnter(ClientInstanceTeleportLock)) 1442 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1391 return; 1443 return;
1392   1444  
1393 try 1445 try
1394 { 1446 {
1395 // Do not do anything in case the tab is not selected. 1447 // Do not do anything in case the tab is not selected.
1396 vassalForm.Invoke((MethodInvoker)(() => 1448 vassalForm.Invoke((MethodInvoker) (() =>
1397 { 1449 {
1398 if (!Tabs.SelectedTab.Equals(TopCollidersTab)) 1450 if (!Tabs.SelectedTab.Equals(TopCollidersTab))
1399 throw new Exception(); 1451 throw new Exception();
1400 })); 1452 }));
1401   1453  
1402 // Get the statistics. 1454 // Get the statistics.
1403 string result = wasPOST(vassalConfiguration.HTTPServerURL, 1455 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1404 wasKeyValueEscape(new Dictionary<string, string> 1456 wasKeyValueEscape(new Dictionary<string, string>
1405 { 1457 {
1406 {"command", "getregiontop"}, 1458 {"command", "getregiontop"},
1407 {"group", vassalConfiguration.Group}, 1459 {"group", vassalConfiguration.Group},
1408 {"password", vassalConfiguration.Password}, 1460 {"password", vassalConfiguration.Password},
1409 {"type", "colliders"} 1461 {"type", "colliders"}
1410 }), vassalConfiguration.DataTimeout); 1462 }), vassalConfiguration.DataTimeout);
1411   1463  
1412 bool success; 1464 bool success;
1413 if (string.IsNullOrEmpty(result) || 1465 if (string.IsNullOrEmpty(result) ||
1414 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1466 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1415 throw new Exception(); 1467 throw new Exception();
1416   1468  
1417 HashSet<List<string>> data = 1469 HashSet<List<string>> data =
1418 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))) 1470 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1419 .Select((x, i) => new { Index = i, Value = x }) 1471 .Select((x, i) => new {Index = i, Value = x})
1420 .GroupBy(x => x.Index / 5) 1472 .GroupBy(x => x.Index/5)
1421 .Select(x => x.Select(v => v.Value).ToList())); 1473 .Select(x => x.Select(v => v.Value).ToList()));
1422 if (data.Count.Equals(0)) 1474 if (data.Count.Equals(0))
1423 throw new Exception(); 1475 throw new Exception();
1424   1476  
1425 vassalForm.Invoke((MethodInvoker)(() => 1477 vassalForm.Invoke((MethodInvoker) (() =>
-   1478 {
-   1479 // Remove rows that are not in the data update.
-   1480 foreach (
1426 { 1481 int index in
-   1482 TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>()
-   1483 .Where(
-   1484 topCollidersRow =>
-   1485 !data.Any(q => q[2].Equals(topCollidersRow.Cells["TopCollidersUUID"].Value)))
1427 switch (!TopCollidersGridView.Rows.Count.Equals(0)) 1486 .Select(q => q.Index))
-   1487 {
1428 { 1488 TopCollidersGridView.Rows.RemoveAt(index);
-   1489 }
1429 case true: 1490 // Now update or add new data.
1430 foreach (DataGridViewRow topCollidersRow in (IEnumerable)TopCollidersGridView.Rows) 1491 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5)))
1431 { 1492 {
-   1493 DataGridViewRow row =
1432 List<string> updateRowData = 1494 TopCollidersGridView.Rows.AsParallel()
1433 data.AsParallel() 1495 .Cast<DataGridViewRow>()
1434 .FirstOrDefault(q => q[2].Equals(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString())); 1496 .FirstOrDefault(q => q.Cells["TopCollidersUUID"].Value.Equals(dataComponents[2]));
1435 switch (updateRowData != null && updateRowData.Count.Equals(5)) 1497 switch (row != null)
1436 { 1498 {
1437 case true: 1499 case true: // the row exists, so update it.
1438 topCollidersRow.Cells["TopCollidersScore"].Value = updateRowData[0]; 1500 row.Cells["TopCollidersScore"].Value = dataComponents[0];
1439 topCollidersRow.Cells["TopCollidersTaskName"].Value = updateRowData[1]; 1501 row.Cells["TopSCollidersTaskName"].Value = dataComponents[1];
1440 topCollidersRow.Cells["TopCollidersUUID"].Value = updateRowData[2]; 1502 row.Cells["TopCollidersUUID"].Value = dataComponents[2];
1441 topCollidersRow.Cells["TopCollidersOwner"].Value = updateRowData[3]; 1503 row.Cells["TopCollidersOwner"].Value = dataComponents[3];
1442 topCollidersRow.Cells["TopCollidersPosition"].Value = updateRowData[4]; -  
1443 break; -  
1444 } -  
1445 } 1504 row.Cells["TopCollidersPosition"].Value = dataComponents[4];
1446 break; -  
1447 default: 1505 break;
1448 foreach (List<string> updateRowData in data) -  
1449 { 1506 case false: // the row dosn't exist, so add it.
1450 TopCollidersGridView.Rows.Add(updateRowData[0], updateRowData[1], updateRowData[2], 1507 TopCollidersGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2],
1451 updateRowData[3], updateRowData[4]); 1508 dataComponents[3], dataComponents[4]);
1452 } 1509 break;
1453 break; 1510 }
1454 } 1511 }
1455   1512  
1456 })); 1513 }));
1457 } 1514 }
1458 catch (Exception) 1515 catch (Exception)
1459 { 1516 {
1460   1517  
1461 } 1518 }
1462 finally 1519 finally
1463 { 1520 {
1464 Monitor.Exit(ClientInstanceTeleportLock); 1521 Monitor.Exit(ClientInstanceTeleportLock);
1465 } 1522 }
1466 }; 1523 };
1467 topCollidersTabTimer.Start(); 1524 topCollidersTabTimer.Start();
1468 } 1525 }
1469   1526  
1470 private void RequestedEditRegions(object sender, EventArgs e) 1527 private void RequestedEditRegions(object sender, EventArgs e)
1471 { 1528 {
1472 // Clear any selection. 1529 // Clear any selection.
1473 LoadedRegions.SelectedIndex = -1; 1530 LoadedRegions.SelectedIndex = -1;
1474 RegionEditForm regionEditForm = new RegionEditForm { TopMost = true }; 1531 RegionEditForm regionEditForm = new RegionEditForm {TopMost = true};
1475 regionEditForm.Show(); 1532 regionEditForm.Show();
1476 } 1533 }
1477   1534  
1478 private void RequestSelecting(object sender, TabControlCancelEventArgs e) 1535 private void RequestSelecting(object sender, TabControlCancelEventArgs e)
1479 { 1536 {
1480 e.Cancel = !e.TabPage.Enabled; 1537 e.Cancel = !e.TabPage.Enabled;
1481 } 1538 }
-   1539  
-   1540 private void RequestExportTopScripts(object sender, EventArgs e)
-   1541 {
-   1542 vassalForm.BeginInvoke((MethodInvoker) (() =>
-   1543 {
-   1544 switch (vassalForm.ExportCSVDialog.ShowDialog())
-   1545 {
-   1546 case DialogResult.OK:
-   1547 string file = vassalForm.ExportCSVDialog.FileName;
-   1548 new Thread(() =>
-   1549 {
-   1550 vassalForm.BeginInvoke((MethodInvoker) (() =>
-   1551 {
-   1552 try
-   1553 {
-   1554 vassalForm.StatusText.Text = @"exporting...";
-   1555 vassalForm.StatusProgress.Value = 0;
-   1556  
-   1557 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
-   1558 {
-   1559 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows)
-   1560 {
-   1561 streamWriter.WriteLine(wasEnumerableToCSV(new[]
-   1562 {
-   1563 topScriptsRow.Cells["TopScriptsScore"].Value.ToString(),
-   1564 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString(),
-   1565 topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(),
-   1566 topScriptsRow.Cells["TopScriptsOwner"].Value.ToString(),
-   1567 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString()
-   1568 }));
-   1569 }
-   1570 }
-   1571  
-   1572 vassalForm.StatusText.Text = @"exported";
-   1573 vassalForm.StatusProgress.Value = 100;
-   1574 }
-   1575 catch (Exception ex)
-   1576 {
-   1577 vassalForm.StatusText.Text = ex.Message;
-   1578 }
-   1579 }));
-   1580 })
-   1581 {IsBackground = true, Priority = ThreadPriority.Normal}.Start();
-   1582 break;
-   1583 }
-   1584 }));
-   1585 }
-   1586  
-   1587 private void RequestExportTopColliders(object sender, EventArgs e)
-   1588 {
-   1589 vassalForm.BeginInvoke((MethodInvoker) (() =>
-   1590 {
-   1591 switch (vassalForm.ExportCSVDialog.ShowDialog())
-   1592 {
-   1593 case DialogResult.OK:
-   1594 string file = vassalForm.ExportCSVDialog.FileName;
-   1595 new Thread(() =>
-   1596 {
-   1597 vassalForm.BeginInvoke((MethodInvoker) (() =>
-   1598 {
-   1599 try
-   1600 {
-   1601 vassalForm.StatusText.Text = @"exporting...";
-   1602 vassalForm.StatusProgress.Value = 0;
-   1603  
-   1604 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
-   1605 {
-   1606 foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows)
-   1607 {
-   1608 streamWriter.WriteLine(wasEnumerableToCSV(new[]
-   1609 {
-   1610 topCollidersRow.Cells["TopCollidersScore"].Value.ToString(),
-   1611 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString(),
-   1612 topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(),
-   1613 topCollidersRow.Cells["TopCollidersOwner"].Value.ToString(),
-   1614 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString()
-   1615 }));
-   1616 }
-   1617 }
-   1618  
-   1619 vassalForm.StatusText.Text = @"exported";
-   1620 vassalForm.StatusProgress.Value = 100;
-   1621 }
-   1622 catch (Exception ex)
-   1623 {
-   1624 vassalForm.StatusText.Text = ex.Message;
-   1625 }
-   1626 }));
-   1627 })
-   1628 {IsBackground = true, Priority = ThreadPriority.Normal}.Start();
-   1629 break;
-   1630 }
-   1631 }));
-   1632 }
-   1633  
-   1634 private void RequestFilterTopScripts(object sender, EventArgs e)
-   1635 {
-   1636 vassalForm.BeginInvoke((MethodInvoker) (() =>
-   1637 {
-   1638 Regex topScriptsRowRegex;
-   1639 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
-   1640 {
-   1641 case true:
-   1642 topScriptsRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
-   1643 break;
-   1644 default:
-   1645 topScriptsRowRegex = new Regex(@".+?", RegexOptions.Compiled);
-   1646 break;
-   1647 }
-   1648 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>())
-   1649 {
-   1650 topScriptsRow.Visible =
-   1651 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsScore"].Value.ToString()) ||
-   1652 topScriptsRowRegex.IsMatch(
-   1653 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString()) ||
-   1654 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString()) ||
-   1655 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsOwner"].Value.ToString()) ||
-   1656 topScriptsRowRegex.IsMatch(
-   1657 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString());
-   1658 }
-   1659 }));
-   1660 }
-   1661  
-   1662 private void RequestFilterTopColliders(object sender, EventArgs e)
-   1663 {
-   1664 vassalForm.BeginInvoke((MethodInvoker)(() =>
-   1665 {
-   1666 Regex topCollidersRowRegex;
-   1667 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
-   1668 {
-   1669 case true:
-   1670 topCollidersRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
-   1671 break;
-   1672 default:
-   1673 topCollidersRowRegex = new Regex(@".+?", RegexOptions.Compiled);
-   1674 break;
-   1675 }
-   1676 foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>())
-   1677 {
-   1678 topCollidersRow.Visible =
-   1679 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersScore"].Value.ToString()) ||
-   1680 topCollidersRowRegex.IsMatch(
-   1681 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString()) ||
-   1682 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString()) ||
-   1683 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersOwner"].Value.ToString()) ||
-   1684 topCollidersRowRegex.IsMatch(
-   1685 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString());
-   1686 }
-   1687 }));
-   1688 }
-   1689  
-   1690 private void RequestReturnTopScriptsObjects(object sender, EventArgs e)
-   1691 {
-   1692 // Block teleports and disable button.
-   1693 vassalForm.Invoke((MethodInvoker) (() =>
-   1694 {
-   1695 vassalForm.ReturnTopScriptsButton.Enabled = false;
-   1696 RegionTeleportGroup.Enabled = false;
-   1697 }));
-   1698  
-   1699 // Enqueue all the UUIDs to return.
-   1700 Queue<KeyValuePair<UUID, Vector3>> returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>();
-   1701 vassalForm.Invoke((MethodInvoker) (() =>
-   1702 {
-   1703 foreach (
-   1704 DataGridViewRow topScriptsRow in
-   1705 TopScriptsGridView.Rows.AsParallel()
-   1706 .Cast<DataGridViewRow>()
-   1707 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
-   1708 {
-   1709 Vector3 objectPosition;
-   1710 UUID returnUUID;
-   1711 if (!UUID.TryParse(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(), out returnUUID) ||
-   1712 !Vector3.TryParse(topScriptsRow.Cells["TopScriptsPosition"].Value.ToString(), out objectPosition))
-   1713 continue;
-   1714 returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
-   1715 }
-   1716 }));
-   1717  
-   1718 // If no rows were selected, enable teleports, the return button and return.
-   1719 if (returnUUIDs.Count.Equals(0))
-   1720 {
-   1721 vassalForm.Invoke((MethodInvoker)(() =>
-   1722 {
-   1723 vassalForm.ReturnTopScriptsButton.Enabled = true;
-   1724 RegionTeleportGroup.Enabled = true;
-   1725 }));
-   1726 return;
-   1727 }
-   1728  
-   1729 new Thread(() =>
-   1730 {
-   1731 Monitor.Enter(ClientInstanceTeleportLock);
-   1732  
-   1733 try
-   1734 {
-   1735 vassalForm.Invoke((MethodInvoker) (() =>
-   1736 {
-   1737 vassalForm.StatusProgress.Value = 0;
-   1738 }));
-   1739 int totalObjects = returnUUIDs.Count;
-   1740 do
-   1741 {
-   1742 // Dequeue the first object.
-   1743 KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue();
-   1744  
-   1745 vassalForm.Invoke((MethodInvoker) (() =>
-   1746 {
-   1747 vassalForm.StatusText.Text = @"Returning object UUID: " + objectData.Key.ToString();
-   1748 }));
-   1749  
-   1750 string currentRegionName = string.Empty;
-   1751 vassalForm.Invoke((MethodInvoker) (() =>
-   1752 {
-   1753 currentRegionName = CurrentRegionName.Text;
-   1754 }));
-   1755
-   1756 // Teleport to the object.
-   1757 string result = wasPOST(vassalConfiguration.HTTPServerURL,
-   1758 wasKeyValueEscape(new Dictionary<string, string>
-   1759 {
-   1760 {"command", "teleport"},
-   1761 {"group", vassalConfiguration.Group},
-   1762 {"password", vassalConfiguration.Password},
-   1763 {"position", objectData.Value.ToString()},
-   1764 {"region", currentRegionName},
-   1765 {"fly", "True"}
-   1766 }), vassalConfiguration.TeleportTimeout);
-   1767  
-   1768 if (string.IsNullOrEmpty(result))
-   1769 {
-   1770 vassalForm.Invoke((MethodInvoker)(() =>
-   1771 {
-   1772 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
-   1773 }));
-   1774 continue;
-   1775 }
-   1776  
-   1777 // Return the object.
-   1778 result = wasPOST(vassalConfiguration.HTTPServerURL,
-   1779 wasKeyValueEscape(new Dictionary<string, string>
-   1780 {
-   1781 {"command", "derez"},
-   1782 {"group", vassalConfiguration.Group},
-   1783 {"password", vassalConfiguration.Password},
-   1784 {"item", objectData.Key.ToString()},
-   1785 {"range", "32" }, // maximal prim size = 64 - middle bounding box at half
-   1786 {"type", "ReturnToOwner"}
-   1787 }), vassalConfiguration.DataTimeout);
-   1788  
-   1789 if (string.IsNullOrEmpty(result))
-   1790 {
-   1791 vassalForm.Invoke((MethodInvoker) (() =>
-   1792 {
-   1793 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
-   1794 }));
-   1795 continue;
-   1796 }
-   1797  
-   1798 bool success;
-   1799 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
-   1800 {
-   1801 vassalForm.Invoke((MethodInvoker) (() =>
-   1802 {
-   1803 vassalForm.StatusText.Text = @"No success status could be retrieved. ";
-   1804 }));
-   1805 continue;
-   1806 }
-   1807  
-   1808 switch (success)
-   1809 {
-   1810 case true:
-   1811 vassalForm.Invoke((MethodInvoker) (() =>
-   1812 {
-   1813 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString();
-   1814 // Remove the row from the grid view.
-   1815 DataGridViewRow row =
-   1816 TopScriptsGridView.Rows.AsParallel()
-   1817 .Cast<DataGridViewRow>()
-   1818 .FirstOrDefault(
-   1819 o => o.Cells["TopScriptsUUID"].Value.Equals(objectData.Key.ToString()));
-   1820 if (row == null) return;
-   1821 int i = row.Index;
-   1822 TopScriptsGridView.Rows.RemoveAt(i);
-   1823 }));
-   1824 break;
-   1825 case false:
-   1826 vassalForm.Invoke((MethodInvoker) (() =>
-   1827 {
-   1828 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() +
-   1829 @": " +
-   1830 wasInput(wasKeyValueGet("error", result));
-   1831 }));
-   1832 break;
-   1833 }
-   1834  
-   1835 vassalForm.Invoke((MethodInvoker) (() =>
-   1836 {
-   1837 vassalForm.StatusProgress.Value =
-   1838 Math.Min((int) (Math.Abs(returnUUIDs.Count - totalObjects)/
-   1839 (double) totalObjects), 100);
-   1840 }));
-   1841 } while (!returnUUIDs.Count.Equals(0));
-   1842 vassalForm.Invoke((MethodInvoker) (() =>
-   1843 {
-   1844 vassalForm.StatusProgress.Value = 100;
-   1845 }));
-   1846 }
-   1847 catch (Exception ex)
-   1848 {
-   1849 vassalForm.Invoke((MethodInvoker)(() =>
-   1850 {
-   1851 vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message;
-   1852 }));
-   1853 }
-   1854 finally
-   1855 {
-   1856 Monitor.Exit(ClientInstanceTeleportLock);
-   1857 // Allow teleports and enable button.
-   1858 vassalForm.BeginInvoke((MethodInvoker)(() =>
-   1859 {
-   1860 vassalForm.ReturnTopScriptsButton.Enabled = true;
-   1861 RegionTeleportGroup.Enabled = true;
-   1862 }));
-   1863 }
-   1864 })
-   1865 {IsBackground = true}.Start();
-   1866 }
-   1867  
-   1868 private void RequestReturnTopCollidersObjects(object sender, EventArgs e)
-   1869 {
-   1870 // Block teleports and disable button.
-   1871 vassalForm.Invoke((MethodInvoker)(() =>
-   1872 {
-   1873 vassalForm.ReturnTopCollidersButton.Enabled = false;
-   1874 RegionTeleportGroup.Enabled = false;
-   1875 }));
-   1876  
-   1877 // Enqueue all the UUIDs to return.
-   1878 Queue<KeyValuePair<UUID, Vector3>> returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>();
-   1879 vassalForm.Invoke((MethodInvoker)(() =>
-   1880 {
-   1881 foreach (
-   1882 DataGridViewRow topCollidersRow in
-   1883 TopCollidersGridView.Rows.AsParallel()
-   1884 .Cast<DataGridViewRow>()
-   1885 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
-   1886 {
-   1887 Vector3 objectPosition;
-   1888 UUID returnUUID;
-   1889 if (!UUID.TryParse(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(), out returnUUID) ||
-   1890 !Vector3.TryParse(topCollidersRow.Cells["TopCollidersPosition"].Value.ToString(), out objectPosition))
-   1891 continue;
-   1892 returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
-   1893 }
-   1894 }));
-   1895  
-   1896 // If no rows were selected, enable teleports, the return button and return.
-   1897 if (returnUUIDs.Count.Equals(0))
-   1898 {
-   1899 vassalForm.Invoke((MethodInvoker)(() =>
-   1900 {
-   1901 vassalForm.ReturnTopCollidersButton.Enabled = true;
-   1902 RegionTeleportGroup.Enabled = true;
-   1903 }));
-   1904 return;
-   1905 }
-   1906  
-   1907 new Thread(() =>
-   1908 {
-   1909 Monitor.Enter(ClientInstanceTeleportLock);
-   1910  
-   1911 try
-   1912 {
-   1913 vassalForm.Invoke((MethodInvoker)(() =>
-   1914 {
-   1915 vassalForm.StatusProgress.Value = 0;
-   1916 }));
-   1917 int totalObjects = returnUUIDs.Count;
-   1918 do
-   1919 {
-   1920 // Dequeue the first object.
-   1921 KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue();
-   1922  
-   1923 vassalForm.Invoke((MethodInvoker)(() =>
-   1924 {
-   1925 vassalForm.StatusText.Text = @"Returning UUID: " + objectData.Key.ToString();
-   1926 }));
-   1927  
-   1928 string currentRegionName = string.Empty;
-   1929 vassalForm.Invoke((MethodInvoker)(() =>
-   1930 {
-   1931 currentRegionName = CurrentRegionName.Text;
-   1932 }));
-   1933  
-   1934 // Teleport to the object.
-   1935 string result = wasPOST(vassalConfiguration.HTTPServerURL,
-   1936 wasKeyValueEscape(new Dictionary<string, string>
-   1937 {
-   1938 {"command", "teleport"},
-   1939 {"group", vassalConfiguration.Group},
-   1940 {"password", vassalConfiguration.Password},
-   1941 {"position", objectData.Value.ToString()},
-   1942 {"region", currentRegionName},
-   1943 {"fly", "True"}
-   1944 }), vassalConfiguration.DataTimeout);
-   1945  
-   1946 if (string.IsNullOrEmpty(result))
-   1947 {
-   1948 vassalForm.Invoke((MethodInvoker)(() =>
-   1949 {
-   1950 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
-   1951 }));
-   1952 continue;
-   1953 }
-   1954  
-   1955 // Return the object.
-   1956 result = wasPOST(vassalConfiguration.HTTPServerURL,
-   1957 wasKeyValueEscape(new Dictionary<string, string>
-   1958 {
-   1959 {"command", "derez"},
-   1960 {"group", vassalConfiguration.Group},
-   1961 {"password", vassalConfiguration.Password},
-   1962 {"item", objectData.Key.ToString()},
-   1963 {"range", "32" }, // maximal prim size = 64 - middle bounding box at half
-   1964 {"type", "ReturnToOwner"}
-   1965 }), vassalConfiguration.DataTimeout);
-   1966  
-   1967 if (string.IsNullOrEmpty(result))
-   1968 {
-   1969 vassalForm.Invoke((MethodInvoker)(() =>
-   1970 {
-   1971 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
-   1972 }));
-   1973 continue;
-   1974 }
-   1975  
-   1976 bool success;
-   1977 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
-   1978 {
-   1979 vassalForm.Invoke((MethodInvoker)(() =>
-   1980 {
-   1981 vassalForm.StatusText.Text = @"No success status could be retrieved. ";
-   1982 }));
-   1983 continue;
-   1984 }
-   1985  
-   1986 switch (success)
-   1987 {
-   1988 case true:
-   1989 vassalForm.Invoke((MethodInvoker)(() =>
-   1990 {
-   1991 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString();
-   1992 // Remove the row from the grid view.
-   1993 DataGridViewRow row =
-   1994 TopCollidersGridView.Rows.AsParallel()
-   1995 .Cast<DataGridViewRow>()
-   1996 .FirstOrDefault(
-   1997 o => o.Cells["TopCollidersUUID"].Value.Equals(objectData.Key.ToString()));
-   1998 if (row == null) return;
-   1999 int i = row.Index;
-   2000 TopCollidersGridView.Rows.RemoveAt(i);
-   2001 }));
-   2002 break;
-   2003 case false:
-   2004 vassalForm.Invoke((MethodInvoker)(() =>
-   2005 {
-   2006 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() +
-   2007 @": " +
-   2008 wasInput(wasKeyValueGet("error", result));
-   2009 }));
-   2010 break;
-   2011 }
-   2012  
-   2013 vassalForm.Invoke((MethodInvoker)(() =>
-   2014 {
-   2015 vassalForm.StatusProgress.Value =
-   2016 Math.Min((int)(Math.Abs(returnUUIDs.Count - totalObjects) /
-   2017 (double)totalObjects), 100);
-   2018 }));
-   2019 } while (!returnUUIDs.Count.Equals(0));
-   2020 vassalForm.Invoke((MethodInvoker)(() =>
-   2021 {
-   2022 vassalForm.StatusProgress.Value = 100;
-   2023 }));
-   2024 }
-   2025 catch (Exception ex)
-   2026 {
-   2027 vassalForm.Invoke((MethodInvoker)(() =>
-   2028 {
-   2029 vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message;
-   2030 }));
-   2031 }
-   2032 finally
-   2033 {
-   2034 Monitor.Exit(ClientInstanceTeleportLock);
-   2035 // Allow teleports and enable button.
-   2036 vassalForm.BeginInvoke((MethodInvoker)(() =>
-   2037 {
-   2038 vassalForm.ReturnTopScriptsButton.Enabled = true;
-   2039 RegionTeleportGroup.Enabled = true;
-   2040 }));
-   2041 }
-   2042 })
-   2043 { IsBackground = true }.Start();
-   2044 }
-   2045  
-   2046 private void RequestBatchRestart(object sender, EventArgs e)
-   2047 {
-   2048  
-   2049 }
1482 } 2050 }
1483 } 2051 }
1484   2052