corrade-vassal – Diff between revs 3 and 4

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 3 Rev 4
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 VassalConfiguration vassalConfiguration = new VassalConfiguration(); 34 public static VassalConfiguration vassalConfiguration = new VassalConfiguration();
35 public static Vassal vassalForm; 35 public static Vassal vassalForm;
36 public static readonly object ClientInstanceTeleportLock = new object(); 36 public static readonly object ClientInstanceTeleportLock = new object();
37   37  
38 /////////////////////////////////////////////////////////////////////////// 38 ///////////////////////////////////////////////////////////////////////////
39 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // 39 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
40 /////////////////////////////////////////////////////////////////////////// 40 ///////////////////////////////////////////////////////////////////////////
41 /// <summary>RFC1738 URL Escapes a string</summary> 41 /// <summary>RFC1738 URL Escapes a string</summary>
42 /// <param name="data">a string to escape</param> 42 /// <param name="data">a string to escape</param>
43 /// <returns>an RFC1738 escaped string</returns> 43 /// <returns>an RFC1738 escaped string</returns>
44 private static string wasURLEscapeDataString(string data) 44 private static string wasURLEscapeDataString(string data)
45 { 45 {
46 return HttpUtility.UrlEncode(data); 46 return HttpUtility.UrlEncode(data);
47 } 47 }
48   48  
49 /////////////////////////////////////////////////////////////////////////// 49 ///////////////////////////////////////////////////////////////////////////
50 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // 50 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
51 /////////////////////////////////////////////////////////////////////////// 51 ///////////////////////////////////////////////////////////////////////////
52 /// <summary>RFC1738 URL Unescape a string</summary> 52 /// <summary>RFC1738 URL Unescape a string</summary>
53 /// <param name="data">a string to unescape</param> 53 /// <param name="data">a string to unescape</param>
54 /// <returns>an RFC1738 unescaped string</returns> 54 /// <returns>an RFC1738 unescaped string</returns>
55 private static string wasURLUnescapeDataString(string data) 55 private static string wasURLUnescapeDataString(string data)
56 { 56 {
57 return HttpUtility.UrlDecode(data); 57 return HttpUtility.UrlDecode(data);
58 } 58 }
59   59  
60 /////////////////////////////////////////////////////////////////////////// 60 ///////////////////////////////////////////////////////////////////////////
61 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 61 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
62 /////////////////////////////////////////////////////////////////////////// 62 ///////////////////////////////////////////////////////////////////////////
63 /// <summary>URI unescapes an RFC3986 URI escaped string</summary> 63 /// <summary>URI unescapes an RFC3986 URI escaped string</summary>
64 /// <param name="data">a string to unescape</param> 64 /// <param name="data">a string to unescape</param>
65 /// <returns>the resulting string</returns> 65 /// <returns>the resulting string</returns>
66 private static string wasURIUnescapeDataString(string data) 66 private static string wasURIUnescapeDataString(string data)
67 { 67 {
68 // Uri.UnescapeDataString can only handle 32766 characters at a time 68 // Uri.UnescapeDataString can only handle 32766 characters at a time
69 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766) 69 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766)
70 .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)))))
71 .ToArray()); 71 .ToArray());
72 } 72 }
73   73  
74 /////////////////////////////////////////////////////////////////////////// 74 ///////////////////////////////////////////////////////////////////////////
75 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 75 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
76 /////////////////////////////////////////////////////////////////////////// 76 ///////////////////////////////////////////////////////////////////////////
77 /// <summary>RFC3986 URI Escapes a string</summary> 77 /// <summary>RFC3986 URI Escapes a string</summary>
78 /// <param name="data">a string to escape</param> 78 /// <param name="data">a string to escape</param>
79 /// <returns>an RFC3986 escaped string</returns> 79 /// <returns>an RFC3986 escaped string</returns>
80 private static string wasURIEscapeDataString(string data) 80 private static string wasURIEscapeDataString(string data)
81 { 81 {
82 // Uri.EscapeDataString can only handle 32766 characters at a time 82 // Uri.EscapeDataString can only handle 32766 characters at a time
83 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766) 83 return string.Join("", Enumerable.Range(0, (data.Length + 32765)/32766)
84 .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)))))
85 .ToArray()); 85 .ToArray());
86 } 86 }
87   87  
88 /////////////////////////////////////////////////////////////////////////// 88 ///////////////////////////////////////////////////////////////////////////
89 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 89 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
90 /////////////////////////////////////////////////////////////////////////// 90 ///////////////////////////////////////////////////////////////////////////
91 /// <summary> 91 /// <summary>
92 /// Gets an array element at a given modulo index. 92 /// Gets an array element at a given modulo index.
93 /// </summary> 93 /// </summary>
94 /// <typeparam name="T">the array type</typeparam> 94 /// <typeparam name="T">the array type</typeparam>
95 /// <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>
96 /// <param name="data">the array</param> 96 /// <param name="data">the array</param>
97 /// <return>an array element</return> 97 /// <return>an array element</return>
98 public static T wasGetElementAt<T>(T[] data, int index) 98 public static T wasGetElementAt<T>(T[] data, int index)
99 { 99 {
100 switch (index < 0) 100 switch (index < 0)
101 { 101 {
102 case true: 102 case true:
103 return data[((index%data.Length) + data.Length)%data.Length]; 103 return data[((index%data.Length) + data.Length)%data.Length];
104 default: 104 default:
105 return data[index%data.Length]; 105 return data[index%data.Length];
106 } 106 }
107 } 107 }
108   108  
109 #region KEY-VALUE DATA 109 #region KEY-VALUE DATA
110   110  
111 /////////////////////////////////////////////////////////////////////////// 111 ///////////////////////////////////////////////////////////////////////////
112 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 112 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
113 /////////////////////////////////////////////////////////////////////////// 113 ///////////////////////////////////////////////////////////////////////////
114 /// <summary> 114 /// <summary>
115 /// 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.
116 /// </summary> 116 /// </summary>
117 /// <param name="key">the key of the value</param> 117 /// <param name="key">the key of the value</param>
118 /// <param name="data">the key-value data segment</param> 118 /// <param name="data">the key-value data segment</param>
119 /// <returns>true if the key was found in data</returns> 119 /// <returns>true if the key was found in data</returns>
120 private static string wasKeyValueGet(string key, string data) 120 private static string wasKeyValueGet(string key, string data)
121 { 121 {
122 return data.Split('&') 122 return data.Split('&')
123 .AsParallel() 123 .AsParallel()
124 .Select(o => o.Split('=').ToList()) 124 .Select(o => o.Split('=').ToList())
125 .Where(o => o.Count.Equals(2)) 125 .Where(o => o.Count.Equals(2))
126 .Select(o => new 126 .Select(o => new
127 { 127 {
128 k = o.First(), 128 k = o.First(),
129 v = o.Last() 129 v = o.Last()
130 }) 130 })
131 .Where(o => o.k.Equals(key)) 131 .Where(o => o.k.Equals(key))
132 .Select(o => o.v) 132 .Select(o => o.v)
133 .FirstOrDefault(); 133 .FirstOrDefault();
134 } 134 }
135   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; 973 string selectedRegionName = string.Empty;
974 Vector3 selectedRegionPosition = Vector3.Zero; 974 Vector3 selectedRegionPosition = Vector3.Zero;
975 bool startTeleport = false; 975 bool startTeleport = false;
976 vassalForm.Invoke((MethodInvoker) (() => 976 vassalForm.Invoke((MethodInvoker) (() =>
977 { 977 {
978 ListViewItem listViewItem = LoadedRegions.SelectedItem as ListViewItem; 978 ListViewItem listViewItem = LoadedRegions.SelectedItem as ListViewItem;
979 switch (listViewItem != null && LoadedRegions.SelectedIndex != -1) 979 switch (listViewItem != null && LoadedRegions.SelectedIndex != -1)
980 { 980 {
981 case true: 981 case true:
982 selectedRegionName = listViewItem.Text; 982 selectedRegionName = listViewItem.Text;
983 selectedRegionPosition = (Vector3)listViewItem.Tag; 983 selectedRegionPosition = (Vector3)listViewItem.Tag;
984 startTeleport = true; 984 startTeleport = true;
985 break; 985 break;
986 default: 986 default:
987 startTeleport = false; 987 startTeleport = false;
988 break; 988 break;
989 } 989 }
990 })); 990 }));
991   991  
992 if (!startTeleport) return; 992 if (!startTeleport) return;
993 993
994   994  
995 // Announce teleport. 995 // Announce teleport.
996 vassalForm.Invoke((MethodInvoker)(() => 996 vassalForm.Invoke((MethodInvoker)(() =>
997 { 997 {
998 vassalForm.RegionTeleportGroup.Enabled = false; 998 vassalForm.RegionTeleportGroup.Enabled = false;
999 vassalForm.StatusProgress.Value = 0; 999 vassalForm.StatusProgress.Value = 0;
1000 vassalForm.StatusText.Text = @"Teleporting to " + selectedRegionName; 1000 vassalForm.StatusText.Text = @"Teleporting to " + selectedRegionName;
1001 })); 1001 }));
1002   1002  
1003 new Thread(() => 1003 new Thread(() =>
1004 { 1004 {
1005 Monitor.Enter(ClientInstanceTeleportLock); 1005 Monitor.Enter(ClientInstanceTeleportLock);
1006 try 1006 try
1007 { 1007 {
1008 int elapsedSeconds = 0; 1008 int elapsedSeconds = 0;
1009 System.Timers.Timer teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds); 1009 System.Timers.Timer teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
1010 teleportTimer.Elapsed += (o, p) => 1010 teleportTimer.Elapsed += (o, p) =>
1011 { 1011 {
1012 vassalForm.Invoke((MethodInvoker) (() => 1012 vassalForm.Invoke((MethodInvoker) (() =>
1013 { 1013 {
1014 vassalForm.StatusProgress.Value = 1014 vassalForm.StatusProgress.Value =
1015 Math.Min( 1015 Math.Min(
1016 (int) 1016 (int)
1017 (100d* 1017 (100d*
1018 (TimeSpan.FromSeconds(++elapsedSeconds).TotalMilliseconds/ 1018 (TimeSpan.FromSeconds(++elapsedSeconds).TotalMilliseconds/
1019 vassalConfiguration.TeleportTimeout)), 100); 1019 vassalConfiguration.TeleportTimeout)), 100);
1020 })); 1020 }));
1021 }; 1021 };
1022 teleportTimer.Start(); 1022 teleportTimer.Start();
1023 string result = null; 1023 string result = null;
1024 ManualResetEvent receivedPOST = new ManualResetEvent(false); 1024 ManualResetEvent receivedPOST = new ManualResetEvent(false);
1025 new Thread(() => 1025 new Thread(() =>
1026 { 1026 {
1027 result = wasInput(wasPOST(vassalConfiguration.HTTPServerURL, 1027 result = wasInput(wasPOST(vassalConfiguration.HTTPServerURL,
1028 wasKeyValueEscape(new Dictionary<string, string> 1028 wasKeyValueEscape(new Dictionary<string, string>
1029 { 1029 {
1030 {"command", "teleport"}, 1030 {"command", "teleport"},
1031 {"group", vassalConfiguration.Group}, 1031 {"group", vassalConfiguration.Group},
1032 {"password", vassalConfiguration.Password}, 1032 {"password", vassalConfiguration.Password},
1033 {"region", selectedRegionName}, 1033 {"region", selectedRegionName},
1034 {"position", selectedRegionPosition.ToString()}, 1034 {"position", selectedRegionPosition.ToString()},
1035 {"fly", "True"} 1035 {"fly", "True"}
1036 }), vassalConfiguration.TeleportTimeout)); 1036 }), vassalConfiguration.TeleportTimeout));
1037 receivedPOST.Set(); 1037 receivedPOST.Set();
1038 }) {IsBackground = true}.Start(); 1038 }) {IsBackground = true}.Start();
1039 receivedPOST.WaitOne((int) vassalConfiguration.TeleportTimeout, false); 1039 receivedPOST.WaitOne((int) vassalConfiguration.TeleportTimeout, false);
1040 teleportTimer.Stop(); 1040 teleportTimer.Stop();
1041 switch (!string.IsNullOrEmpty(result) && wasKeyValueGet("success", result) == "True") 1041 switch (!string.IsNullOrEmpty(result) && wasKeyValueGet("success", result) == "True")
1042 { 1042 {
1043 case true: 1043 case true:
1044 vassalForm.Invoke((MethodInvoker) (() => 1044 vassalForm.Invoke((MethodInvoker) (() =>
1045 { 1045 {
1046 vassalForm.StatusText.Text = @"Now at " + selectedRegionName; 1046 vassalForm.StatusText.Text = @"Now at " + selectedRegionName;
1047 vassalForm.CurrentRegionName.Text = selectedRegionName; 1047 vassalForm.CurrentRegionName.Text = selectedRegionName;
1048 })); 1048 }));
1049 break; 1049 break;
1050 default: 1050 default:
1051 switch (!string.IsNullOrEmpty(result)) 1051 switch (!string.IsNullOrEmpty(result))
1052 { 1052 {
1053 case true: 1053 case true:
1054 vassalForm.Invoke((MethodInvoker) (() => 1054 vassalForm.Invoke((MethodInvoker) (() =>
1055 { 1055 {
1056 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName + 1056 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName +
1057 @": " + 1057 @": " +
1058 wasKeyValueGet("error", result); 1058 wasKeyValueGet("error", result);
1059 })); 1059 }));
1060 break; 1060 break;
1061 default: 1061 default:
1062 vassalForm.Invoke((MethodInvoker) (() => 1062 vassalForm.Invoke((MethodInvoker) (() =>
1063 { 1063 {
1064 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName; 1064 vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName;
1065 })); 1065 }));
1066 break; 1066 break;
1067 } 1067 }
1068 break; 1068 break;
1069 } 1069 }
1070 } 1070 }
1071 catch (Exception ex) 1071 catch (Exception ex)
1072 { 1072 {
1073 vassalForm.Invoke((MethodInvoker) (() => 1073 vassalForm.Invoke((MethodInvoker) (() =>
1074 { 1074 {
1075 vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message; 1075 vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message;
1076 })); 1076 }));
1077 } 1077 }
1078 finally 1078 finally
1079 { 1079 {
1080 Monitor.Exit(ClientInstanceTeleportLock); 1080 Monitor.Exit(ClientInstanceTeleportLock);
1081 vassalForm.Invoke((MethodInvoker) (() => 1081 vassalForm.Invoke((MethodInvoker) (() =>
1082 { 1082 {
1083 vassalForm.StatusProgress.Value = 100; 1083 vassalForm.StatusProgress.Value = 100;
1084 vassalForm.RegionTeleportGroup.Enabled = true; 1084 vassalForm.RegionTeleportGroup.Enabled = true;
1085 // Set the map image to the loading spinner. 1085 // Set the map image to the loading spinner.
1086 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly(); 1086 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
1087 System.IO.Stream file = 1087 System.IO.Stream file =
1088 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif"); 1088 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
1089 switch (file != null) 1089 switch (file != null)
1090 { 1090 {
1091 case true: 1091 case true:
1092 vassalForm.Invoke((MethodInvoker) (() => 1092 vassalForm.Invoke((MethodInvoker) (() =>
1093 { 1093 {
1094 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage; 1094 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
1095 RegionAvatarsMap.Image = Image.FromStream(file); 1095 RegionAvatarsMap.Image = Image.FromStream(file);
1096 RegionAvatarsMap.Refresh(); 1096 RegionAvatarsMap.Refresh();
1097 })); 1097 }));
1098 break; 1098 break;
1099 } 1099 }
1100 // Clear the top scripts table. 1100 // Clear the top scripts table.
1101 TopScriptsGridView.Rows.Clear(); 1101 TopScriptsGridView.Rows.Clear();
1102 // Clear the top colliders table. 1102 // Clear the top colliders table.
1103 TopCollidersGridView.Rows.Clear(); 1103 TopCollidersGridView.Rows.Clear();
1104 // Invalidate data for overview tab. 1104 // Invalidate data for overview tab.
1105 vassalForm.CurrentRegionAt.Visible = false; 1105 vassalForm.CurrentRegionAt.Visible = false;
1106 vassalForm.CurrentRegionName.Visible = false; 1106 vassalForm.CurrentRegionName.Visible = false;
1107 Agents.Text = string.Empty; 1107 Agents.Text = string.Empty;
1108 Agents.Enabled = false; 1108 Agents.Enabled = false;
1109 LastLag.Text = string.Empty; 1109 LastLag.Text = string.Empty;
1110 LastLag.Enabled = false; 1110 LastLag.Enabled = false;
1111 Dilation.Text = string.Empty; 1111 Dilation.Text = string.Empty;
1112 Dilation.Enabled = false; 1112 Dilation.Enabled = false;
1113 FPS.Text = string.Empty; 1113 FPS.Text = string.Empty;
1114 FPS.Enabled = false; 1114 FPS.Enabled = false;
1115 PhysicsFPS.Text = string.Empty; 1115 PhysicsFPS.Text = string.Empty;
1116 PhysicsFPS.Enabled = false; 1116 PhysicsFPS.Enabled = false;
1117 ActiveScripts.Text = string.Empty; 1117 ActiveScripts.Text = string.Empty;
1118 ActiveScripts.Enabled = false; 1118 ActiveScripts.Enabled = false;
1119 ScriptTime.Text = string.Empty; 1119 ScriptTime.Text = string.Empty;
1120 ScriptTime.Enabled = false; 1120 ScriptTime.Enabled = false;
1121 Objects.Text = string.Empty; 1121 Objects.Text = string.Empty;
1122 Objects.Enabled = false; 1122 Objects.Enabled = false;
1123 })); 1123 }));
1124 } 1124 }
1125 }).Start(); 1125 }).Start();
1126   1126  
1127 } 1127 }
1128   1128  
1129 private void SettingsRequested(object sender, EventArgs e) 1129 private void SettingsRequested(object sender, EventArgs e)
1130 { 1130 {
1131 SettingsForm settingsForm = new SettingsForm {TopMost = true}; 1131 SettingsForm settingsForm = new SettingsForm {TopMost = true};
1132 settingsForm.Show(); 1132 settingsForm.Show();
1133 } 1133 }
1134   1134  
1135 private void VassalShown(object sender, EventArgs e) 1135 private void VassalShown(object sender, EventArgs e)
1136 { 1136 {
1137 // Set the version 1137 // Set the version
1138 vassalForm.Version.Text = @"v" + VASSAL_CONSTANTS.VASSAL_VERSION; 1138 vassalForm.Version.Text = @"v" + VASSAL_CONSTANTS.VASSAL_VERSION;
-   1139  
-   1140 // Disable estate manager tabs since we will enable these dynamically.
-   1141 TopScriptsTab.Enabled = false;
-   1142 TopCollidersTab.Enabled = false;
1139   1143  
1140 // Get the configuration file settings if it exists. 1144 // Get the configuration file settings if it exists.
1141 if (File.Exists(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE)) 1145 if (File.Exists(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE))
1142 { 1146 {
-   1147 // Load the configuration.
1143 VassalConfiguration.Load(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE, ref vassalConfiguration); 1148 VassalConfiguration.Load(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE, ref vassalConfiguration);
1144 } 1149 }
1145   1150  
1146 // Get all the regions if they exist. 1151 // Get all the regions if they exist.
1147 if (File.Exists(VASSAL_CONSTANTS.VASSAL_REGIONS)) 1152 if (File.Exists(VASSAL_CONSTANTS.VASSAL_REGIONS))
1148 { 1153 {
1149 Vector3 localPosition; 1154 Vector3 localPosition;
1150 List<KeyValuePair<string, Vector3>> ConfiguredRegions = new List<KeyValuePair<string, Vector3>>( 1155 List<KeyValuePair<string, Vector3>> ConfiguredRegions = new List<KeyValuePair<string, Vector3>>(
1151 File.ReadAllLines(VASSAL_CONSTANTS.VASSAL_REGIONS) 1156 File.ReadAllLines(VASSAL_CONSTANTS.VASSAL_REGIONS)
1152 .Select(o => new List<string>(wasCSVToEnumerable(o))) 1157 .Select(o => new List<string>(wasCSVToEnumerable(o)))
1153 .Where(o => o.Count == 2) 1158 .Where(o => o.Count == 2)
1154 .ToDictionary(o => o.First(), 1159 .ToDictionary(o => o.First(),
1155 p => 1160 p =>
1156 Vector3.TryParse(p.Last(), out localPosition) 1161 Vector3.TryParse(p.Last(), out localPosition)
1157 ? localPosition 1162 ? localPosition
1158 : Vector3.Zero).OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value)); 1163 : Vector3.Zero).OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value));
1159 // Populate the loaded regions. 1164 // Populate the loaded regions.
1160 LoadedRegions.Items.Clear(); 1165 LoadedRegions.Items.Clear();
1161 LoadedRegions.Items.AddRange( 1166 LoadedRegions.Items.AddRange(
1162 ConfiguredRegions.Select(o => (object) new ListViewItem {Text = o.Key, Tag = o.Value}) 1167 ConfiguredRegions.Select(o => (object) new ListViewItem {Text = o.Key, Tag = o.Value})
1163 .ToArray()); 1168 .ToArray());
1164 // Populate the batch restart grid view. 1169 // Populate the batch restart grid view.
1165 BatchRestartGridView.Rows.Clear(); 1170 BatchRestartGridView.Rows.Clear();
1166 foreach (KeyValuePair<string, Vector3> data in ConfiguredRegions) 1171 foreach (KeyValuePair<string, Vector3> data in ConfiguredRegions)
1167 { 1172 {
1168 BatchRestartGridView.Rows.Add(data.Key, data.Value.ToString()); 1173 BatchRestartGridView.Rows.Add(data.Key, data.Value.ToString());
1169 } 1174 }
1170 } 1175 }
1171   1176  
1172 // Set the map image to the loading spinner. 1177 // Set the map image to the loading spinner.
1173 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly(); 1178 Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
1174 System.IO.Stream file = 1179 System.IO.Stream file =
1175 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif"); 1180 thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
1176 switch (file != null) 1181 switch (file != null)
1177 { 1182 {
1178 case true: 1183 case true:
1179 vassalForm.Invoke((MethodInvoker) (() => 1184 vassalForm.Invoke((MethodInvoker) (() =>
1180 { 1185 {
1181 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage; 1186 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
1182 RegionAvatarsMap.Image = Image.FromStream(file); 1187 RegionAvatarsMap.Image = Image.FromStream(file);
1183 RegionAvatarsMap.Refresh(); 1188 RegionAvatarsMap.Refresh();
1184 })); 1189 }));
1185 break; 1190 break;
1186 } 1191 }
1187   1192  
1188 // Start the overview timer. 1193 // Start the overview timer.
1189 overviewTabTimer.Elapsed += (o, p) => 1194 overviewTabTimer.Elapsed += (o, p) =>
1190 { 1195 {
1191 if (!Monitor.TryEnter(ClientInstanceTeleportLock)) 1196 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1192 return; 1197 return;
1193   1198  
1194 try 1199 try
1195 { 1200 {
1196 // Do not do anything in case the tab is not selected. 1201 // Do not do anything in case the tab is not selected.
1197 vassalForm.Invoke((MethodInvoker) (() => 1202 vassalForm.Invoke((MethodInvoker) (() =>
1198 { 1203 {
1199 if (!Tabs.SelectedTab.Equals(OverviewTab)) 1204 if (!Tabs.SelectedTab.Equals(OverviewTab))
1200 throw new Exception(); 1205 throw new Exception();
1201 })); 1206 }));
1202   1207  
1203 // Get the statistics. 1208 // Get the statistics.
1204 string result = wasPOST(vassalConfiguration.HTTPServerURL, 1209 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1205 wasKeyValueEscape(new Dictionary<string, string> 1210 wasKeyValueEscape(new Dictionary<string, string>
1206 { 1211 {
1207 {"command", "getregiondata"}, 1212 {"command", "getregiondata"},
1208 {"group", vassalConfiguration.Group}, 1213 {"group", vassalConfiguration.Group},
1209 {"password", vassalConfiguration.Password}, 1214 {"password", vassalConfiguration.Password},
1210 { 1215 {
1211 "data", wasEnumerableToCSV(new[] 1216 "data", wasEnumerableToCSV(new[]
1212 { 1217 {
1213 "Agents", 1218 "Agents",
1214 "LastLag", 1219 "LastLag",
1215 "Dilation", 1220 "Dilation",
1216 "FPS", 1221 "FPS",
1217 "PhysicsFPS", 1222 "PhysicsFPS",
1218 "ActiveScripts", 1223 "ActiveScripts",
1219 "ScriptTime", 1224 "ScriptTime",
1220 "Objects", 1225 "Objects",
1221 "Name" 1226 "Name",
-   1227 "IsEstateManager"
1222 }) 1228 })
1223 } 1229 }
1224 }), vassalConfiguration.DataTimeout); 1230 }), vassalConfiguration.DataTimeout);
1225   1231  
1226 bool success; 1232 bool success;
1227 if (string.IsNullOrEmpty(result) || 1233 if (string.IsNullOrEmpty(result) ||
1228 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1234 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1229 throw new Exception(); 1235 throw new Exception();
1230   1236  
1231 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList(); 1237 List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1232 if (data.Count.Equals(0)) 1238 if (data.Count.Equals(0))
1233 throw new Exception(); 1239 throw new Exception();
1234   1240  
1235 vassalForm.Invoke((MethodInvoker) (() => 1241 vassalForm.Invoke((MethodInvoker) (() =>
1236 { 1242 {
-   1243 // Drop access to features if we are not estate managers.
-   1244 bool isEstateManager;
-   1245 switch (
-   1246 bool.TryParse(data[data.IndexOf("IsEstateManager") + 1], out isEstateManager) &&
-   1247 isEstateManager)
-   1248 {
-   1249 case true: // we are an estate manager
-   1250 TopScriptsTab.Enabled = true;
-   1251 TopCollidersTab.Enabled = true;
-   1252 break;
-   1253 default:
-   1254 TopScriptsTab.Enabled = false;
-   1255 TopCollidersTab.Enabled = false;
-   1256 break;
-   1257 }
-   1258  
1237 // Show the region name. 1259 // Show the region name.
1238 vassalForm.CurrentRegionName.Text = data[data.IndexOf("Name") + 1]; 1260 vassalForm.CurrentRegionName.Text = data[data.IndexOf("Name") + 1];
1239 vassalForm.CurrentRegionAt.Visible = true; 1261 vassalForm.CurrentRegionAt.Visible = true;
1240 vassalForm.CurrentRegionName.Visible = true; 1262 vassalForm.CurrentRegionName.Visible = true;
1241   1263  
1242 // Populate the overview tab. 1264 // Populate the overview tab.
1243 Agents.Text = data[data.IndexOf("Agents") + 1]; 1265 Agents.Text = data[data.IndexOf("Agents") + 1];
1244 Agents.Enabled = true; 1266 Agents.Enabled = true;
1245 LastLag.Text = data[data.IndexOf("LastLag") + 1]; 1267 LastLag.Text = data[data.IndexOf("LastLag") + 1];
1246 LastLag.Enabled = true; 1268 LastLag.Enabled = true;
1247 Dilation.Text = data[data.IndexOf("Dilation") + 1]; 1269 Dilation.Text = data[data.IndexOf("Dilation") + 1];
1248 Dilation.Enabled = true; 1270 Dilation.Enabled = true;
1249 FPS.Text = data[data.IndexOf("FPS") + 1]; 1271 FPS.Text = data[data.IndexOf("FPS") + 1];
1250 FPS.Enabled = true; 1272 FPS.Enabled = true;
1251 PhysicsFPS.Text = data[data.IndexOf("PhysicsFPS") + 1]; 1273 PhysicsFPS.Text = data[data.IndexOf("PhysicsFPS") + 1];
1252 PhysicsFPS.Enabled = true; 1274 PhysicsFPS.Enabled = true;
1253 ActiveScripts.Text = data[data.IndexOf("ActiveScripts") + 1]; 1275 ActiveScripts.Text = data[data.IndexOf("ActiveScripts") + 1];
1254 ActiveScripts.Enabled = true; 1276 ActiveScripts.Enabled = true;
1255 ScriptTime.Text = data[data.IndexOf("ScriptTime") + 1]; 1277 ScriptTime.Text = data[data.IndexOf("ScriptTime") + 1];
1256 ScriptTime.Enabled = true; 1278 ScriptTime.Enabled = true;
1257 Objects.Text = data[data.IndexOf("Objects") + 1]; 1279 Objects.Text = data[data.IndexOf("Objects") + 1];
1258 Objects.Enabled = true; 1280 Objects.Enabled = true;
1259 })); 1281 }));
1260   1282  
1261 // Get the map image. 1283 // Get the map image.
1262 result = wasPOST(vassalConfiguration.HTTPServerURL, 1284 result = wasPOST(vassalConfiguration.HTTPServerURL,
1263 wasKeyValueEscape(new Dictionary<string, string> 1285 wasKeyValueEscape(new Dictionary<string, string>
1264 { 1286 {
1265 {"command", "getgridregiondata"}, 1287 {"command", "getgridregiondata"},
1266 {"group", vassalConfiguration.Group}, 1288 {"group", vassalConfiguration.Group},
1267 {"password", vassalConfiguration.Password}, 1289 {"password", vassalConfiguration.Password},
1268 {"data", "MapImageID"} 1290 {"data", "MapImageID"}
1269 }), vassalConfiguration.DataTimeout); 1291 }), vassalConfiguration.DataTimeout);
1270   1292  
1271 if (string.IsNullOrEmpty(result) || 1293 if (string.IsNullOrEmpty(result) ||
1272 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1294 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1273 throw new Exception(); 1295 throw new Exception();
1274   1296  
1275 data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList(); 1297 data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
1276 if (!data.Count.Equals(2)) 1298 if (!data.Count.Equals(2))
1277 throw new Exception(); 1299 throw new Exception();
1278 result = wasPOST(vassalConfiguration.HTTPServerURL, 1300 result = wasPOST(vassalConfiguration.HTTPServerURL,
1279 wasKeyValueEscape(new Dictionary<string, string> 1301 wasKeyValueEscape(new Dictionary<string, string>
1280 { 1302 {
1281 {"command", "download"}, 1303 {"command", "download"},
1282 {"group", vassalConfiguration.Group}, 1304 {"group", vassalConfiguration.Group},
1283 {"password", vassalConfiguration.Password}, 1305 {"password", vassalConfiguration.Password},
1284 {"item", data.Last()}, 1306 {"item", data.Last()},
1285 {"type", "Texture"}, 1307 {"type", "Texture"},
1286 {"format", "Jpeg"}, 1308 {"format", "Jpeg"},
1287 }), vassalConfiguration.DataTimeout); 1309 }), vassalConfiguration.DataTimeout);
1288 if (string.IsNullOrEmpty(result) || 1310 if (string.IsNullOrEmpty(result) ||
1289 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1311 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1290 throw new Exception(); 1312 throw new Exception();
1291 byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result))); 1313 byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
1292 Image mapImage; 1314 Image mapImage;
1293 using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length)) 1315 using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
1294 { 1316 {
1295 mapImage = Image.FromStream(memoryStream); 1317 mapImage = Image.FromStream(memoryStream);
1296 } 1318 }
1297   1319  
1298 // Get the avatar positions. 1320 // Get the avatar positions.
1299 result = wasPOST(vassalConfiguration.HTTPServerURL, 1321 result = wasPOST(vassalConfiguration.HTTPServerURL,
1300 wasKeyValueEscape(new Dictionary<string, string> 1322 wasKeyValueEscape(new Dictionary<string, string>
1301 { 1323 {
1302 {"command", "getavatarpositions"}, 1324 {"command", "getavatarpositions"},
1303 {"group", vassalConfiguration.Group}, 1325 {"group", vassalConfiguration.Group},
1304 {"password", vassalConfiguration.Password}, 1326 {"password", vassalConfiguration.Password},
1305 {"entity", "region"} 1327 {"entity", "region"}
1306 }), vassalConfiguration.DataTimeout); 1328 }), vassalConfiguration.DataTimeout);
1307   1329  
1308 if (string.IsNullOrEmpty(result) || 1330 if (string.IsNullOrEmpty(result) ||
1309 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1331 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1310 throw new Exception(); 1332 throw new Exception();
1311   1333  
1312 // Every thrid element represents a Vecto3 of the avatar position. 1334 // Every thrid element represents a Vecto3 of the avatar position.
1313 data = 1335 data =
1314 wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))) 1336 wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1315 .Skip(2) 1337 .Skip(2)
1316 .Where((x, i) => i%3 == 0) 1338 .Where((x, i) => i%3 == 0)
1317 .ToList(); 1339 .ToList();
1318   1340  
1319 // Draw the avatars onto the map. 1341 // Draw the avatars onto the map.
1320 Graphics mapGraphics = Graphics.FromImage(mapImage); 1342 Graphics mapGraphics = Graphics.FromImage(mapImage);
1321 Vector3 position; 1343 Vector3 position;
1322 foreach (string vector in data) 1344 foreach (string vector in data)
1323 { 1345 {
1324 switch (Vector3.TryParse(vector, out position)) 1346 switch (Vector3.TryParse(vector, out position))
1325 { 1347 {
1326 case true: 1348 case true:
1327 mapGraphics.FillEllipse(Brushes.Chartreuse, 1349 mapGraphics.FillEllipse(Brushes.Chartreuse,
1328 new Rectangle((int) position.X, (int) position.Y, 4, 4)); 1350 new Rectangle((int) position.X, (int) position.Y, 4, 4));
1329 break; 1351 break;
1330 } 1352 }
1331 } 1353 }
1332 mapGraphics.DrawImage(mapImage, new Point(0, 0)); 1354 mapGraphics.DrawImage(mapImage, new Point(0, 0));
1333   1355  
1334 vassalForm.Invoke((MethodInvoker) (() => 1356 vassalForm.Invoke((MethodInvoker) (() =>
1335 { 1357 {
1336 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.StretchImage; 1358 RegionAvatarsMap.SizeMode = PictureBoxSizeMode.StretchImage;
1337 RegionAvatarsMap.Image = mapImage; 1359 RegionAvatarsMap.Image = mapImage;
1338 RegionAvatarsMap.Refresh(); 1360 RegionAvatarsMap.Refresh();
1339 })); 1361 }));
1340 } 1362 }
1341 catch (Exception) 1363 catch (Exception)
1342 { 1364 {
1343   1365  
1344 } 1366 }
1345 finally 1367 finally
1346 { 1368 {
1347 Monitor.Exit(ClientInstanceTeleportLock); 1369 Monitor.Exit(ClientInstanceTeleportLock);
1348 } 1370 }
1349   1371  
1350 }; 1372 };
1351 overviewTabTimer.Start(); 1373 overviewTabTimer.Start();
1352   1374  
1353 // Start the top scores timer. 1375 // Start the top scores timer.
1354 topScriptsTabTimer.Elapsed += (o, p) => 1376 topScriptsTabTimer.Elapsed += (o, p) =>
1355 { 1377 {
1356 if (!Monitor.TryEnter(ClientInstanceTeleportLock)) 1378 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1357 return; 1379 return;
1358   1380  
1359 try 1381 try
1360 { 1382 {
1361 // Do not do anything in case the tab is not selected. 1383 // Do not do anything in case the tab is not selected.
1362 vassalForm.Invoke((MethodInvoker) (() => 1384 vassalForm.Invoke((MethodInvoker) (() =>
1363 { 1385 {
1364 if (!Tabs.SelectedTab.Equals(TopScriptsTab)) 1386 if (!Tabs.SelectedTab.Equals(TopScriptsTab))
1365 throw new Exception(); 1387 throw new Exception();
1366 })); 1388 }));
1367   1389  
1368 // Get the statistics. 1390 // Get the statistics.
1369 string result = wasPOST(vassalConfiguration.HTTPServerURL, 1391 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1370 wasKeyValueEscape(new Dictionary<string, string> 1392 wasKeyValueEscape(new Dictionary<string, string>
1371 { 1393 {
1372 {"command", "getregiontop"}, 1394 {"command", "getregiontop"},
1373 {"group", vassalConfiguration.Group}, 1395 {"group", vassalConfiguration.Group},
1374 {"password", vassalConfiguration.Password}, 1396 {"password", vassalConfiguration.Password},
1375 {"type", "scripts"} 1397 {"type", "scripts"}
1376 }), vassalConfiguration.DataTimeout); 1398 }), vassalConfiguration.DataTimeout);
1377   1399  
1378 bool success; 1400 bool success;
1379 if (string.IsNullOrEmpty(result) || 1401 if (string.IsNullOrEmpty(result) ||
1380 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1402 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1381 throw new Exception(); 1403 throw new Exception();
1382   1404  
1383 HashSet<List<string>> data = 1405 HashSet<List<string>> data =
1384 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))) 1406 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1385 .Select((x, i) => new {Index = i, Value = x}) 1407 .Select((x, i) => new {Index = i, Value = x})
1386 .GroupBy(x => x.Index/5) 1408 .GroupBy(x => x.Index/5)
1387 .Select(x => x.Select(v => v.Value).ToList())); 1409 .Select(x => x.Select(v => v.Value).ToList()));
1388 if (data.Count.Equals(0)) 1410 if (data.Count.Equals(0))
1389 throw new Exception(); 1411 throw new Exception();
1390   1412  
1391 vassalForm.Invoke((MethodInvoker) (() => 1413 vassalForm.Invoke((MethodInvoker) (() =>
1392 { 1414 {
1393 // Remove rows that are not in the data update. 1415 // Remove rows that are not in the data update.
1394 foreach ( 1416 foreach (
1395 int index in 1417 int index in
1396 TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>() 1418 TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>()
1397 .Where( 1419 .Where(
1398 topScriptsRow => 1420 topScriptsRow =>
1399 !data.Any(q => q[2].Equals(topScriptsRow.Cells["TopScriptsUUID"].Value))) 1421 !data.Any(q => q[2].Equals(topScriptsRow.Cells["TopScriptsUUID"].Value)))
1400 .Select(q => q.Index)) 1422 .Select(q => q.Index))
1401 { 1423 {
1402 TopScriptsGridView.Rows.RemoveAt(index); 1424 TopScriptsGridView.Rows.RemoveAt(index);
1403 } 1425 }
1404 // Now update or add new data. 1426 // Now update or add new data.
1405 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5))) 1427 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5)))
1406 { 1428 {
1407 DataGridViewRow row = 1429 DataGridViewRow row =
1408 TopScriptsGridView.Rows.AsParallel() 1430 TopScriptsGridView.Rows.AsParallel()
1409 .Cast<DataGridViewRow>() 1431 .Cast<DataGridViewRow>()
1410 .FirstOrDefault(q => q.Cells["TopScriptsUUID"].Value.Equals(dataComponents[2])); 1432 .FirstOrDefault(q => q.Cells["TopScriptsUUID"].Value.Equals(dataComponents[2]));
1411 switch (row != null) 1433 switch (row != null)
1412 { 1434 {
1413 case true: // the row exists, so update it. 1435 case true: // the row exists, so update it.
1414 row.Cells["TopScriptsScore"].Value = dataComponents[0]; 1436 row.Cells["TopScriptsScore"].Value = dataComponents[0];
1415 row.Cells["TopScriptsTaskName"].Value = dataComponents[1]; 1437 row.Cells["TopScriptsTaskName"].Value = dataComponents[1];
1416 row.Cells["TopScriptsUUID"].Value = dataComponents[2]; 1438 row.Cells["TopScriptsUUID"].Value = dataComponents[2];
1417 row.Cells["TopScriptsOwner"].Value = dataComponents[3]; 1439 row.Cells["TopScriptsOwner"].Value = dataComponents[3];
1418 row.Cells["TopScriptsPosition"].Value = dataComponents[4]; 1440 row.Cells["TopScriptsPosition"].Value = dataComponents[4];
1419 break; 1441 break;
1420 case false: // the row dosn't exist, so add it. 1442 case false: // the row dosn't exist, so add it.
1421 TopScriptsGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2], 1443 TopScriptsGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2],
1422 dataComponents[3], dataComponents[4]); 1444 dataComponents[3], dataComponents[4]);
1423 break; 1445 break;
1424 } 1446 }
1425 } 1447 }
1426 })); 1448 }));
1427 } 1449 }
1428 catch (Exception) 1450 catch (Exception)
1429 { 1451 {
1430   1452  
1431 } 1453 }
1432 finally 1454 finally
1433 { 1455 {
1434 Monitor.Exit(ClientInstanceTeleportLock); 1456 Monitor.Exit(ClientInstanceTeleportLock);
1435 } 1457 }
1436 }; 1458 };
1437 topScriptsTabTimer.Start(); 1459 topScriptsTabTimer.Start();
1438   1460  
1439 // Start the top colliders timer. 1461 // Start the top colliders timer.
1440 topCollidersTabTimer.Elapsed += (o, p) => 1462 topCollidersTabTimer.Elapsed += (o, p) =>
1441 { 1463 {
1442 if (!Monitor.TryEnter(ClientInstanceTeleportLock)) 1464 if (!Monitor.TryEnter(ClientInstanceTeleportLock))
1443 return; 1465 return;
1444   1466  
1445 try 1467 try
1446 { 1468 {
1447 // Do not do anything in case the tab is not selected. 1469 // Do not do anything in case the tab is not selected.
1448 vassalForm.Invoke((MethodInvoker) (() => 1470 vassalForm.Invoke((MethodInvoker) (() =>
1449 { 1471 {
1450 if (!Tabs.SelectedTab.Equals(TopCollidersTab)) 1472 if (!Tabs.SelectedTab.Equals(TopCollidersTab))
1451 throw new Exception(); 1473 throw new Exception();
1452 })); 1474 }));
1453   1475  
1454 // Get the statistics. 1476 // Get the statistics.
1455 string result = wasPOST(vassalConfiguration.HTTPServerURL, 1477 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1456 wasKeyValueEscape(new Dictionary<string, string> 1478 wasKeyValueEscape(new Dictionary<string, string>
1457 { 1479 {
1458 {"command", "getregiontop"}, 1480 {"command", "getregiontop"},
1459 {"group", vassalConfiguration.Group}, 1481 {"group", vassalConfiguration.Group},
1460 {"password", vassalConfiguration.Password}, 1482 {"password", vassalConfiguration.Password},
1461 {"type", "colliders"} 1483 {"type", "colliders"}
1462 }), vassalConfiguration.DataTimeout); 1484 }), vassalConfiguration.DataTimeout);
1463   1485  
1464 bool success; 1486 bool success;
1465 if (string.IsNullOrEmpty(result) || 1487 if (string.IsNullOrEmpty(result) ||
1466 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1488 !bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1467 throw new Exception(); 1489 throw new Exception();
1468   1490  
1469 HashSet<List<string>> data = 1491 HashSet<List<string>> data =
1470 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))) 1492 new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
1471 .Select((x, i) => new {Index = i, Value = x}) 1493 .Select((x, i) => new {Index = i, Value = x})
1472 .GroupBy(x => x.Index/5) 1494 .GroupBy(x => x.Index/5)
1473 .Select(x => x.Select(v => v.Value).ToList())); 1495 .Select(x => x.Select(v => v.Value).ToList()));
1474 if (data.Count.Equals(0)) 1496 if (data.Count.Equals(0))
1475 throw new Exception(); 1497 throw new Exception();
1476   1498  
1477 vassalForm.Invoke((MethodInvoker) (() => 1499 vassalForm.Invoke((MethodInvoker) (() =>
1478 { 1500 {
1479 // Remove rows that are not in the data update. 1501 // Remove rows that are not in the data update.
1480 foreach ( 1502 foreach (
1481 int index in 1503 int index in
1482 TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>() 1504 TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>()
1483 .Where( 1505 .Where(
1484 topCollidersRow => 1506 topCollidersRow =>
1485 !data.Any(q => q[2].Equals(topCollidersRow.Cells["TopCollidersUUID"].Value))) 1507 !data.Any(q => q[2].Equals(topCollidersRow.Cells["TopCollidersUUID"].Value)))
1486 .Select(q => q.Index)) 1508 .Select(q => q.Index))
1487 { 1509 {
1488 TopCollidersGridView.Rows.RemoveAt(index); 1510 TopCollidersGridView.Rows.RemoveAt(index);
1489 } 1511 }
1490 // Now update or add new data. 1512 // Now update or add new data.
1491 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5))) 1513 foreach (List<string> dataComponents in data.Where(q => q.Count.Equals(5)))
1492 { 1514 {
1493 DataGridViewRow row = 1515 DataGridViewRow row =
1494 TopCollidersGridView.Rows.AsParallel() 1516 TopCollidersGridView.Rows.AsParallel()
1495 .Cast<DataGridViewRow>() 1517 .Cast<DataGridViewRow>()
1496 .FirstOrDefault(q => q.Cells["TopCollidersUUID"].Value.Equals(dataComponents[2])); 1518 .FirstOrDefault(q => q.Cells["TopCollidersUUID"].Value.Equals(dataComponents[2]));
1497 switch (row != null) 1519 switch (row != null)
1498 { 1520 {
1499 case true: // the row exists, so update it. 1521 case true: // the row exists, so update it.
1500 row.Cells["TopCollidersScore"].Value = dataComponents[0]; 1522 row.Cells["TopCollidersScore"].Value = dataComponents[0];
1501 row.Cells["TopSCollidersTaskName"].Value = dataComponents[1]; 1523 row.Cells["TopSCollidersTaskName"].Value = dataComponents[1];
1502 row.Cells["TopCollidersUUID"].Value = dataComponents[2]; 1524 row.Cells["TopCollidersUUID"].Value = dataComponents[2];
1503 row.Cells["TopCollidersOwner"].Value = dataComponents[3]; 1525 row.Cells["TopCollidersOwner"].Value = dataComponents[3];
1504 row.Cells["TopCollidersPosition"].Value = dataComponents[4]; 1526 row.Cells["TopCollidersPosition"].Value = dataComponents[4];
1505 break; 1527 break;
1506 case false: // the row dosn't exist, so add it. 1528 case false: // the row dosn't exist, so add it.
1507 TopCollidersGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2], 1529 TopCollidersGridView.Rows.Add(dataComponents[0], dataComponents[1], dataComponents[2],
1508 dataComponents[3], dataComponents[4]); 1530 dataComponents[3], dataComponents[4]);
1509 break; 1531 break;
1510 } 1532 }
1511 } 1533 }
1512   1534  
1513 })); 1535 }));
1514 } 1536 }
1515 catch (Exception) 1537 catch (Exception)
1516 { 1538 {
1517   1539  
1518 } 1540 }
1519 finally 1541 finally
1520 { 1542 {
1521 Monitor.Exit(ClientInstanceTeleportLock); 1543 Monitor.Exit(ClientInstanceTeleportLock);
1522 } 1544 }
1523 }; 1545 };
1524 topCollidersTabTimer.Start(); 1546 topCollidersTabTimer.Start();
1525 } 1547 }
1526   1548  
1527 private void RequestedEditRegions(object sender, EventArgs e) 1549 private void RequestedEditRegions(object sender, EventArgs e)
1528 { 1550 {
1529 // Clear any selection. 1551 // Clear any selection.
1530 LoadedRegions.SelectedIndex = -1; 1552 LoadedRegions.SelectedIndex = -1;
1531 RegionEditForm regionEditForm = new RegionEditForm {TopMost = true}; 1553 RegionEditForm regionEditForm = new RegionEditForm {TopMost = true};
1532 regionEditForm.Show(); 1554 regionEditForm.Show();
1533 } 1555 }
1534   1556  
1535 private void RequestSelecting(object sender, TabControlCancelEventArgs e) 1557 private void RequestSelecting(object sender, TabControlCancelEventArgs e)
1536 { 1558 {
1537 e.Cancel = !e.TabPage.Enabled; 1559 e.Cancel = !e.TabPage.Enabled;
1538 } 1560 }
1539   1561  
1540 private void RequestExportTopScripts(object sender, EventArgs e) 1562 private void RequestExportTopScripts(object sender, EventArgs e)
1541 { 1563 {
1542 vassalForm.BeginInvoke((MethodInvoker) (() => 1564 vassalForm.BeginInvoke((MethodInvoker) (() =>
1543 { 1565 {
1544 switch (vassalForm.ExportCSVDialog.ShowDialog()) 1566 switch (vassalForm.ExportCSVDialog.ShowDialog())
1545 { 1567 {
1546 case DialogResult.OK: 1568 case DialogResult.OK:
1547 string file = vassalForm.ExportCSVDialog.FileName; 1569 string file = vassalForm.ExportCSVDialog.FileName;
1548 new Thread(() => 1570 new Thread(() =>
1549 { 1571 {
1550 vassalForm.BeginInvoke((MethodInvoker) (() => 1572 vassalForm.BeginInvoke((MethodInvoker) (() =>
1551 { 1573 {
1552 try 1574 try
1553 { 1575 {
1554 vassalForm.StatusText.Text = @"exporting..."; 1576 vassalForm.StatusText.Text = @"exporting...";
1555 vassalForm.StatusProgress.Value = 0; 1577 vassalForm.StatusProgress.Value = 0;
1556   1578  
1557 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8)) 1579 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
1558 { 1580 {
1559 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows) 1581 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows)
1560 { 1582 {
1561 streamWriter.WriteLine(wasEnumerableToCSV(new[] 1583 streamWriter.WriteLine(wasEnumerableToCSV(new[]
1562 { 1584 {
1563 topScriptsRow.Cells["TopScriptsScore"].Value.ToString(), 1585 topScriptsRow.Cells["TopScriptsScore"].Value.ToString(),
1564 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString(), 1586 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString(),
1565 topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(), 1587 topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(),
1566 topScriptsRow.Cells["TopScriptsOwner"].Value.ToString(), 1588 topScriptsRow.Cells["TopScriptsOwner"].Value.ToString(),
1567 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString() 1589 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString()
1568 })); 1590 }));
1569 } 1591 }
1570 } 1592 }
1571   1593  
1572 vassalForm.StatusText.Text = @"exported"; 1594 vassalForm.StatusText.Text = @"exported";
1573 vassalForm.StatusProgress.Value = 100; 1595 vassalForm.StatusProgress.Value = 100;
1574 } 1596 }
1575 catch (Exception ex) 1597 catch (Exception ex)
1576 { 1598 {
1577 vassalForm.StatusText.Text = ex.Message; 1599 vassalForm.StatusText.Text = ex.Message;
1578 } 1600 }
1579 })); 1601 }));
1580 }) 1602 })
1581 {IsBackground = true, Priority = ThreadPriority.Normal}.Start(); 1603 {IsBackground = true, Priority = ThreadPriority.Normal}.Start();
1582 break; 1604 break;
1583 } 1605 }
1584 })); 1606 }));
1585 } 1607 }
1586   1608  
1587 private void RequestExportTopColliders(object sender, EventArgs e) 1609 private void RequestExportTopColliders(object sender, EventArgs e)
1588 { 1610 {
1589 vassalForm.BeginInvoke((MethodInvoker) (() => 1611 vassalForm.BeginInvoke((MethodInvoker) (() =>
1590 { 1612 {
1591 switch (vassalForm.ExportCSVDialog.ShowDialog()) 1613 switch (vassalForm.ExportCSVDialog.ShowDialog())
1592 { 1614 {
1593 case DialogResult.OK: 1615 case DialogResult.OK:
1594 string file = vassalForm.ExportCSVDialog.FileName; 1616 string file = vassalForm.ExportCSVDialog.FileName;
1595 new Thread(() => 1617 new Thread(() =>
1596 { 1618 {
1597 vassalForm.BeginInvoke((MethodInvoker) (() => 1619 vassalForm.BeginInvoke((MethodInvoker) (() =>
1598 { 1620 {
1599 try 1621 try
1600 { 1622 {
1601 vassalForm.StatusText.Text = @"exporting..."; 1623 vassalForm.StatusText.Text = @"exporting...";
1602 vassalForm.StatusProgress.Value = 0; 1624 vassalForm.StatusProgress.Value = 0;
1603   1625  
1604 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8)) 1626 using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
1605 { 1627 {
1606 foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows) 1628 foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows)
1607 { 1629 {
1608 streamWriter.WriteLine(wasEnumerableToCSV(new[] 1630 streamWriter.WriteLine(wasEnumerableToCSV(new[]
1609 { 1631 {
1610 topCollidersRow.Cells["TopCollidersScore"].Value.ToString(), 1632 topCollidersRow.Cells["TopCollidersScore"].Value.ToString(),
1611 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString(), 1633 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString(),
1612 topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(), 1634 topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(),
1613 topCollidersRow.Cells["TopCollidersOwner"].Value.ToString(), 1635 topCollidersRow.Cells["TopCollidersOwner"].Value.ToString(),
1614 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString() 1636 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString()
1615 })); 1637 }));
1616 } 1638 }
1617 } 1639 }
1618   1640  
1619 vassalForm.StatusText.Text = @"exported"; 1641 vassalForm.StatusText.Text = @"exported";
1620 vassalForm.StatusProgress.Value = 100; 1642 vassalForm.StatusProgress.Value = 100;
1621 } 1643 }
1622 catch (Exception ex) 1644 catch (Exception ex)
1623 { 1645 {
1624 vassalForm.StatusText.Text = ex.Message; 1646 vassalForm.StatusText.Text = ex.Message;
1625 } 1647 }
1626 })); 1648 }));
1627 }) 1649 })
1628 {IsBackground = true, Priority = ThreadPriority.Normal}.Start(); 1650 {IsBackground = true, Priority = ThreadPriority.Normal}.Start();
1629 break; 1651 break;
1630 } 1652 }
1631 })); 1653 }));
1632 } 1654 }
1633   1655  
1634 private void RequestFilterTopScripts(object sender, EventArgs e) 1656 private void RequestFilterTopScripts(object sender, EventArgs e)
1635 { 1657 {
1636 vassalForm.BeginInvoke((MethodInvoker) (() => 1658 vassalForm.BeginInvoke((MethodInvoker) (() =>
1637 { 1659 {
1638 Regex topScriptsRowRegex; 1660 Regex topScriptsRowRegex;
1639 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text)) 1661 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
1640 { 1662 {
1641 case true: 1663 case true:
1642 topScriptsRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled); 1664 topScriptsRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
1643 break; 1665 break;
1644 default: 1666 default:
1645 topScriptsRowRegex = new Regex(@".+?", RegexOptions.Compiled); 1667 topScriptsRowRegex = new Regex(@".+?", RegexOptions.Compiled);
1646 break; 1668 break;
1647 } 1669 }
1648 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>()) 1670 foreach (DataGridViewRow topScriptsRow in TopScriptsGridView.Rows.AsParallel().Cast<DataGridViewRow>())
1649 { 1671 {
1650 topScriptsRow.Visible = 1672 topScriptsRow.Visible =
1651 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsScore"].Value.ToString()) || 1673 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsScore"].Value.ToString()) ||
1652 topScriptsRowRegex.IsMatch( 1674 topScriptsRowRegex.IsMatch(
1653 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString()) || 1675 topScriptsRow.Cells["TopScriptsTaskName"].Value.ToString()) ||
1654 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString()) || 1676 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString()) ||
1655 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsOwner"].Value.ToString()) || 1677 topScriptsRowRegex.IsMatch(topScriptsRow.Cells["TopScriptsOwner"].Value.ToString()) ||
1656 topScriptsRowRegex.IsMatch( 1678 topScriptsRowRegex.IsMatch(
1657 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString()); 1679 topScriptsRow.Cells["TopScriptsPosition"].Value.ToString());
1658 } 1680 }
1659 })); 1681 }));
1660 } 1682 }
1661   1683  
1662 private void RequestFilterTopColliders(object sender, EventArgs e) 1684 private void RequestFilterTopColliders(object sender, EventArgs e)
1663 { 1685 {
1664 vassalForm.BeginInvoke((MethodInvoker)(() => 1686 vassalForm.BeginInvoke((MethodInvoker)(() =>
1665 { 1687 {
1666 Regex topCollidersRowRegex; 1688 Regex topCollidersRowRegex;
1667 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text)) 1689 switch (!string.IsNullOrEmpty(TopScriptsFilter.Text))
1668 { 1690 {
1669 case true: 1691 case true:
1670 topCollidersRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled); 1692 topCollidersRowRegex = new Regex(TopScriptsFilter.Text, RegexOptions.Compiled);
1671 break; 1693 break;
1672 default: 1694 default:
1673 topCollidersRowRegex = new Regex(@".+?", RegexOptions.Compiled); 1695 topCollidersRowRegex = new Regex(@".+?", RegexOptions.Compiled);
1674 break; 1696 break;
1675 } 1697 }
1676 foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>()) 1698 foreach (DataGridViewRow topCollidersRow in TopCollidersGridView.Rows.AsParallel().Cast<DataGridViewRow>())
1677 { 1699 {
1678 topCollidersRow.Visible = 1700 topCollidersRow.Visible =
1679 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersScore"].Value.ToString()) || 1701 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersScore"].Value.ToString()) ||
1680 topCollidersRowRegex.IsMatch( 1702 topCollidersRowRegex.IsMatch(
1681 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString()) || 1703 topCollidersRow.Cells["TopCollidersTaskName"].Value.ToString()) ||
1682 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString()) || 1704 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString()) ||
1683 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersOwner"].Value.ToString()) || 1705 topCollidersRowRegex.IsMatch(topCollidersRow.Cells["TopCollidersOwner"].Value.ToString()) ||
1684 topCollidersRowRegex.IsMatch( 1706 topCollidersRowRegex.IsMatch(
1685 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString()); 1707 topCollidersRow.Cells["TopCollidersPosition"].Value.ToString());
1686 } 1708 }
1687 })); 1709 }));
1688 } 1710 }
1689   1711  
1690 private void RequestReturnTopScriptsObjects(object sender, EventArgs e) 1712 private void RequestReturnTopScriptsObjects(object sender, EventArgs e)
1691 { 1713 {
1692 // Block teleports and disable button. 1714 // Block teleports and disable button.
1693 vassalForm.Invoke((MethodInvoker) (() => 1715 vassalForm.Invoke((MethodInvoker) (() =>
1694 { 1716 {
1695 vassalForm.ReturnTopScriptsButton.Enabled = false; 1717 vassalForm.ReturnTopScriptsButton.Enabled = false;
1696 RegionTeleportGroup.Enabled = false; 1718 RegionTeleportGroup.Enabled = false;
1697 })); 1719 }));
1698   1720  
1699 // Enqueue all the UUIDs to return. 1721 // Enqueue all the UUIDs to return.
1700 Queue<KeyValuePair<UUID, Vector3>> returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>(); 1722 Queue<KeyValuePair<UUID, Vector3>> returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>();
1701 vassalForm.Invoke((MethodInvoker) (() => 1723 vassalForm.Invoke((MethodInvoker) (() =>
1702 { 1724 {
1703 foreach ( 1725 foreach (
1704 DataGridViewRow topScriptsRow in 1726 DataGridViewRow topScriptsRow in
1705 TopScriptsGridView.Rows.AsParallel() 1727 TopScriptsGridView.Rows.AsParallel()
1706 .Cast<DataGridViewRow>() 1728 .Cast<DataGridViewRow>()
1707 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected))) 1729 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
1708 { 1730 {
1709 Vector3 objectPosition; 1731 Vector3 objectPosition;
1710 UUID returnUUID; 1732 UUID returnUUID;
1711 if (!UUID.TryParse(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(), out returnUUID) || 1733 if (!UUID.TryParse(topScriptsRow.Cells["TopScriptsUUID"].Value.ToString(), out returnUUID) ||
1712 !Vector3.TryParse(topScriptsRow.Cells["TopScriptsPosition"].Value.ToString(), out objectPosition)) 1734 !Vector3.TryParse(topScriptsRow.Cells["TopScriptsPosition"].Value.ToString(), out objectPosition))
1713 continue; 1735 continue;
1714 returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition)); 1736 returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
1715 } 1737 }
1716 })); 1738 }));
1717   1739  
1718 // If no rows were selected, enable teleports, the return button and return. 1740 // If no rows were selected, enable teleports, the return button and return.
1719 if (returnUUIDs.Count.Equals(0)) 1741 if (returnUUIDs.Count.Equals(0))
1720 { 1742 {
1721 vassalForm.Invoke((MethodInvoker)(() => 1743 vassalForm.Invoke((MethodInvoker)(() =>
1722 { 1744 {
1723 vassalForm.ReturnTopScriptsButton.Enabled = true; 1745 vassalForm.ReturnTopScriptsButton.Enabled = true;
1724 RegionTeleportGroup.Enabled = true; 1746 RegionTeleportGroup.Enabled = true;
1725 })); 1747 }));
1726 return; 1748 return;
1727 } 1749 }
1728   1750  
1729 new Thread(() => 1751 new Thread(() =>
1730 { 1752 {
1731 Monitor.Enter(ClientInstanceTeleportLock); 1753 Monitor.Enter(ClientInstanceTeleportLock);
1732   1754  
1733 try 1755 try
1734 { 1756 {
1735 vassalForm.Invoke((MethodInvoker) (() => 1757 vassalForm.Invoke((MethodInvoker) (() =>
1736 { 1758 {
1737 vassalForm.StatusProgress.Value = 0; 1759 vassalForm.StatusProgress.Value = 0;
1738 })); 1760 }));
1739 int totalObjects = returnUUIDs.Count; 1761 int totalObjects = returnUUIDs.Count;
1740 do 1762 do
1741 { 1763 {
1742 // Dequeue the first object. 1764 // Dequeue the first object.
1743 KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue(); 1765 KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue();
1744   1766  
1745 vassalForm.Invoke((MethodInvoker) (() => 1767 vassalForm.Invoke((MethodInvoker) (() =>
1746 { 1768 {
1747 vassalForm.StatusText.Text = @"Returning object UUID: " + objectData.Key.ToString(); 1769 vassalForm.StatusText.Text = @"Returning object UUID: " + objectData.Key.ToString();
1748 })); 1770 }));
1749   1771  
1750 string currentRegionName = string.Empty; 1772 string currentRegionName = string.Empty;
1751 vassalForm.Invoke((MethodInvoker) (() => 1773 vassalForm.Invoke((MethodInvoker) (() =>
1752 { 1774 {
1753 currentRegionName = CurrentRegionName.Text; 1775 currentRegionName = CurrentRegionName.Text;
1754 })); 1776 }));
1755 1777
1756 // Teleport to the object. 1778 // Teleport to the object.
1757 string result = wasPOST(vassalConfiguration.HTTPServerURL, 1779 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1758 wasKeyValueEscape(new Dictionary<string, string> 1780 wasKeyValueEscape(new Dictionary<string, string>
1759 { 1781 {
1760 {"command", "teleport"}, 1782 {"command", "teleport"},
1761 {"group", vassalConfiguration.Group}, 1783 {"group", vassalConfiguration.Group},
1762 {"password", vassalConfiguration.Password}, 1784 {"password", vassalConfiguration.Password},
1763 {"position", objectData.Value.ToString()}, 1785 {"position", objectData.Value.ToString()},
1764 {"region", currentRegionName}, 1786 {"region", currentRegionName},
1765 {"fly", "True"} 1787 {"fly", "True"}
1766 }), vassalConfiguration.TeleportTimeout); 1788 }), vassalConfiguration.TeleportTimeout);
1767   1789  
1768 if (string.IsNullOrEmpty(result)) 1790 if (string.IsNullOrEmpty(result))
1769 { 1791 {
1770 vassalForm.Invoke((MethodInvoker)(() => 1792 vassalForm.Invoke((MethodInvoker)(() =>
1771 { 1793 {
1772 vassalForm.StatusText.Text = @"Error communicating with Corrade."; 1794 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
1773 })); 1795 }));
1774 continue; 1796 continue;
1775 } 1797 }
1776   1798  
1777 // Return the object. 1799 // Return the object.
1778 result = wasPOST(vassalConfiguration.HTTPServerURL, 1800 result = wasPOST(vassalConfiguration.HTTPServerURL,
1779 wasKeyValueEscape(new Dictionary<string, string> 1801 wasKeyValueEscape(new Dictionary<string, string>
1780 { 1802 {
1781 {"command", "derez"}, 1803 {"command", "derez"},
1782 {"group", vassalConfiguration.Group}, 1804 {"group", vassalConfiguration.Group},
1783 {"password", vassalConfiguration.Password}, 1805 {"password", vassalConfiguration.Password},
1784 {"item", objectData.Key.ToString()}, 1806 {"item", objectData.Key.ToString()},
1785 {"range", "32" }, // maximal prim size = 64 - middle bounding box at half 1807 {"range", "32" }, // maximal prim size = 64 - middle bounding box at half
1786 {"type", "ReturnToOwner"} 1808 {"type", "ReturnToOwner"}
1787 }), vassalConfiguration.DataTimeout); 1809 }), vassalConfiguration.DataTimeout);
1788   1810  
1789 if (string.IsNullOrEmpty(result)) 1811 if (string.IsNullOrEmpty(result))
1790 { 1812 {
1791 vassalForm.Invoke((MethodInvoker) (() => 1813 vassalForm.Invoke((MethodInvoker) (() =>
1792 { 1814 {
1793 vassalForm.StatusText.Text = @"Error communicating with Corrade."; 1815 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
1794 })); 1816 }));
1795 continue; 1817 continue;
1796 } 1818 }
1797   1819  
1798 bool success; 1820 bool success;
1799 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1821 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1800 { 1822 {
1801 vassalForm.Invoke((MethodInvoker) (() => 1823 vassalForm.Invoke((MethodInvoker) (() =>
1802 { 1824 {
1803 vassalForm.StatusText.Text = @"No success status could be retrieved. "; 1825 vassalForm.StatusText.Text = @"No success status could be retrieved. ";
1804 })); 1826 }));
1805 continue; 1827 continue;
1806 } 1828 }
1807   1829  
1808 switch (success) 1830 switch (success)
1809 { 1831 {
1810 case true: 1832 case true:
1811 vassalForm.Invoke((MethodInvoker) (() => 1833 vassalForm.Invoke((MethodInvoker) (() =>
1812 { 1834 {
1813 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString(); 1835 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString();
1814 // Remove the row from the grid view. 1836 // Remove the row from the grid view.
1815 DataGridViewRow row = 1837 DataGridViewRow row =
1816 TopScriptsGridView.Rows.AsParallel() 1838 TopScriptsGridView.Rows.AsParallel()
1817 .Cast<DataGridViewRow>() 1839 .Cast<DataGridViewRow>()
1818 .FirstOrDefault( 1840 .FirstOrDefault(
1819 o => o.Cells["TopScriptsUUID"].Value.Equals(objectData.Key.ToString())); 1841 o => o.Cells["TopScriptsUUID"].Value.Equals(objectData.Key.ToString()));
1820 if (row == null) return; 1842 if (row == null) return;
1821 int i = row.Index; 1843 int i = row.Index;
1822 TopScriptsGridView.Rows.RemoveAt(i); 1844 TopScriptsGridView.Rows.RemoveAt(i);
1823 })); 1845 }));
1824 break; 1846 break;
1825 case false: 1847 case false:
1826 vassalForm.Invoke((MethodInvoker) (() => 1848 vassalForm.Invoke((MethodInvoker) (() =>
1827 { 1849 {
1828 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() + 1850 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() +
1829 @": " + 1851 @": " +
1830 wasInput(wasKeyValueGet("error", result)); 1852 wasInput(wasKeyValueGet("error", result));
1831 })); 1853 }));
1832 break; 1854 break;
1833 } 1855 }
1834   1856  
1835 vassalForm.Invoke((MethodInvoker) (() => 1857 vassalForm.Invoke((MethodInvoker) (() =>
1836 { 1858 {
1837 vassalForm.StatusProgress.Value = 1859 vassalForm.StatusProgress.Value =
1838 Math.Min((int) (Math.Abs(returnUUIDs.Count - totalObjects)/ 1860 Math.Min((int) (Math.Abs(returnUUIDs.Count - totalObjects)/
1839 (double) totalObjects), 100); 1861 (double) totalObjects), 100);
1840 })); 1862 }));
1841 } while (!returnUUIDs.Count.Equals(0)); 1863 } while (!returnUUIDs.Count.Equals(0));
1842 vassalForm.Invoke((MethodInvoker) (() => 1864 vassalForm.Invoke((MethodInvoker) (() =>
1843 { 1865 {
1844 vassalForm.StatusProgress.Value = 100; 1866 vassalForm.StatusProgress.Value = 100;
1845 })); 1867 }));
1846 } 1868 }
1847 catch (Exception ex) 1869 catch (Exception ex)
1848 { 1870 {
1849 vassalForm.Invoke((MethodInvoker)(() => 1871 vassalForm.Invoke((MethodInvoker)(() =>
1850 { 1872 {
1851 vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message; 1873 vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message;
1852 })); 1874 }));
1853 } 1875 }
1854 finally 1876 finally
1855 { 1877 {
1856 Monitor.Exit(ClientInstanceTeleportLock); 1878 Monitor.Exit(ClientInstanceTeleportLock);
1857 // Allow teleports and enable button. 1879 // Allow teleports and enable button.
1858 vassalForm.BeginInvoke((MethodInvoker)(() => 1880 vassalForm.BeginInvoke((MethodInvoker)(() =>
1859 { 1881 {
1860 vassalForm.ReturnTopScriptsButton.Enabled = true; 1882 vassalForm.ReturnTopScriptsButton.Enabled = true;
1861 RegionTeleportGroup.Enabled = true; 1883 RegionTeleportGroup.Enabled = true;
1862 })); 1884 }));
1863 } 1885 }
1864 }) 1886 })
1865 {IsBackground = true}.Start(); 1887 {IsBackground = true}.Start();
1866 } 1888 }
1867   1889  
1868 private void RequestReturnTopCollidersObjects(object sender, EventArgs e) 1890 private void RequestReturnTopCollidersObjects(object sender, EventArgs e)
1869 { 1891 {
1870 // Block teleports and disable button. 1892 // Block teleports and disable button.
1871 vassalForm.Invoke((MethodInvoker)(() => 1893 vassalForm.Invoke((MethodInvoker)(() =>
1872 { 1894 {
1873 vassalForm.ReturnTopCollidersButton.Enabled = false; 1895 vassalForm.ReturnTopCollidersButton.Enabled = false;
1874 RegionTeleportGroup.Enabled = false; 1896 RegionTeleportGroup.Enabled = false;
1875 })); 1897 }));
1876   1898  
1877 // Enqueue all the UUIDs to return. 1899 // Enqueue all the UUIDs to return.
1878 Queue<KeyValuePair<UUID, Vector3>> returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>(); 1900 Queue<KeyValuePair<UUID, Vector3>> returnUUIDs = new Queue<KeyValuePair<UUID, Vector3>>();
1879 vassalForm.Invoke((MethodInvoker)(() => 1901 vassalForm.Invoke((MethodInvoker)(() =>
1880 { 1902 {
1881 foreach ( 1903 foreach (
1882 DataGridViewRow topCollidersRow in 1904 DataGridViewRow topCollidersRow in
1883 TopCollidersGridView.Rows.AsParallel() 1905 TopCollidersGridView.Rows.AsParallel()
1884 .Cast<DataGridViewRow>() 1906 .Cast<DataGridViewRow>()
1885 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected))) 1907 .Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
1886 { 1908 {
1887 Vector3 objectPosition; 1909 Vector3 objectPosition;
1888 UUID returnUUID; 1910 UUID returnUUID;
1889 if (!UUID.TryParse(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(), out returnUUID) || 1911 if (!UUID.TryParse(topCollidersRow.Cells["TopCollidersUUID"].Value.ToString(), out returnUUID) ||
1890 !Vector3.TryParse(topCollidersRow.Cells["TopCollidersPosition"].Value.ToString(), out objectPosition)) 1912 !Vector3.TryParse(topCollidersRow.Cells["TopCollidersPosition"].Value.ToString(), out objectPosition))
1891 continue; 1913 continue;
1892 returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition)); 1914 returnUUIDs.Enqueue(new KeyValuePair<UUID, Vector3>(returnUUID, objectPosition));
1893 } 1915 }
1894 })); 1916 }));
1895   1917  
1896 // If no rows were selected, enable teleports, the return button and return. 1918 // If no rows were selected, enable teleports, the return button and return.
1897 if (returnUUIDs.Count.Equals(0)) 1919 if (returnUUIDs.Count.Equals(0))
1898 { 1920 {
1899 vassalForm.Invoke((MethodInvoker)(() => 1921 vassalForm.Invoke((MethodInvoker)(() =>
1900 { 1922 {
1901 vassalForm.ReturnTopCollidersButton.Enabled = true; 1923 vassalForm.ReturnTopCollidersButton.Enabled = true;
1902 RegionTeleportGroup.Enabled = true; 1924 RegionTeleportGroup.Enabled = true;
1903 })); 1925 }));
1904 return; 1926 return;
1905 } 1927 }
1906   1928  
1907 new Thread(() => 1929 new Thread(() =>
1908 { 1930 {
1909 Monitor.Enter(ClientInstanceTeleportLock); 1931 Monitor.Enter(ClientInstanceTeleportLock);
1910   1932  
1911 try 1933 try
1912 { 1934 {
1913 vassalForm.Invoke((MethodInvoker)(() => 1935 vassalForm.Invoke((MethodInvoker)(() =>
1914 { 1936 {
1915 vassalForm.StatusProgress.Value = 0; 1937 vassalForm.StatusProgress.Value = 0;
1916 })); 1938 }));
1917 int totalObjects = returnUUIDs.Count; 1939 int totalObjects = returnUUIDs.Count;
1918 do 1940 do
1919 { 1941 {
1920 // Dequeue the first object. 1942 // Dequeue the first object.
1921 KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue(); 1943 KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue();
1922   1944  
1923 vassalForm.Invoke((MethodInvoker)(() => 1945 vassalForm.Invoke((MethodInvoker)(() =>
1924 { 1946 {
1925 vassalForm.StatusText.Text = @"Returning UUID: " + objectData.Key.ToString(); 1947 vassalForm.StatusText.Text = @"Returning UUID: " + objectData.Key.ToString();
1926 })); 1948 }));
1927   1949  
1928 string currentRegionName = string.Empty; 1950 string currentRegionName = string.Empty;
1929 vassalForm.Invoke((MethodInvoker)(() => 1951 vassalForm.Invoke((MethodInvoker)(() =>
1930 { 1952 {
1931 currentRegionName = CurrentRegionName.Text; 1953 currentRegionName = CurrentRegionName.Text;
1932 })); 1954 }));
1933   1955  
1934 // Teleport to the object. 1956 // Teleport to the object.
1935 string result = wasPOST(vassalConfiguration.HTTPServerURL, 1957 string result = wasPOST(vassalConfiguration.HTTPServerURL,
1936 wasKeyValueEscape(new Dictionary<string, string> 1958 wasKeyValueEscape(new Dictionary<string, string>
1937 { 1959 {
1938 {"command", "teleport"}, 1960 {"command", "teleport"},
1939 {"group", vassalConfiguration.Group}, 1961 {"group", vassalConfiguration.Group},
1940 {"password", vassalConfiguration.Password}, 1962 {"password", vassalConfiguration.Password},
1941 {"position", objectData.Value.ToString()}, 1963 {"position", objectData.Value.ToString()},
1942 {"region", currentRegionName}, 1964 {"region", currentRegionName},
1943 {"fly", "True"} 1965 {"fly", "True"}
1944 }), vassalConfiguration.DataTimeout); 1966 }), vassalConfiguration.DataTimeout);
1945   1967  
1946 if (string.IsNullOrEmpty(result)) 1968 if (string.IsNullOrEmpty(result))
1947 { 1969 {
1948 vassalForm.Invoke((MethodInvoker)(() => 1970 vassalForm.Invoke((MethodInvoker)(() =>
1949 { 1971 {
1950 vassalForm.StatusText.Text = @"Error communicating with Corrade."; 1972 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
1951 })); 1973 }));
1952 continue; 1974 continue;
1953 } 1975 }
1954   1976  
1955 // Return the object. 1977 // Return the object.
1956 result = wasPOST(vassalConfiguration.HTTPServerURL, 1978 result = wasPOST(vassalConfiguration.HTTPServerURL,
1957 wasKeyValueEscape(new Dictionary<string, string> 1979 wasKeyValueEscape(new Dictionary<string, string>
1958 { 1980 {
1959 {"command", "derez"}, 1981 {"command", "derez"},
1960 {"group", vassalConfiguration.Group}, 1982 {"group", vassalConfiguration.Group},
1961 {"password", vassalConfiguration.Password}, 1983 {"password", vassalConfiguration.Password},
1962 {"item", objectData.Key.ToString()}, 1984 {"item", objectData.Key.ToString()},
1963 {"range", "32" }, // maximal prim size = 64 - middle bounding box at half 1985 {"range", "32" }, // maximal prim size = 64 - middle bounding box at half
1964 {"type", "ReturnToOwner"} 1986 {"type", "ReturnToOwner"}
1965 }), vassalConfiguration.DataTimeout); 1987 }), vassalConfiguration.DataTimeout);
1966   1988  
1967 if (string.IsNullOrEmpty(result)) 1989 if (string.IsNullOrEmpty(result))
1968 { 1990 {
1969 vassalForm.Invoke((MethodInvoker)(() => 1991 vassalForm.Invoke((MethodInvoker)(() =>
1970 { 1992 {
1971 vassalForm.StatusText.Text = @"Error communicating with Corrade."; 1993 vassalForm.StatusText.Text = @"Error communicating with Corrade.";
1972 })); 1994 }));
1973 continue; 1995 continue;
1974 } 1996 }
1975   1997  
1976 bool success; 1998 bool success;
1977 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success)) 1999 if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
1978 { 2000 {
1979 vassalForm.Invoke((MethodInvoker)(() => 2001 vassalForm.Invoke((MethodInvoker)(() =>
1980 { 2002 {
1981 vassalForm.StatusText.Text = @"No success status could be retrieved. "; 2003 vassalForm.StatusText.Text = @"No success status could be retrieved. ";
1982 })); 2004 }));
1983 continue; 2005 continue;
1984 } 2006 }
1985   2007  
1986 switch (success) 2008 switch (success)
1987 { 2009 {
1988 case true: 2010 case true:
1989 vassalForm.Invoke((MethodInvoker)(() => 2011 vassalForm.Invoke((MethodInvoker)(() =>
1990 { 2012 {
1991 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString(); 2013 vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString();
1992 // Remove the row from the grid view. 2014 // Remove the row from the grid view.
1993 DataGridViewRow row = 2015 DataGridViewRow row =
1994 TopCollidersGridView.Rows.AsParallel() 2016 TopCollidersGridView.Rows.AsParallel()
1995 .Cast<DataGridViewRow>() 2017 .Cast<DataGridViewRow>()
1996 .FirstOrDefault( 2018 .FirstOrDefault(
1997 o => o.Cells["TopCollidersUUID"].Value.Equals(objectData.Key.ToString())); 2019 o => o.Cells["TopCollidersUUID"].Value.Equals(objectData.Key.ToString()));
1998 if (row == null) return; 2020 if (row == null) return;
1999 int i = row.Index; 2021 int i = row.Index;
2000 TopCollidersGridView.Rows.RemoveAt(i); 2022 TopCollidersGridView.Rows.RemoveAt(i);
2001 })); 2023 }));
2002 break; 2024 break;
2003 case false: 2025 case false:
2004 vassalForm.Invoke((MethodInvoker)(() => 2026 vassalForm.Invoke((MethodInvoker)(() =>
2005 { 2027 {
2006 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() + 2028 vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() +
2007 @": " + 2029 @": " +
2008 wasInput(wasKeyValueGet("error", result)); 2030 wasInput(wasKeyValueGet("error", result));
2009 })); 2031 }));
2010 break; 2032 break;
2011 } 2033 }
2012   2034  
2013 vassalForm.Invoke((MethodInvoker)(() => 2035 vassalForm.Invoke((MethodInvoker)(() =>
2014 { 2036 {
2015 vassalForm.StatusProgress.Value = 2037 vassalForm.StatusProgress.Value =
2016 Math.Min((int)(Math.Abs(returnUUIDs.Count - totalObjects) / 2038 Math.Min((int)(Math.Abs(returnUUIDs.Count - totalObjects) /
2017 (double)totalObjects), 100); 2039 (double)totalObjects), 100);
2018 })); 2040 }));
2019 } while (!returnUUIDs.Count.Equals(0)); 2041 } while (!returnUUIDs.Count.Equals(0));
2020 vassalForm.Invoke((MethodInvoker)(() => 2042 vassalForm.Invoke((MethodInvoker)(() =>
2021 { 2043 {
2022 vassalForm.StatusProgress.Value = 100; 2044 vassalForm.StatusProgress.Value = 100;
2023 })); 2045 }));
2024 } 2046 }
2025 catch (Exception ex) 2047 catch (Exception ex)
2026 { 2048 {
2027 vassalForm.Invoke((MethodInvoker)(() => 2049 vassalForm.Invoke((MethodInvoker)(() =>
2028 { 2050 {
2029 vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message; 2051 vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message;
2030 })); 2052 }));
2031 } 2053 }
2032 finally 2054 finally
2033 { 2055 {
2034 Monitor.Exit(ClientInstanceTeleportLock); 2056 Monitor.Exit(ClientInstanceTeleportLock);
2035 // Allow teleports and enable button. 2057 // Allow teleports and enable button.
2036 vassalForm.BeginInvoke((MethodInvoker)(() => 2058 vassalForm.BeginInvoke((MethodInvoker)(() =>
2037 { 2059 {
2038 vassalForm.ReturnTopScriptsButton.Enabled = true; 2060 vassalForm.ReturnTopScriptsButton.Enabled = true;
2039 RegionTeleportGroup.Enabled = true; 2061 RegionTeleportGroup.Enabled = true;
2040 })); 2062 }));
2041 } 2063 }
2042 }) 2064 })
2043 { IsBackground = true }.Start(); 2065 { IsBackground = true }.Start();
2044 } 2066 }
2045   2067  
2046 private void RequestBatchRestart(object sender, EventArgs e) 2068 private void RequestBatchRestart(object sender, EventArgs e)
2047 { 2069 {
2048   2070  
2049 } 2071 }
2050 } 2072 }
2051 } 2073 }
2052   2074