corrade-vassal

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 7  →  ?path2? @ 8
/Vassal/Vassal/VassalForm.cs
@@ -5,10 +5,7 @@
///////////////////////////////////////////////////////////////////////////
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
@@ -18,7 +15,6 @@
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Timers;
using System.Threading;
using System.Web;
using System.Windows.Forms;
@@ -30,12 +26,14 @@
{
public partial class Vassal : Form
{
public static System.Timers.Timer overviewTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static System.Timers.Timer residentListTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static System.Timers.Timer topScriptsTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static System.Timers.Timer topCollidersTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static System.Timers.Timer regionsStateTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static volatile int regionsStateCheckIndex = 0;
public static Timer vassalTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static Timer overviewTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static Timer residentListTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static Timer estateTopTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static Timer regionsStateTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static Timer estateTexturesTabTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
public static Image[] groundTextureImages = new Image[4];
public static volatile int regionsStateCheckIndex;
public static VassalConfiguration vassalConfiguration = new VassalConfiguration();
public static Vassal vassalForm;
public static readonly object ClientInstanceTeleportLock = new object();
@@ -42,175 +40,135 @@
public static readonly object RegionsStateCheckLock = new object();
 
/// <summary>
/// Linden constants.
/// Corrade's input filter function.
/// </summary>
public struct LINDEN_CONSTANTS
private static readonly Func<string, string> wasInput = o =>
{
public struct ALERTS
{
public const string NO_ROOM_TO_SIT_HERE = @"No room to sit here, try another spot.";
if (string.IsNullOrEmpty(o)) return string.Empty;
 
public const string UNABLE_TO_SET_HOME =
@"You can only set your 'Home Location' on your land or at a mainland Infohub.";
 
public const string HOME_SET = @"Home position set.";
}
 
public struct ASSETS
foreach (Filter filter in vassalConfiguration.InputFilters)
{
public struct NOTECARD
switch (filter)
{
public const string NEWLINE = "\n";
public const uint MAXIMUM_BODY_LENTH = 65536;
case Filter.RFC1738:
o = wasURLUnescapeDataString(o);
break;
case Filter.RFC3986:
o = wasURIUnescapeDataString(o);
break;
case Filter.ENIGMA:
o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
vassalConfiguration.ENIGMA.plugs.ToArray(),
vassalConfiguration.ENIGMA.reflector);
break;
case Filter.VIGENERE:
o = wasDecryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
break;
case Filter.ATBASH:
o = wasATBASH(o);
break;
case Filter.BASE64:
o = Encoding.UTF8.GetString(Convert.FromBase64String(o));
break;
}
}
return o;
};
 
public struct AVATARS
/// <summary>
/// Corrade's output filter function.
/// </summary>
private static readonly Func<string, string> wasOutput = o =>
{
if (string.IsNullOrEmpty(o)) return string.Empty;
 
foreach (Filter filter in vassalConfiguration.OutputFilters)
{
public const uint SET_DISPLAY_NAME_SUCCESS = 200;
public const string LASTNAME_PLACEHOLDER = @"Resident";
public const uint MAXIMUM_DISPLAY_NAME_CHARACTERS = 31;
public const uint MINIMUM_DISPLAY_NAME_CHARACTERS = 1;
public const uint MAXIMUM_NUMBER_OF_ATTACHMENTS = 38;
 
public struct PROFILE
switch (filter)
{
public const uint SECOND_LIFE_TEXT_SIZE = 510;
public const uint FIRST_LIFE_TEXT_SIZE = 253;
case Filter.RFC1738:
o = wasURLEscapeDataString(o);
break;
case Filter.RFC3986:
o = wasURIEscapeDataString(o);
break;
case Filter.ENIGMA:
o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
vassalConfiguration.ENIGMA.plugs.ToArray(),
vassalConfiguration.ENIGMA.reflector);
break;
case Filter.VIGENERE:
o = wasEncryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
break;
case Filter.ATBASH:
o = wasATBASH(o);
break;
case Filter.BASE64:
o = Convert.ToBase64String(Encoding.UTF8.GetBytes(o));
break;
}
 
public struct PICKS
{
public const uint MAXIMUM_PICKS = 10;
public const uint MAXIMUM_PICK_DESCRIPTION_SIZE = 1022;
}
 
public struct CLASSIFIEDS
{
public const uint MAXIMUM_CLASSIFIEDS = 100;
}
}
return o;
};
 
public struct PRIMITIVES
private static readonly Action updateCurrentRegionName = () =>
{
try
{
public const uint MAXIMUM_NAME_SIZE = 63;
public const uint MAXIMUM_DESCRIPTION_SIZE = 127;
public const double MAXIMUM_REZ_HEIGHT = 4096.0;
public const double MINIMUM_SIZE_X = 0.01;
public const double MINIMUM_SIZE_Y = 0.01;
public const double MINIMUM_SIZE_Z = 0.01;
public const double MAXIMUM_SIZE_X = 64.0;
public const double MAXIMUM_SIZE_Y = 64.0;
public const double MAXIMUM_SIZE_Z = 64.0;
}
 
public struct OBJECTS
{
public const uint MAXIMUM_PRIMITIVE_COUNT = 256;
}
 
public struct DIRECTORY
{
public struct EVENT
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getregiondata"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"data", "Name"}
}), 60000);
bool success;
if (string.IsNullOrEmpty(result) ||
!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
{
public const uint SEARCH_RESULTS_COUNT = 200;
vassalForm.BeginInvoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Failed to query Corrade for current region."; }));
return;
}
 
public struct GROUP
switch (success)
{
public const uint SEARCH_RESULTS_COUNT = 100;
case true:
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.CurrentRegionAt.Visible = true;
vassalForm.CurrentRegionName.Visible = true;
vassalForm.CurrentRegionName.Text =
wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).Last();
}));
break;
default:
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.CurrentRegionAt.Visible = false;
vassalForm.CurrentRegionName.Visible = false;
vassalForm.StatusText.Text = @"Error getting current region: " +
wasInput(wasKeyValueGet("error", result));
}));
break;
}
 
public struct LAND
{
public const uint SEARCH_RESULTS_COUNT = 100;
}
 
public struct PEOPLE
{
public const uint SEARCH_RESULTS_COUNT = 100;
}
}
 
public struct ESTATE
catch (Exception ex)
{
public const uint REGION_RESTART_DELAY = 120;
public const uint MAXIMUM_BAN_LIST_LENGTH = 500;
public const uint MAXIMUM_GROUP_LIST_LENGTH = 63;
public const uint MAXIMUM_USER_LIST_LENGTH = 500;
public const uint MAXIMUM_MANAGER_LIST_LENGTH = 10;
 
public struct MESSAGES
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
public const string REGION_RESTART_MESSAGE = @"restart";
}
vassalForm.StatusText.Text =
@"Error getting current region: " +
ex.Message;
}));
}
};
 
public struct PARCELS
{
public const double MAXIMUM_AUTO_RETURN_TIME = 999999;
public const uint MINIMUM_AUTO_RETURN_TIME = 0;
public const uint MAXIMUM_NAME_LENGTH = 63;
public const uint MAXIMUM_DESCRIPTION_LENGTH = 255;
}
 
public struct GRID
{
public const string SECOND_LIFE = @"Second Life";
public const string TIME_ZONE = @"Pacific Standard Time";
}
 
public struct CHAT
{
public const uint MAXIMUM_MESSAGE_LENGTH = 1024;
}
 
public struct GROUPS
{
public const uint MAXIMUM_NUMBER_OF_ROLES = 10;
public const string EVERYONE_ROLE_NAME = @"Everyone";
public const uint MAXIMUM_GROUP_NAME_LENGTH = 35;
public const uint MAXIMUM_GROUP_TITLE_LENGTH = 20;
}
 
public struct NOTICES
{
public const uint MAXIMUM_NOTICE_MESSAGE_LENGTH = 512;
}
 
public struct LSL
{
public const string CSV_DELIMITER = @", ";
public const float SENSOR_RANGE = 96;
public const string DATE_TIME_STAMP = @"yyy-MM-ddTHH:mm:ss.ffffffZ";
}
 
public struct REGION
{
public const float TELEPORT_MINIMUM_DISTANCE = 1;
public const float DEFAULT_AGENT_LIMIT = 40;
public const float DEFAULT_OBJECT_BONUS = 1;
public const bool DEFAULT_FIXED_SUN = false;
public const float DEFAULT_TERRAIN_LOWER_LIMIT = -4;
public const float DEFAULT_TERRAIN_RAISE_LIMIT = 4;
public const bool DEFAULT_USE_ESTATE_SUN = true;
public const float DEFAULT_WATER_HEIGHT = 20;
public const float SUNRISE = 6;
}
 
public struct VIEWER
{
public const float MAXIMUM_DRAW_DISTANCE = 4096;
}
 
public struct TELEPORTS
{
public struct THROTTLE
{
public const uint MAX_TELEPORTS = 10;
public const uint GRACE_SECONDS = 15;
}
}
public Vassal()
{
InitializeComponent();
vassalForm = this;
}
 
///////////////////////////////////////////////////////////////////////////
@@ -333,566 +291,7 @@
 
#endregion
 
#region CRYPTOGRAPHY
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Gets a sub-array from an array.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="data">the array</param>
/// <param name="start">the start index</param>
/// <param name="stop">the stop index (-1 denotes the end)</param>
/// <returns>the array slice between start and stop</returns>
public static T[] wasGetSubArray<T>(T[] data, int start, int stop)
{
if (stop.Equals(-1))
stop = data.Length - 1;
T[] result = new T[stop - start + 1];
Array.Copy(data, start, result, 0, stop - start + 1);
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Delete a sub-array and return the result.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="data">the array</param>
/// <param name="start">the start index</param>
/// <param name="stop">the stop index (-1 denotes the end)</param>
/// <returns>the array without elements between start and stop</returns>
public static T[] wasDeleteSubArray<T>(T[] data, int start, int stop)
{
if (stop.Equals(-1))
stop = data.Length - 1;
T[] result = new T[data.Length - (stop - start) - 1];
Array.Copy(data, 0, result, 0, start);
Array.Copy(data, stop + 1, result, start, data.Length - stop - 1);
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Concatenate multiple arrays.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="arrays">multiple arrays</param>
/// <returns>a flat array with all arrays concatenated</returns>
public static T[] wasConcatenateArrays<T>(params T[][] arrays)
{
int resultLength = 0;
foreach (T[] o in arrays)
{
resultLength += o.Length;
}
T[] result = new T[resultLength];
int offset = 0;
for (int x = 0; x < arrays.Length; x++)
{
arrays[x].CopyTo(result, offset);
offset += arrays[x].Length;
}
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Permutes an array in reverse a given number of times.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="input">the array</param>
/// <param name="times">the number of times to permute</param>
/// <returns>the array with the elements permuted</returns>
private static T[] wasReversePermuteArrayElements<T>(T[] input, int times)
{
if (times.Equals(0)) return input;
T[] slice = new T[input.Length];
Array.Copy(input, 1, slice, 0, input.Length - 1);
Array.Copy(input, 0, slice, input.Length - 1, 1);
return wasReversePermuteArrayElements(slice, --times);
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Permutes an array forward a given number of times.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="input">the array</param>
/// <param name="times">the number of times to permute</param>
/// <returns>the array with the elements permuted</returns>
private static T[] wasForwardPermuteArrayElements<T>(T[] input, int times)
{
if (times.Equals(0)) return input;
T[] slice = new T[input.Length];
Array.Copy(input, input.Length - 1, slice, 0, 1);
Array.Copy(input, 0, slice, 1, input.Length - 1);
return wasForwardPermuteArrayElements(slice, --times);
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Encrypt or decrypt a message given a set of rotors, plugs and a reflector.
/// </summary>
/// <param name="message">the message to encyrpt or decrypt</param>
/// <param name="rotors">any combination of: 1, 2, 3, 4, 5, 6, 7, 8, b, g</param>
/// <param name="plugs">the letter representing the start character for the rotor</param>
/// <param name="reflector">any one of: B, b, C, c</param>
/// <returns>either a decrypted or encrypted string</returns>
private static string wasEnigma(string message, char[] rotors, char[] plugs, char reflector)
{
Dictionary<char, char[]> def_rotors = new Dictionary<char, char[]>
{
{
'1', new[]
{
'e', 'k', 'm', 'f', 'l',
'g', 'd', 'q', 'v', 'z',
'n', 't', 'o', 'w', 'y',
'h', 'x', 'u', 's', 'p',
'a', 'i', 'b', 'r', 'c',
'j'
}
},
{
'2', new[]
{
'a', 'j', 'd', 'k', 's',
'i', 'r', 'u', 'x', 'b',
'l', 'h', 'w', 't', 'm',
'c', 'q', 'g', 'z', 'n',
'p', 'y', 'f', 'v', 'o',
'e'
}
},
{
'3', new[]
{
'b', 'd', 'f', 'h', 'j',
'l', 'c', 'p', 'r', 't',
'x', 'v', 'z', 'n', 'y',
'e', 'i', 'w', 'g', 'a',
'k', 'm', 'u', 's', 'q',
'o'
}
},
{
'4', new[]
{
'e', 's', 'o', 'v', 'p',
'z', 'j', 'a', 'y', 'q',
'u', 'i', 'r', 'h', 'x',
'l', 'n', 'f', 't', 'g',
'k', 'd', 'c', 'm', 'w',
'b'
}
},
{
'5', new[]
{
'v', 'z', 'b', 'r', 'g',
'i', 't', 'y', 'u', 'p',
's', 'd', 'n', 'h', 'l',
'x', 'a', 'w', 'm', 'j',
'q', 'o', 'f', 'e', 'c',
'k'
}
},
{
'6', new[]
{
'j', 'p', 'g', 'v', 'o',
'u', 'm', 'f', 'y', 'q',
'b', 'e', 'n', 'h', 'z',
'r', 'd', 'k', 'a', 's',
'x', 'l', 'i', 'c', 't',
'w'
}
},
{
'7', new[]
{
'n', 'z', 'j', 'h', 'g',
'r', 'c', 'x', 'm', 'y',
's', 'w', 'b', 'o', 'u',
'f', 'a', 'i', 'v', 'l',
'p', 'e', 'k', 'q', 'd',
't'
}
},
{
'8', new[]
{
'f', 'k', 'q', 'h', 't',
'l', 'x', 'o', 'c', 'b',
'j', 's', 'p', 'd', 'z',
'r', 'a', 'm', 'e', 'w',
'n', 'i', 'u', 'y', 'g',
'v'
}
},
{
'b', new[]
{
'l', 'e', 'y', 'j', 'v',
'c', 'n', 'i', 'x', 'w',
'p', 'b', 'q', 'm', 'd',
'r', 't', 'a', 'k', 'z',
'g', 'f', 'u', 'h', 'o',
's'
}
},
{
'g', new[]
{
'f', 's', 'o', 'k', 'a',
'n', 'u', 'e', 'r', 'h',
'm', 'b', 't', 'i', 'y',
'c', 'w', 'l', 'q', 'p',
'z', 'x', 'v', 'g', 'j',
'd'
}
}
};
 
Dictionary<char, char[]> def_reflectors = new Dictionary<char, char[]>
{
{
'B', new[]
{
'a', 'y', 'b', 'r', 'c', 'u', 'd', 'h',
'e', 'q', 'f', 's', 'g', 'l', 'i', 'p',
'j', 'x', 'k', 'n', 'm', 'o', 't', 'z',
'v', 'w'
}
},
{
'b', new[]
{
'a', 'e', 'b', 'n', 'c', 'k', 'd', 'q',
'f', 'u', 'g', 'y', 'h', 'w', 'i', 'j',
'l', 'o', 'm', 'p', 'r', 'x', 's', 'z',
't', 'v'
}
},
{
'C', new[]
{
'a', 'f', 'b', 'v', 'c', 'p', 'd', 'j',
'e', 'i', 'g', 'o', 'h', 'y', 'k', 'r',
'l', 'z', 'm', 'x', 'n', 'w', 't', 'q',
's', 'u'
}
},
{
'c', new[]
{
'a', 'r', 'b', 'd', 'c', 'o', 'e', 'j',
'f', 'n', 'g', 't', 'h', 'k', 'i', 'v',
'l', 'm', 'p', 'w', 'q', 'z', 's', 'x',
'u', 'y'
}
}
};
 
// Setup rotors from plugs.
foreach (char rotor in rotors)
{
char plug = plugs[Array.IndexOf(rotors, rotor)];
int i = Array.IndexOf(def_rotors[rotor], plug);
if (i.Equals(0)) continue;
def_rotors[rotor] = wasConcatenateArrays(new[] {plug},
wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i, i), i, -1),
wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i + 1, -1), 0, i - 1));
}
 
StringBuilder result = new StringBuilder();
foreach (char c in message)
{
if (!char.IsLetter(c))
{
result.Append(c);
continue;
}
 
// Normalize to lower.
char l = char.ToLower(c);
 
Action<char[]> rotate = o =>
{
int i = o.Length - 1;
do
{
def_rotors[o[0]] = wasForwardPermuteArrayElements(def_rotors[o[0]], 1);
if (i.Equals(0))
{
rotors = wasReversePermuteArrayElements(o, 1);
continue;
}
l = wasGetElementAt(def_rotors[o[1]], Array.IndexOf(def_rotors[o[0]], l) - 1);
o = wasReversePermuteArrayElements(o, 1);
} while (--i > -1);
};
 
// Forward pass through the Enigma's rotors.
rotate.Invoke(rotors);
 
// Reflect
int x = Array.IndexOf(def_reflectors[reflector], l);
l = (x + 1)%2 == 0 ? def_reflectors[reflector][x - 1] : def_reflectors[reflector][x + 1];
 
// Reverse the order of the rotors.
Array.Reverse(rotors);
 
// Reverse pass through the Enigma's rotors.
rotate.Invoke(rotors);
 
if (char.IsUpper(c))
{
l = char.ToUpper(l);
}
result.Append(l);
}
 
return result.ToString();
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Expand the VIGENRE key to the length of the input.
/// </summary>
/// <param name="input">the input to expand to</param>
/// <param name="enc_key">the key to expand</param>
/// <returns>the expanded key</returns>
private static string wasVigenereExpandKey(string input, string enc_key)
{
string exp_key = string.Empty;
int i = 0, j = 0;
do
{
char p = input[i];
if (!char.IsLetter(p))
{
exp_key += p;
++i;
continue;
}
int m = j%enc_key.Length;
exp_key += enc_key[m];
++j;
++i;
} while (i < input.Length);
return exp_key;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Encrypt using VIGENERE.
/// </summary>
/// <param name="input">the input to encrypt</param>
/// <param name="enc_key">the key to encrypt with</param>
/// <returns>the encrypted input</returns>
private static string wasEncryptVIGENERE(string input, string enc_key)
{
char[] a =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
 
enc_key = wasVigenereExpandKey(input, enc_key);
string result = string.Empty;
int i = 0;
do
{
char p = input[i];
if (!char.IsLetter(p))
{
result += p;
++i;
continue;
}
char q =
wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i]))[
Array.IndexOf(a, char.ToLowerInvariant(p))];
if (char.IsUpper(p))
{
q = char.ToUpperInvariant(q);
}
result += q;
++i;
} while (i < input.Length);
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Decrypt using VIGENERE.
/// </summary>
/// <param name="input">the input to decrypt</param>
/// <param name="enc_key">the key to decrypt with</param>
/// <returns>the decrypted input</returns>
private static string wasDecryptVIGENERE(string input, string enc_key)
{
char[] a =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
 
enc_key = wasVigenereExpandKey(input, enc_key);
string result = string.Empty;
int i = 0;
do
{
char p = input[i];
if (!char.IsLetter(p))
{
result += p;
++i;
continue;
}
char q =
a[
Array.IndexOf(wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i])),
char.ToLowerInvariant(p))];
if (char.IsUpper(p))
{
q = char.ToUpperInvariant(q);
}
result += q;
++i;
} while (i < input.Length);
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// An implementation of the ATBASH cypher for latin alphabets.
/// </summary>
/// <param name="data">the data to encrypt or decrypt</param>
/// <returns>the encrypted or decrypted data</returns>
private static string wasATBASH(string data)
{
char[] a =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
 
char[] input = data.ToArray();
 
Parallel.ForEach(Enumerable.Range(0, data.Length), i =>
{
char e = input[i];
if (!char.IsLetter(e)) return;
int x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e));
if (!char.IsUpper(e))
{
input[i] = a[x];
return;
}
input[i] = char.ToUpperInvariant(a[x]);
});
 
return new string(input);
}
 
#endregion
 
/// <summary>
/// Corrade's input filter function.
/// </summary>
private static readonly Func<string, string> wasInput = o =>
{
if (string.IsNullOrEmpty(o)) return string.Empty;
 
foreach (Filter filter in vassalConfiguration.InputFilters)
{
switch (filter)
{
case Filter.RFC1738:
o = wasURLUnescapeDataString(o);
break;
case Filter.RFC3986:
o = wasURIUnescapeDataString(o);
break;
case Filter.ENIGMA:
o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
vassalConfiguration.ENIGMA.plugs.ToArray(),
vassalConfiguration.ENIGMA.reflector);
break;
case Filter.VIGENERE:
o = wasDecryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
break;
case Filter.ATBASH:
o = wasATBASH(o);
break;
case Filter.BASE64:
o = Encoding.UTF8.GetString(Convert.FromBase64String(o));
break;
}
}
return o;
};
 
/// <summary>
/// Corrade's output filter function.
/// </summary>
private static readonly Func<string, string> wasOutput = o =>
{
if (string.IsNullOrEmpty(o)) return string.Empty;
 
foreach (Filter filter in vassalConfiguration.OutputFilters)
{
switch (filter)
{
case Filter.RFC1738:
o = wasURLEscapeDataString(o);
break;
case Filter.RFC3986:
o = wasURIEscapeDataString(o);
break;
case Filter.ENIGMA:
o = wasEnigma(o, vassalConfiguration.ENIGMA.rotors.ToArray(),
vassalConfiguration.ENIGMA.plugs.ToArray(),
vassalConfiguration.ENIGMA.reflector);
break;
case Filter.VIGENERE:
o = wasEncryptVIGENERE(o, vassalConfiguration.VIGENERESecret);
break;
case Filter.ATBASH:
o = wasATBASH(o);
break;
case Filter.BASE64:
o = Convert.ToBase64String(Encoding.UTF8.GetBytes(o));
break;
}
}
return o;
};
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>Escapes a dictionary's keys and values for sending as POST data.</summary>
@@ -927,7 +326,7 @@
break;
}
});
return String.Join(",", csv);
return string.Join(",", csv);
}
 
///////////////////////////////////////////////////////////////////////////
@@ -987,7 +386,7 @@
/// <returns>a key-value data encoded string</returns>
private static string wasKeyValueEncode(Dictionary<string, string> data)
{
return String.Join("&", data.AsParallel().Select(o => String.Join("=", o.Key, o.Value)));
return string.Join("&", data.AsParallel().Select(o => string.Join("=", o.Key, o.Value)));
}
 
///////////////////////////////////////////////////////////////////////////
@@ -1006,7 +405,10 @@
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL);
request.UserAgent = VASSAL_CONSTANTS.USER_AGENT;
request.Proxy = WebRequest.DefaultWebProxy;
request.Pipelined = true;
request.KeepAlive = true;
request.Timeout = (int) millisecondsTimeout;
request.ReadWriteTimeout = (int) millisecondsTimeout;
request.AllowAutoRedirect = true;
request.AllowWriteStreamBuffering = true;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
@@ -1047,164 +449,58 @@
}
catch (Exception)
{
 
}
 
return null;
}
 
/// <summary>
/// Constants used by Corrade.
/// </summary>
public struct VASSAL_CONSTANTS
private void RegionSelected(object sender, EventArgs e)
{
/// <summary>
/// Copyright.
/// </summary>
public const string COPYRIGHT = @"(c) Copyright 2013 Wizardry and Steamworks";
new Thread(() =>
{
try
{
// Stop timers.
vassalTimer.Stop();
overviewTabTimer.Stop();
regionsStateTabTimer.Stop();
residentListTabTimer.Stop();
estateTopTabTimer.Stop();
estateTexturesTabTimer.Stop();
 
public const string WIZARDRY_AND_STEAMWORKS = @"Wizardry and Steamworks";
public const string VASSAL = @"Vassal";
public const string WIZARDRY_AND_STEAMWORKS_WEBSITE = @"http://grimore.org";
Monitor.Enter(ClientInstanceTeleportLock);
 
/// <summary>
/// Vassal version.
/// </summary>
public static readonly string VASSAL_VERSION = Assembly.GetEntryAssembly().GetName().Version.ToString();
string selectedRegionName = string.Empty;
Vector3 selectedRegionPosition = Vector3.Zero;
bool startTeleport = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
ListViewItem listViewItem = LoadedRegionsBox.SelectedItem as ListViewItem;
switch (listViewItem != null && LoadedRegionsBox.SelectedIndex != -1)
{
case true:
selectedRegionName = listViewItem.Text;
selectedRegionPosition = (Vector3) listViewItem.Tag;
startTeleport = true;
break;
default:
startTeleport = false;
break;
}
}));
 
/// <summary>
/// Corrade user agent.
/// </summary>
public static readonly string USER_AGENT =
$"{VASSAL}/{VASSAL_VERSION} ({WIZARDRY_AND_STEAMWORKS_WEBSITE})";
if (!startTeleport) throw new Exception();
 
/// <summary>
/// Vassal compile date.
/// </summary>
public static readonly string VASSAL_COMPILE_DATE = new DateTime(2000, 1, 1).Add(new TimeSpan(
TimeSpan.TicksPerDay*Assembly.GetEntryAssembly().GetName().Version.Build + // days since 1 January 2000
TimeSpan.TicksPerSecond*2*Assembly.GetEntryAssembly().GetName().Version.Revision)).ToLongDateString();
 
/// <summary>
/// Vassal configuration file.
/// </summary>
public static readonly string VASSAL_CONFIGURATION_FILE = @"Vassal.ini";
 
/// <summary>
/// Vassal regions file.
/// </summary>
public static readonly string VASSAL_REGIONS = @"Regions.csv";
 
/// <summary>
/// Conten-types that Corrade can send and receive.
/// </summary>
public struct CONTENT_TYPE
{
public const string TEXT_PLAIN = @"text/plain";
public const string WWW_FORM_URLENCODED = @"application/x-www-form-urlencoded";
}
}
 
private static readonly System.Action updateCurrentRegionName = () =>
{
try
{
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
// Announce teleport.
vassalForm.Invoke((MethodInvoker) (() =>
{
{"command", "getregiondata"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"data", "Name"}
}), 60000);
bool success;
if (string.IsNullOrEmpty(result) ||
!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Failed to query Corrade for current region.";
vassalForm.RegionTeleportGroup.Enabled = false;
vassalForm.StatusProgress.Value = 0;
vassalForm.StatusText.Text = @"Teleporting to " + selectedRegionName;
}));
return;
}
switch (success)
{
case true:
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.CurrentRegionAt.Visible = true;
vassalForm.CurrentRegionName.Visible = true;
vassalForm.CurrentRegionName.Text =
wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).Last();
}));
break;
default:
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.CurrentRegionAt.Visible = false;
vassalForm.CurrentRegionName.Visible = false;
vassalForm.StatusText.Text = @"Error getting current region: " +
wasInput(wasKeyValueGet("error", result));
}));
break;
}
}
catch (Exception ex)
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text =
@"Error getting current region: " +
ex.Message;
}));
}
};
 
public Vassal()
{
InitializeComponent();
vassalForm = this;
}
 
private void RegionSelected(object sender, EventArgs e)
{
string selectedRegionName = string.Empty;
Vector3 selectedRegionPosition = Vector3.Zero;
bool startTeleport = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
ListViewItem listViewItem = LoadedRegions.SelectedItem as ListViewItem;
switch (listViewItem != null && LoadedRegions.SelectedIndex != -1)
{
case true:
selectedRegionName = listViewItem.Text;
selectedRegionPosition = (Vector3) listViewItem.Tag;
startTeleport = true;
break;
default:
startTeleport = false;
break;
}
}));
 
if (!startTeleport) return;
 
 
// Announce teleport.
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.RegionTeleportGroup.Enabled = false;
vassalForm.StatusProgress.Value = 0;
vassalForm.StatusText.Text = @"Teleporting to " + selectedRegionName;
}));
 
new Thread(() =>
{
Monitor.Enter(ClientInstanceTeleportLock);
try
{
int elapsedSeconds = 0;
System.Timers.Timer teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
Timer teleportTimer = new Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
teleportTimer.Elapsed += (o, p) =>
{
vassalForm.Invoke((MethodInvoker) (() =>
@@ -1257,10 +553,13 @@
}));
break;
default:
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Failed teleporting to " + selectedRegionName;
}));
vassalForm.Invoke(
(MethodInvoker)
(() =>
{
vassalForm.StatusText.Text = @"Failed teleporting to " +
selectedRegionName;
}));
break;
}
break;
@@ -1268,21 +567,19 @@
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message;
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Error communicating with Corrade: " + ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.StatusProgress.Value = 100;
vassalForm.RegionTeleportGroup.Enabled = true;
// Set the map image to the loading spinner.
Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
System.IO.Stream file =
Assembly thisAssembly = Assembly.GetExecutingAssembly();
Stream file =
thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
switch (file != null)
{
@@ -1301,6 +598,10 @@
TopScriptsGridView.Rows.Clear();
// Clear the top colliders table.
TopCollidersGridView.Rows.Clear();
// Clear the estate list table.
EstateListGridView.Rows.Clear();
// Clear the estate list selection box.
EstateListSelectBox.SelectedIndex = -1;
// Invalidate data for overview tab.
vassalForm.CurrentRegionAt.Visible = false;
vassalForm.CurrentRegionName.Visible = false;
@@ -1321,6 +622,16 @@
Objects.Text = string.Empty;
Objects.Enabled = false;
}));
 
Monitor.Exit(ClientInstanceTeleportLock);
 
// start timers
vassalTimer.Start();
overviewTabTimer.Start();
regionsStateTabTimer.Start();
residentListTabTimer.Start();
estateTopTabTimer.Start();
estateTexturesTabTimer.Start();
}
})
{IsBackground = true}.Start();
@@ -1328,6 +639,7 @@
 
private void SettingsRequested(object sender, EventArgs e)
{
vassalForm.BeginInvoke((MethodInvoker) (() => { VassalStatusGroup.Enabled = false; }));
SettingsForm settingsForm = new SettingsForm {TopMost = true};
settingsForm.Show();
}
@@ -1338,9 +650,19 @@
vassalForm.Version.Text = @"v" + VASSAL_CONSTANTS.VASSAL_VERSION;
 
// Disable estate manager tabs since we will enable these dynamically.
TopScriptsTab.Enabled = false;
TopCollidersTab.Enabled = false;
EstateTopTab.Enabled = false;
EstateListsTab.Enabled = false;
ResidentListBanGroup.Enabled = false;
EstateTerrainDownloadUploadGroup.Enabled = false;
// Estate textures
RegionTexturesLowUUIDApplyBox.Enabled = false;
RegionTexturesLowUUIDApplyButton.Enabled = false;
RegionTexturesMiddleLowUUIDApplyBox.Enabled = false;
RegionTexturesMiddleLowUUIDApplyButton.Enabled = false;
RegionTexturesMiddleHighUUIDApplyBox.Enabled = false;
RegionTexturesMiddleHighUUIDApplyButton.Enabled = false;
RegionTexturesHighUUIDApplyBox.Enabled = false;
RegionTexturesHighUUIDApplyButton.Enabled = false;
 
// Get the configuration file settings if it exists.
if (File.Exists(VASSAL_CONSTANTS.VASSAL_CONFIGURATION_FILE))
@@ -1351,40 +673,6 @@
RegionRestartDelayBox.Text = vassalConfiguration.RegionRestartDelay.ToString(Utils.EnUsCulture);
}
 
// Spawn a thread to check Corrade's connection status.
new Thread(() =>
{
TcpClient tcpClient = new TcpClient();
try
{
System.Uri uri = new System.Uri(vassalConfiguration.HTTPServerURL);
tcpClient.Connect(uri.Host, uri.Port);
// port open
vassalForm.BeginInvoke((MethodInvoker) (() => { Tabs.Enabled = true; }));
// set the loading spinner
Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
System.IO.Stream file =
thisAssembly.GetManifestResourceStream("Vassal.img.loading.gif");
switch (file != null)
{
case true:
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
RegionAvatarsMap.SizeMode = PictureBoxSizeMode.CenterImage;
RegionAvatarsMap.Image = Image.FromStream(file);
RegionAvatarsMap.Refresh();
}));
break;
}
}
catch (Exception)
{
// port closed
vassalForm.BeginInvoke((MethodInvoker) (() => { Tabs.Enabled = false; }));
}
})
{IsBackground = true}.Start();
 
// Get all the regions if they exist.
if (File.Exists(VASSAL_CONSTANTS.VASSAL_REGIONS))
{
@@ -1399,8 +687,8 @@
? localPosition
: Vector3.Zero).OrderBy(o => o.Key).ToDictionary(o => o.Key, o => o.Value));
// Populate the loaded regions.
LoadedRegions.Items.Clear();
LoadedRegions.Items.AddRange(
LoadedRegionsBox.Items.Clear();
LoadedRegionsBox.Items.AddRange(
ConfiguredRegions.Select(o => (object) new ListViewItem {Text = o.Key, Tag = o.Value})
.ToArray());
// Populate the batch restart grid view.
@@ -1416,17 +704,65 @@
}
}
 
// Start the overview timer.
overviewTabTimer.Elapsed += (o, p) =>
// Start the vassal timer.
vassalTimer.Elapsed += (o, p) =>
{
if (!Monitor.TryEnter(ClientInstanceTeleportLock))
return;
try
{
// Check Corrade connection status.
TcpClient tcpClient = new TcpClient();
Uri uri = new Uri(vassalConfiguration.HTTPServerURL);
tcpClient.Connect(uri.Host, uri.Port);
// port open
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.CurrentRegionAt.Visible = true;
vassalForm.CurrentRegionName.Visible = true;
Assembly thisAssembly = Assembly.GetExecutingAssembly();
Stream file =
thisAssembly.GetManifestResourceStream("Vassal.img.online.png");
switch (file != null)
{
case true:
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
ConnectionStatusPictureBox.Image = Image.FromStream(file);
ConnectionStatusPictureBox.Refresh();
}));
break;
}
Tabs.Enabled = true;
}));
}
catch (Exception)
{
// port closed
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
vassalForm.CurrentRegionAt.Visible = false;
vassalForm.CurrentRegionName.Visible = false;
Assembly thisAssembly = Assembly.GetExecutingAssembly();
Stream file =
thisAssembly.GetManifestResourceStream("Vassal.img.offline.png");
switch (file != null)
{
case true:
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
ConnectionStatusPictureBox.Image = Image.FromStream(file);
ConnectionStatusPictureBox.Refresh();
}));
break;
}
Tabs.Enabled = false;
}));
}
 
try
{
// Always run the overview regardless which tab is active.
 
// Get the statistics.
// Get the simulator name and if we are an estate manager.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
@@ -1436,14 +772,6 @@
{
"data", wasEnumerableToCSV(new[]
{
"Agents",
"LastLag",
"Dilation",
"FPS",
"PhysicsFPS",
"ActiveScripts",
"ScriptTime",
"Objects",
"Name",
"IsEstateManager"
})
@@ -1468,14 +796,38 @@
isEstateManager)
{
case true: // we are an estate manager
TopScriptsTab.Enabled = true;
TopCollidersTab.Enabled = true;
EstateTopTab.Enabled = true;
EstateListsTab.Enabled = true;
ResidentListBanGroup.Enabled = true;
EstateTerrainDownloadUploadGroup.Enabled = true;
RegionToolsRegionDebugGroup.Enabled = true;
RegionToolsRegionInfoGroup.Enabled = true;
// Estate textures
RegionTexturesLowUUIDApplyBox.Enabled = true;
RegionTexturesLowUUIDApplyButton.Enabled = true;
RegionTexturesMiddleLowUUIDApplyBox.Enabled = true;
RegionTexturesMiddleLowUUIDApplyButton.Enabled = true;
RegionTexturesMiddleHighUUIDApplyBox.Enabled = true;
RegionTexturesMiddleHighUUIDApplyButton.Enabled = true;
RegionTexturesHighUUIDApplyBox.Enabled = true;
RegionTexturesHighUUIDApplyButton.Enabled = true;
break;
default:
TopScriptsTab.Enabled = false;
TopCollidersTab.Enabled = false;
EstateTopTab.Enabled = false;
EstateListsTab.Enabled = false;
ResidentListBanGroup.Enabled = false;
EstateTerrainDownloadUploadGroup.Enabled = false;
RegionToolsRegionDebugGroup.Enabled = false;
RegionToolsRegionInfoGroup.Enabled = false;
// Estate textures
RegionTexturesLowUUIDApplyBox.Enabled = false;
RegionTexturesLowUUIDApplyButton.Enabled = false;
RegionTexturesMiddleLowUUIDApplyBox.Enabled = false;
RegionTexturesMiddleLowUUIDApplyButton.Enabled = false;
RegionTexturesMiddleHighUUIDApplyBox.Enabled = false;
RegionTexturesMiddleHighUUIDApplyButton.Enabled = false;
RegionTexturesHighUUIDApplyBox.Enabled = false;
RegionTexturesHighUUIDApplyButton.Enabled = false;
break;
}
 
@@ -1483,7 +835,67 @@
vassalForm.CurrentRegionName.Text = data[data.IndexOf("Name") + 1];
vassalForm.CurrentRegionAt.Visible = true;
vassalForm.CurrentRegionName.Visible = true;
}));
}
catch (Exception)
{
}
 
Monitor.Exit(ClientInstanceTeleportLock);
};
vassalTimer.Start();
 
// Start the overview timer.
overviewTabTimer.Elapsed += (o, p) =>
{
// Do not do anything in case the tab is not selected.
bool run = false;
vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(OverviewTab); }));
 
if (!run)
{
overviewTabTimer.Stop();
return;
}
 
overviewTabTimer.Stop();
 
try
{
// Get the statistics.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getregiondata"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{
"data", wasEnumerableToCSV(new[]
{
"Agents",
"LastLag",
"Dilation",
"FPS",
"PhysicsFPS",
"ActiveScripts",
"ScriptTime",
"Objects",
"AvatarPositions"
})
}
}), vassalConfiguration.DataTimeout);
 
bool success;
if (string.IsNullOrEmpty(result) ||
!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception();
 
List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
if (data.Count.Equals(0))
throw new Exception();
 
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
// Populate the overview tab.
Agents.Text = data[data.IndexOf("Agents") + 1];
Agents.Enabled = true;
@@ -1503,6 +915,21 @@
Objects.Enabled = true;
}));
 
// Get avatar positions.
// Pattern: [...], X, 10, Y, 63, Z, 200, [...], X, 52, Y, 73, Z, 55, [...[...]]
float X = 0, Y = 0, Z = 0;
List<Vector3> positions = data.Select((x, i) => new {Item = x, Index = i})
.Where(x => x.Item.Equals("X") || x.Item.Equals("Y") || x.Item.Equals("Z"))
.Select(z => data[z.Index + 1]).Select((x, i) => new {Value = x, Index = i})
.GroupBy(x => x.Index/3)
.Select(x => x.Select(v => v.Value).ToList())
.Where(
x =>
float.TryParse(x[0], out X) && float.TryParse(x[1], out Y) &&
float.TryParse(x[2], out Z))
.Select(x => new Vector3(X, Y, Z))
.ToList();
 
// Get the map image.
result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
@@ -1528,7 +955,7 @@
{"password", vassalConfiguration.Password},
{"item", data.Last()},
{"type", "Texture"},
{"format", "Jpeg"},
{"format", "Jpeg"}
}), vassalConfiguration.DataTimeout);
if (string.IsNullOrEmpty(result) ||
!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
@@ -1540,39 +967,12 @@
mapImage = Image.FromStream(memoryStream);
}
 
// Get the avatar positions.
result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getavatarpositions"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"entity", "region"}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result) ||
!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception();
 
// Every thrid element represents a Vecto3 of the avatar position.
data =
wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
.Skip(2)
.Where((x, i) => i%3 == 0)
.ToList();
 
// Draw the avatars onto the map.
Graphics mapGraphics = Graphics.FromImage(mapImage);
Vector3 position;
foreach (string vector in data)
foreach (Vector3 position in positions)
{
switch (Vector3.TryParse(vector, out position))
{
case true:
mapGraphics.FillEllipse(Brushes.Chartreuse,
new Rectangle((int) position.X, (int) position.Y, 4, 4));
break;
}
mapGraphics.FillEllipse(Brushes.Chartreuse,
new Rectangle((int) position.X, (int) position.Y, 4, 4));
}
mapGraphics.DrawImage(mapImage, new Point(0, 0));
 
@@ -1585,13 +985,9 @@
}
catch (Exception)
{
 
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
}
 
overviewTabTimer.Start();
};
overviewTabTimer.Start();
 
@@ -1599,15 +995,16 @@
{
// Do not do anything in case the tab is not selected.
bool run = false;
vassalForm.Invoke((MethodInvoker) (() =>
vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(RegionsStateTab); }));
 
if (!run)
{
run = Tabs.SelectedTab.Equals(RegionsStateTab);
}));
if (!run) return;
 
if (!Monitor.TryEnter(RegionsStateCheckLock))
regionsStateTabTimer.Stop();
return;
}
 
regionsStateTabTimer.Stop();
 
try
{
string regionName = string.Empty;
@@ -1616,6 +1013,8 @@
regionName =
RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateRegionName"].Value
.ToString();
RegionsStateGridView.Rows[regionsStateCheckIndex].DefaultCellStyle.BackColor =
Color.Gold;
}));
 
if (string.IsNullOrEmpty(regionName))
@@ -1663,17 +1062,14 @@
}
RegionsStateGridView.Rows[regionsStateCheckIndex].Cells["RegionsStateLastCheck"].Value = DateTime
.Now.ToUniversalTime()
.ToString(Vassal.LINDEN_CONSTANTS.LSL.DATE_TIME_STAMP);
 
.ToString(LINDEN_CONSTANTS.LSL.DATE_TIME_STAMP);
}));
}
catch (Exception)
{
 
}
finally
{
Monitor.Exit(RegionsStateCheckLock);
++regionsStateCheckIndex;
vassalForm.Invoke((MethodInvoker) (() =>
{
@@ -1683,26 +1079,29 @@
}
}));
}
 
regionsStateTabTimer.Start();
};
regionsStateTabTimer.Start();
 
// Start the top scores timer.
topScriptsTabTimer.Elapsed += (o, p) =>
estateTopTabTimer.Elapsed += (o, p) =>
{
// Do not do anything in case the tab is not selected.
bool run = false;
vassalForm.Invoke((MethodInvoker) (() =>
vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(EstateTopTab); }));
 
if (!run)
{
run = Tabs.SelectedTab.Equals(TopScriptsTab);
}));
if (!run) return;
 
if (!Monitor.TryEnter(ClientInstanceTeleportLock))
estateTopTabTimer.Stop();
return;
}
 
estateTopTabTimer.Stop();
 
try
{
// Get the statistics.
// Get the top scripts.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
@@ -1761,36 +1160,9 @@
}
}
}));
}
catch (Exception)
{
 
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
}
};
topScriptsTabTimer.Start();
 
// Start the top colliders timer.
topCollidersTabTimer.Elapsed += (o, p) =>
{
// Do not do anything in case the tab is not selected.
bool run = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
run = Tabs.SelectedTab.Equals(TopCollidersTab);
}));
if (!run) return;
 
if (!Monitor.TryEnter(ClientInstanceTeleportLock))
return;
 
try
{
// Get the statistics.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
// Get the top colliders.
result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getregiontop"},
@@ -1799,16 +1171,14 @@
{"type", "colliders"}
}), vassalConfiguration.DataTimeout);
 
bool success;
if (string.IsNullOrEmpty(result) ||
!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception();
 
HashSet<List<string>> data =
new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
.Select((x, i) => new {Index = i, Value = x})
.GroupBy(x => x.Index/5)
.Select(x => x.Select(v => v.Value).ToList()));
data = new HashSet<List<string>>(wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
.Select((x, i) => new {Index = i, Value = x})
.GroupBy(x => x.Index/5)
.Select(x => x.Select(v => v.Value).ToList()));
if (data.Count.Equals(0))
throw new Exception();
 
@@ -1848,34 +1218,31 @@
break;
}
}
 
}));
}
catch (Exception)
{
}
 
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
}
estateTopTabTimer.Start();
};
topCollidersTabTimer.Start();
estateTopTabTimer.Start();
 
// Start the resident list timer.
residentListTimer.Elapsed += (o, p) =>
residentListTabTimer.Elapsed += (o, p) =>
{
// Do not do anything in case the tab is not selected.
bool run = false;
vassalForm.Invoke((MethodInvoker) (() =>
vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(ResidentListTab); }));
 
if (!run)
{
run = Tabs.SelectedTab.Equals(ResidentListTab);
}));
if (!run) return;
 
if (!Monitor.TryEnter(ClientInstanceTeleportLock))
residentListTabTimer.Stop();
return;
}
 
residentListTabTimer.Stop();
 
try
{
// Get the avatar positions.
@@ -1934,25 +1301,137 @@
break;
}
}
 
}));
}
catch (Exception)
{
}
 
residentListTabTimer.Start();
};
residentListTabTimer.Start();
 
estateTexturesTabTimer.Elapsed += (o, p) =>
{
// Do not do anything in case the tab is not selected.
bool run = false;
vassalForm.Invoke((MethodInvoker) (() => { run = Tabs.SelectedTab.Equals(EstateTexturesTab); }));
 
if (!run)
{
estateTexturesTabTimer.Stop();
return;
}
finally
 
estateTexturesTabTimer.Stop();
 
try
{
Monitor.Exit(ClientInstanceTeleportLock);
// Get the region terrain texture UUIDs.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getregionterraintextures"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password}
}), vassalConfiguration.DataTimeout);
 
bool success;
if (string.IsNullOrEmpty(result) ||
!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception();
 
List<string> data = wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result))).ToList();
if (!data.Count.Equals(4))
throw new Exception();
 
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTexturesLowUUIDBox.Text = data[0];
if (string.IsNullOrEmpty(RegionTexturesLowUUIDApplyBox.Text))
{
RegionTexturesLowUUIDApplyBox.Text = data[0];
}
RegionTexturesMiddleLowUUIDBox.Text = data[1];
if (string.IsNullOrEmpty(RegionTexturesMiddleLowUUIDApplyBox.Text))
{
RegionTexturesMiddleLowUUIDApplyBox.Text = data[1];
}
RegionTexturesMiddleHighUUIDBox.Text = data[2];
if (string.IsNullOrEmpty(RegionTexturesMiddleHighUUIDApplyBox.Text))
{
RegionTexturesMiddleHighUUIDApplyBox.Text = data[2];
}
RegionTexturesHighUUIDBox.Text = data[3];
if (string.IsNullOrEmpty(RegionTexturesHighUUIDApplyBox.Text))
{
RegionTexturesHighUUIDApplyBox.Text = data[1];
}
}));
 
Parallel.ForEach(Enumerable.Range(0, 4), i =>
{
result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "download"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"item", data[i]},
{"type", "Texture"},
{"format", "Jpeg"}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result) ||
!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
return;
 
byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
{
groundTextureImages[i] = Image.FromStream(memoryStream);
}
 
switch (i)
{
case 0:
vassalForm.BeginInvoke(
(MethodInvoker)
(() => { RegionTexturesLowPictureBox.Image = groundTextureImages[0]; }));
 
break;
case 1:
vassalForm.BeginInvoke(
(MethodInvoker)
(() => { RegionTexturesMiddleLowPictureBox.Image = groundTextureImages[1]; }));
 
break;
case 2:
vassalForm.BeginInvoke(
(MethodInvoker)
(() => { RegionTexturesMiddleHighPictureBox.Image = groundTextureImages[2]; }));
break;
case 3:
vassalForm.BeginInvoke(
(MethodInvoker)
(() => { RegionTexturesHighPictureBox.Image = groundTextureImages[3]; }));
break;
}
});
}
catch (Exception)
{
}
 
estateTexturesTabTimer.Start();
};
residentListTimer.Start();
estateTexturesTabTimer.Start();
}
 
private void RequestedEditRegions(object sender, EventArgs e)
{
// Clear any selection.
LoadedRegions.SelectedIndex = -1;
LoadedRegionsBox.SelectedIndex = -1;
RegionEditForm regionEditForm = new RegionEditForm {TopMost = true};
regionEditForm.Show();
}
@@ -2158,10 +1637,7 @@
 
try
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusProgress.Value = 0;
}));
vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 0; }));
int totalObjects = returnUUIDs.Count;
do
{
@@ -2168,16 +1644,12 @@
// Dequeue the first object.
KeyValuePair<UUID, Vector3> objectData = returnUUIDs.Dequeue();
 
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Returning object UUID: " + objectData.Key.ToString();
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Returning object UUID: " + objectData.Key; }));
 
string currentRegionName = string.Empty;
vassalForm.Invoke((MethodInvoker) (() =>
{
currentRegionName = CurrentRegionName.Text;
}));
vassalForm.Invoke((MethodInvoker) (() => { currentRegionName = CurrentRegionName.Text; }));
 
// Teleport to the object.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
@@ -2193,10 +1665,9 @@
 
if (string.IsNullOrEmpty(result))
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Error communicating with Corrade.";
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
continue;
}
 
@@ -2214,10 +1685,9 @@
 
if (string.IsNullOrEmpty(result))
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Error communicating with Corrade.";
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
continue;
}
 
@@ -2224,10 +1694,9 @@
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"No success status could be retrieved. ";
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"No success status could be retrieved. "; }));
continue;
}
 
@@ -2236,7 +1705,7 @@
case true:
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString();
vassalForm.StatusText.Text = @"Returned object: " + objectData.Key;
// Remove the row from the grid view.
DataGridViewRow row =
TopScriptsGridView.Rows.AsParallel()
@@ -2251,31 +1720,24 @@
case false:
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() +
vassalForm.StatusText.Text = @"Could not return object " + objectData.Key +
@": " +
wasInput(wasKeyValueGet("error", result));
}));
break;
}
 
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusProgress.Value =
Math.Min((int) (Math.Abs(returnUUIDs.Count - totalObjects)/
(double) totalObjects), 100);
Math.Min((int) (100d*Math.Abs(returnUUIDs.Count - totalObjects)/totalObjects), 100);
}));
} while (!returnUUIDs.Count.Equals(0));
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusProgress.Value = 100;
}));
vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 100; }));
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message;
}));
vassalForm.Invoke(
(MethodInvoker) (() => { vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message; }));
}
finally
{
@@ -2337,10 +1799,7 @@
 
try
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusProgress.Value = 0;
}));
vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 0; }));
int totalObjects = returnObjectUUIDQueue.Count;
do
{
@@ -2347,16 +1806,12 @@
// Dequeue the first object.
KeyValuePair<UUID, Vector3> objectData = returnObjectUUIDQueue.Dequeue();
 
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Returning UUID: " + objectData.Key.ToString();
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Returning UUID: " + objectData.Key; }));
 
string currentRegionName = string.Empty;
vassalForm.Invoke((MethodInvoker) (() =>
{
currentRegionName = CurrentRegionName.Text;
}));
vassalForm.Invoke((MethodInvoker) (() => { currentRegionName = CurrentRegionName.Text; }));
 
// Teleport to the object.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
@@ -2372,10 +1827,9 @@
 
if (string.IsNullOrEmpty(result))
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Error communicating with Corrade.";
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
continue;
}
 
@@ -2393,10 +1847,9 @@
 
if (string.IsNullOrEmpty(result))
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Error communicating with Corrade.";
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Error communicating with Corrade."; }));
continue;
}
 
@@ -2403,10 +1856,9 @@
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"No success status could be retrieved. ";
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"No success status could be retrieved. "; }));
continue;
}
 
@@ -2415,7 +1867,7 @@
case true:
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Returned object: " + objectData.Key.ToString();
vassalForm.StatusText.Text = @"Returned object: " + objectData.Key;
// Remove the row from the grid view.
DataGridViewRow row =
TopCollidersGridView.Rows.AsParallel()
@@ -2430,31 +1882,25 @@
case false:
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Could not return object " + objectData.Key.ToString() +
vassalForm.StatusText.Text = @"Could not return object " + objectData.Key +
@": " +
wasInput(wasKeyValueGet("error", result));
}));
break;
}
 
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusProgress.Value =
Math.Min((int) (Math.Abs(returnObjectUUIDQueue.Count - totalObjects)/
(double) totalObjects), 100);
Math.Min(
(int) (100d*Math.Abs(returnObjectUUIDQueue.Count - totalObjects)/totalObjects), 100);
}));
} while (!returnObjectUUIDQueue.Count.Equals(0));
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusProgress.Value = 100;
}));
vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusProgress.Value = 100; }));
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message;
}));
vassalForm.Invoke(
(MethodInvoker) (() => { vassalForm.StatusText.Text = @"Unexpected error: " + ex.Message; }));
}
finally
{
@@ -2567,27 +2013,30 @@
 
if (string.IsNullOrEmpty(result))
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Error communicating with Corrade.";
}));
vassalForm.Invoke(
(MethodInvoker)
(() =>
{
vassalForm.StatusText.Text = @"Error communicating with Corrade.";
}));
continue;
}
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
{
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"No success status could be retrieved. ";
}));
vassalForm.Invoke(
(MethodInvoker)
(() =>
{
vassalForm.StatusText.Text = @"No success status could be retrieved. ";
}));
continue;
}
switch (success)
{
case true:
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Teleport succeeded.";
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Teleport succeeded."; }));
Thread.Sleep(TimeSpan.FromSeconds(1).Milliseconds);
break;
default:
@@ -2602,10 +2051,9 @@
success = true;
break;
default:
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.StatusText.Text = @"Teleport failed.";
}));
vassalForm.Invoke(
(MethodInvoker)
(() => { vassalForm.StatusText.Text = @"Teleport failed."; }));
Thread.Sleep(10000);
break;
}
@@ -2652,7 +2100,8 @@
{"password", vassalConfiguration.Password},
{"action", "restart"},
{
"delay", vassalConfiguration.RegionRestartDelay.ToString(Utils.EnUsCulture)
"delay",
vassalConfiguration.RegionRestartDelay.ToString(Utils.EnUsCulture)
}
}), vassalConfiguration.DataTimeout);
 
@@ -2701,7 +2150,6 @@
}
catch (Exception)
{
 
}
finally
{
@@ -2715,7 +2163,6 @@
}
})
{IsBackground = true}.Start();
 
}
 
private void RequestFilterResidentList(object sender, EventArgs e)
@@ -2806,10 +2253,8 @@
try
{
bool alsoBan = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
alsoBan = vassalForm.ResidentBanAllEstatesBox.Checked;
}));
vassalForm.Invoke(
(MethodInvoker) (() => { alsoBan = vassalForm.ResidentBanAllEstatesBox.Checked; }));
 
// Teleport to the region.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
@@ -2866,12 +2311,10 @@
}
}));
}
 
} while (agentsQueue.Count.Equals(0));
}
catch (Exception)
{
 
}
finally
{
@@ -2902,7 +2345,7 @@
 
try
{
// Get the statistics.
// Get the map heights.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
@@ -2941,16 +2384,18 @@
foreach (int y in Enumerable.Range(1, 255))
{
bitmap.SetPixel(x, 256 - y,
Color.FromArgb((int) wasMapValueToRange(heights[256*x + y], 0, maxHeight, 0, 255), 0, 0));
Color.FromArgb(
Math.Max((int) wasMapValueToRange(heights[256*x + y], 0, maxHeight, 0, 255), 0),
0, 0));
}
}
Bitmap closureBitmap = (Bitmap)bitmap.Clone();
Bitmap closureBitmap = (Bitmap) bitmap.Clone();
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
switch (vassalForm.SaveTerrainFileDialog.ShowDialog())
switch (vassalForm.SavePNGFileDialog.ShowDialog())
{
case DialogResult.OK:
string file = vassalForm.SaveTerrainFileDialog.FileName;
string file = vassalForm.SavePNGFileDialog.FileName;
new Thread(() =>
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
@@ -2975,31 +2420,2294 @@
}
}));
})
{IsBackground = true, Priority = ThreadPriority.Normal}.Start();
{IsBackground = true}.Start();
break;
}
}));
}
}
catch (Exception ex)
{
vassalForm.BeginInvoke((MethodInvoker)(() =>
vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
StatusText.Text = ex.Message;
RegionTeleportGroup.Enabled = true;
RipTerrainButton.Enabled = true;
}));
}
}) {IsBackground = true}.Start();
}
 
private void RequestDownloadTerrain(object sender, EventArgs e)
{
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
DownloadTerrainButton.Enabled = false;
}));
 
new Thread(() =>
{
Monitor.Enter(ClientInstanceTeleportLock);
 
try
{
// Download the terrain.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "terrain"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"action", "get"}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade.");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved.");
 
if (!success)
throw new Exception("Could not download terrain.");
 
byte[] data = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
 
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
switch (vassalForm.SaveRawFileDialog.ShowDialog())
{
case DialogResult.OK:
string file = vassalForm.SaveRawFileDialog.FileName;
new Thread(() =>
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
try
{
vassalForm.StatusText.Text = @"saving terrain...";
vassalForm.StatusProgress.Value = 0;
 
File.WriteAllBytes(file, data);
 
vassalForm.StatusText.Text = @"terrain saved";
vassalForm.StatusProgress.Value = 100;
}
catch (Exception ex)
{
vassalForm.StatusText.Text = ex.Message;
}
}));
})
{IsBackground = true}.Start();
break;
}
}));
}
catch (Exception ex)
{
vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
vassalForm.BeginInvoke((MethodInvoker)(() =>
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
DownloadTerrainButton.Enabled = true;
RegionTeleportGroup.Enabled = true;
RipTerrainButton.Enabled = true;
}));
}
})
{IsBackground = true}.Start();
}
 
}) {IsBackground = true}.Start();
private void RequestUploadTerrain(object sender, EventArgs e)
{
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
UploadTerrainButton.Enabled = false;
}));
 
new Thread(() =>
{
Monitor.Enter(ClientInstanceTeleportLock);
 
try
{
byte[] data = null;
vassalForm.Invoke((MethodInvoker) (() =>
{
switch (vassalForm.LoadRawFileDialog.ShowDialog())
{
case DialogResult.OK:
string file = vassalForm.LoadRawFileDialog.FileName;
vassalForm.StatusText.Text = @"loading terrain...";
vassalForm.StatusProgress.Value = 0;
 
data = File.ReadAllBytes(file);
 
vassalForm.StatusText.Text = @"terrain loaded";
vassalForm.StatusProgress.Value = 100;
break;
}
}));
 
// Upload the terrain.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "terrain"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"action", "set"},
{"data", Convert.ToBase64String(data)}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade.");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved.");
 
if (!success)
throw new Exception("Could not upload terrain.");
}
catch (Exception ex)
{
vassalForm.BeginInvoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
UploadTerrainButton.Enabled = true;
RegionTeleportGroup.Enabled = true;
}));
}
})
{IsBackground = true}.Start();
}
 
private void RequestTabsChanged(object sender, EventArgs e)
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
overviewTabTimer.Stop();
regionsStateTabTimer.Stop();
residentListTabTimer.Stop();
estateTopTabTimer.Stop();
 
if (Tabs.SelectedTab.Equals(OverviewTab))
{
overviewTabTimer.Start();
return;
}
if (Tabs.SelectedTab.Equals(RegionsStateTab))
{
regionsStateTabTimer.Start();
return;
}
if (Tabs.SelectedTab.Equals(ResidentListTab))
{
residentListTabTimer.Start();
return;
}
if (Tabs.SelectedTab.Equals(EstateTopTab))
{
estateTopTabTimer.Start();
return;
}
if (Tabs.SelectedTab.Equals(EstateTexturesTab))
{
estateTexturesTabTimer.Start();
}
}));
}
 
private void RequestFilterEstateList(object sender, EventArgs e)
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
Regex estateListRowRegex;
switch (!string.IsNullOrEmpty(EstateListFilter.Text))
{
case true:
estateListRowRegex = new Regex(EstateListFilter.Text, RegexOptions.Compiled);
break;
default:
estateListRowRegex = new Regex(@".+?", RegexOptions.Compiled);
break;
}
foreach (DataGridViewRow estateListRow in EstateListGridView.Rows.AsParallel().Cast<DataGridViewRow>())
{
estateListRow.Visible =
estateListRowRegex.IsMatch(estateListRow.Cells["EstateListName"].Value.ToString());
}
}));
}
 
private void EstateListSelected(object sender, EventArgs e)
{
string selectedEstateListType = string.Empty;
bool queryEstateList = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
switch (
!string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
{
case true:
queryEstateList = true;
break;
default:
EstateListsResidentsGroup.Enabled = false;
EstateListsGroupsGroup.Enabled = false;
queryEstateList = false;
break;
}
}));
 
if (!queryEstateList) return;
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
// Disable controls.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
EstateListsResidentsGroup.Enabled = false;
EstateListsGroupsGroup.Enabled = false;
}));
 
// Get the selected estate list.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade.");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved.");
 
if (!success)
throw new Exception("Could not retrieve estate list.");
 
vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
.Where(x => !string.IsNullOrEmpty(x))
.Select((x, i) => new {Index = i, Value = x})
.GroupBy(x => x.Index/2)
.Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
{
vassalForm.Invoke(
(MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
}
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { vassalForm.StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
// Enable controls
vassalForm.Invoke((MethodInvoker) (() =>
{
vassalForm.RegionTeleportGroup.Enabled = true;
 
switch (selectedEstateListType)
{
case "ban":
case "manager":
case "user":
EstateListsResidentsGroup.Enabled = true;
EstateListsGroupsGroup.Enabled = false;
break;
case "group":
EstateListsResidentsGroup.Enabled = false;
EstateListsGroupsGroup.Enabled = true;
break;
}
}));
}
})
{IsBackground = true}.Start();
}
 
private void RequestRemoveEstateListMember(object sender, EventArgs e)
{
// Get the estate list type.
string selectedEstateListType = string.Empty;
bool queryEstateList = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
if (vassalForm.EstateListSelectBox.SelectedItem == null)
{
queryEstateList = false;
return;
}
selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
switch (
!string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
{
case true:
queryEstateList = true;
break;
default:
queryEstateList = false;
break;
}
}));
 
// If not estate list type is selected then return.
if (!queryEstateList) return;
 
// Enqueue all the regions to restart.
Queue<UUID> estateListMembersQueue = new Queue<UUID>();
vassalForm.Invoke((MethodInvoker) (() =>
{
foreach (
DataGridViewRow estateListRow in
EstateListGridView.Rows.AsParallel()
.Cast<DataGridViewRow>()
.Where(o => o.Selected || o.Cells.Cast<DataGridViewCell>().Any(p => p.Selected)))
{
UUID estateListMemberUUID;
if (!UUID.TryParse(estateListRow.Cells["EstateListUUID"].Value.ToString(),
out estateListMemberUUID))
continue;
estateListMembersQueue.Enqueue(estateListMemberUUID);
}
}));
 
// If no rows were selected, enable teleports, the return button and return.
if (estateListMembersQueue.Count.Equals(0)) return;
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
RemoveEstateListMemberButton.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
UUID memberUUID = UUID.Zero;
do
{
try
{
memberUUID = estateListMembersQueue.Dequeue();
 
// Remove the agent or group from the list.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "setestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType},
{"action", "remove"},
{selectedEstateListType.Equals("group") ? "target" : "agent", memberUUID.ToString()}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
if (!success)
throw new Exception("Unable to remove member");
 
vassalForm.Invoke((MethodInvoker) (() =>
{
foreach (
int i in
EstateListGridView.Rows.AsParallel()
.Cast<DataGridViewRow>()
.Where(
o =>
o.Cells["EstateListUUID"].Value.ToString()
.Equals(memberUUID.ToString(),
StringComparison.OrdinalIgnoreCase)).Select(o => o.Index)
)
{
EstateListGridView.Rows.RemoveAt(i);
}
}));
}
catch (Exception ex)
{
vassalForm.Invoke(
(MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + memberUUID; }));
}
} while (!estateListMembersQueue.Count.Equals(0));
}
catch (Exception)
{
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
// Enable teleports and enable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
RemoveEstateListMemberButton.Enabled = true;
}));
}
})
{IsBackground = true}.Start();
}
 
private void RequestEstateListsAddResident(object sender, EventArgs e)
{
// Get the estate list type.
string selectedEstateListType = string.Empty;
bool queryEstateList = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
switch (
!string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
{
case true:
queryEstateList = true;
break;
default:
queryEstateList = false;
break;
}
}));
 
// If not estate list type is selected then return.
if (!queryEstateList) return;
 
string firstName = string.Empty;
string lastName = string.Empty;
 
vassalForm.Invoke((MethodInvoker) (() =>
{
switch (string.IsNullOrEmpty(EstateListsResidentFirstName.Text))
{
case true:
EstateListsResidentFirstName.BackColor = Color.MistyRose;
return;
default:
EstateListsResidentFirstName.BackColor = Color.Empty;
break;
}
firstName = EstateListsResidentFirstName.Text;
switch (string.IsNullOrEmpty(EstateListsResidentLastName.Text))
{
case true:
EstateListsResidentLastName.BackColor = Color.MistyRose;
return;
default:
EstateListsResidentLastName.BackColor = Color.Empty;
break;
}
lastName = EstateListsResidentLastName.Text;
}));
 
if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)) return;
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
EstateListsResidentsGroup.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
// Add the resident to the list.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "setestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType},
{"action", "add"},
{"firstname", firstName},
{"lastname", lastName}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
if (!success)
throw new Exception("Unable to add resident");
 
// Retrieve the estate list for updates.
result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade.");
 
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved.");
 
if (!success)
throw new Exception("Could not retrieve estate list.");
 
vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
.Where(x => !string.IsNullOrEmpty(x))
.Select((x, i) => new {Index = i, Value = x})
.GroupBy(x => x.Index/2)
.Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
{
vassalForm.Invoke(
(MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
}
}
catch (Exception ex)
{
vassalForm.Invoke(
(MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + firstName + @" " + lastName; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
// Enable teleports and enable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
EstateListsResidentsGroup.Enabled = true;
}));
}
})
{IsBackground = true}.Start();
}
 
private void RequestEstateListsAddGroup(object sender, EventArgs e)
{
// Get the estate list type.
string selectedEstateListType = string.Empty;
bool queryEstateList = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
switch (
!string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
{
case true:
queryEstateList = true;
break;
default:
queryEstateList = false;
break;
}
}));
 
// If not estate list type is selected then return.
if (!queryEstateList) return;
 
string target = string.Empty;
 
vassalForm.Invoke((MethodInvoker) (() =>
{
switch (string.IsNullOrEmpty(EstateListsAddGroupBox.Text))
{
case true:
EstateListsAddGroupBox.BackColor = Color.MistyRose;
return;
default:
EstateListsAddGroupBox.BackColor = Color.Empty;
break;
}
target = EstateListsAddGroupBox.Text;
}));
 
if (string.IsNullOrEmpty(target)) return;
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
EstateListsGroupsGroup.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
// Add the group to the list.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "setestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType},
{"action", "add"},
{"target", target}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
if (!success)
throw new Exception("Unable to add group");
 
// Retrieve the estate list for updates.
result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade.");
 
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved.");
 
if (!success)
throw new Exception("Could not retrieve estate list.");
 
vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
.Where(x => !string.IsNullOrEmpty(x))
.Select((x, i) => new {Index = i, Value = x})
.GroupBy(x => x.Index/2)
.Select(x => x.Select(v => v.Value).ToList()).Where(x => x.Count.Equals(2)))
{
vassalForm.Invoke(
(MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
}
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
// Enable teleports and enable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
EstateListsGroupsGroup.Enabled = true;
}));
}
})
{IsBackground = true}.Start();
}
 
private void RequestRegionDebugApply(object sender, EventArgs e)
{
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
ApplyRegionDebugButton.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
bool scripts = false;
bool collisons = false;
bool physics = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
scripts = RegionDebugScriptsBox.Checked;
collisons = RegionDebugCollisionsBox.Checked;
physics = RegionDebugPhysicsBox.Checked;
}));
 
// Set the debug settings.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "setregiondebug"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"scripts", scripts.ToString()},
{"collisions", collisons.ToString()},
{"physics", physics.ToString()}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
if (!success)
throw new Exception("Unable to set region debug");
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
}
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
ApplyRegionDebugButton.Enabled = true;
}));
})
{IsBackground = true}.Start();
}
 
private void RequestApplyRegionInfo(object sender, EventArgs e)
{
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
ApplyRegionInfoButton.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
bool terraform = false;
bool fly = false;
bool damage = false;
bool resell = false;
bool push = false;
bool parcel = false;
bool mature = false;
uint agentLimit = 20;
double objectBonus = 2.0;
 
bool run = false;
 
vassalForm.Invoke((MethodInvoker) (() =>
{
terraform = RegionInfoTerraformBox.Checked;
fly = RegionInfoFlyBox.Checked;
damage = RegionInfoDamageBox.Checked;
resell = RegioninfoResellBox.Checked;
push = RegionInfoPushBox.Checked;
parcel = RegionInfoParcelBox.Checked;
mature = RegionInfoMatureBox.Checked;
switch (!uint.TryParse(RegionInfoAgentLimitBox.Text, out agentLimit))
{
case true:
RegionInfoAgentLimitBox.BackColor = Color.MistyRose;
return;
default:
RegionInfoAgentLimitBox.BackColor = Color.Empty;
run = true;
break;
}
switch (!double.TryParse(RegionInfoObjectBonusBox.Text, out objectBonus))
{
case true:
RegionInfoObjectBonusBox.BackColor = Color.MistyRose;
return;
default:
RegionInfoAgentLimitBox.BackColor = Color.Empty;
break;
}
 
run = true;
}));
 
if (!run) return;
 
// Set the debug settings.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "setregioninfo"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"terraform", terraform.ToString()},
{"fly", fly.ToString()},
{"damage", damage.ToString()},
{"resell", resell.ToString()},
{"push", push.ToString()},
{"parcel", parcel.ToString()},
{"mature", mature.ToString()},
{"limit", agentLimit.ToString(Utils.EnUsCulture)},
{"bonus", objectBonus.ToString(Utils.EnUsCulture)}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
if (!success)
throw new Exception("Unable to set region info");
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
}
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
ApplyRegionInfoButton.Enabled = true;
}));
})
{IsBackground = true}.Start();
}
 
private void RequestEstateTexturesApply(object sender, EventArgs e)
{
List<UUID> groundTextureUUIDs = new List<UUID>();
vassalForm.Invoke((MethodInvoker) (() =>
{
UUID textureUUID;
switch (!UUID.TryParse(RegionTexturesLowUUIDApplyBox.Text, out textureUUID))
{
case true:
RegionTexturesLowUUIDApplyBox.BackColor = Color.MistyRose;
return;
default:
RegionTexturesLowUUIDApplyBox.BackColor = Color.Empty;
break;
}
groundTextureUUIDs.Add(textureUUID);
 
switch (!UUID.TryParse(RegionTexturesMiddleLowUUIDApplyBox.Text, out textureUUID))
{
case true:
RegionTexturesMiddleLowUUIDApplyBox.BackColor = Color.MistyRose;
return;
default:
RegionTexturesMiddleLowUUIDApplyBox.BackColor = Color.Empty;
break;
}
groundTextureUUIDs.Add(textureUUID);
 
switch (!UUID.TryParse(RegionTexturesMiddleHighUUIDApplyBox.Text, out textureUUID))
{
case true:
RegionTexturesMiddleHighUUIDApplyBox.BackColor = Color.MistyRose;
return;
default:
RegionTexturesMiddleHighUUIDApplyBox.BackColor = Color.Empty;
break;
}
groundTextureUUIDs.Add(textureUUID);
 
switch (!UUID.TryParse(RegionTexturesHighUUIDApplyBox.Text, out textureUUID))
{
case true:
RegionTexturesHighUUIDApplyBox.BackColor = Color.MistyRose;
return;
default:
RegionTexturesHighUUIDApplyBox.BackColor = Color.Empty;
break;
}
groundTextureUUIDs.Add(textureUUID);
}));
 
if (!groundTextureUUIDs.Count.Equals(4)) return;
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
GroundTexturesGroup.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
// Set the debug settings.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "setregionterraintextures"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"data", wasEnumerableToCSV(groundTextureUUIDs.Select(o => o.ToString()))}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
if (!success)
throw new Exception("Unable to apply estate ground textures");
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
}
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
GroundTexturesGroup.Enabled = true;
}));
})
{IsBackground = true};
}
 
private void RequestDownloadRegionTexture(object sender, EventArgs e)
{
string textureName = string.Empty;
UUID textureUUID = UUID.Zero;
bool run = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
Button button = sender as Button;
if (button == null)
{
run = false;
return;
}
textureName = button.Tag.ToString();
switch (textureName)
{
case "Low":
if (!UUID.TryParse(RegionTexturesLowUUIDBox.Text, out textureUUID))
{
run = false;
return;
}
goto case "MiddleLow";
case "MiddleLow":
if (!UUID.TryParse(RegionTexturesMiddleLowUUIDBox.Text, out textureUUID))
{
run = false;
return;
}
goto case "MiddleHigh";
case "MiddleHigh":
if (!UUID.TryParse(RegionTexturesMiddleHighUUIDBox.Text, out textureUUID))
{
run = false;
return;
}
goto case "High";
case "High":
if (!UUID.TryParse(RegionTexturesHighUUIDBox.Text, out textureUUID))
{
run = false;
return;
}
run = true;
break;
}
}));
 
if (!run) return;
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
GroundTexturesGroup.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "download"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"item", textureUUID.ToString()},
{"type", "Texture"},
{"format", "Png"}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
byte[] mapImageBytes = Convert.FromBase64String(wasInput(wasKeyValueGet("data", result)));
Image mapImage;
using (MemoryStream memoryStream = new MemoryStream(mapImageBytes, 0, mapImageBytes.Length))
{
mapImage = Image.FromStream(memoryStream);
}
 
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
switch (vassalForm.SavePNGFileDialog.ShowDialog())
{
case DialogResult.OK:
string file = vassalForm.SavePNGFileDialog.FileName;
new Thread(() =>
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
try
{
vassalForm.StatusText.Text = @"saving texture...";
vassalForm.StatusProgress.Value = 0;
 
mapImage.Save(file, ImageFormat.Png);
 
vassalForm.StatusText.Text = @"texture saved";
vassalForm.StatusProgress.Value = 100;
}
catch (Exception ex)
{
vassalForm.StatusText.Text = ex.Message;
}
finally
{
mapImage.Dispose();
}
}));
})
{IsBackground = true}.Start();
break;
}
}));
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
}
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
GroundTexturesGroup.Enabled = true;
}));
})
{IsBackground = true}.Start();
}
 
private void RequestEstateListsAddGroupsFromCSV(object sender, EventArgs e)
{
// Get the estate list type.
string selectedEstateListType = string.Empty;
bool queryEstateList = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
switch (
!string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
{
case true:
queryEstateList = true;
break;
default:
queryEstateList = false;
break;
}
}));
 
// If not estate list type is selected then return.
if (!queryEstateList) return;
 
Queue<KeyValuePair<string, UUID>> targets = new Queue<KeyValuePair<string, UUID>>();
 
vassalForm.Invoke((MethodInvoker) (() =>
{
switch (vassalForm.LoadCSVFile.ShowDialog())
{
case DialogResult.OK:
string file = vassalForm.LoadCSVFile.FileName;
try
{
vassalForm.StatusText.Text = @"loading group list...";
vassalForm.StatusProgress.Value = 0;
 
// import groups
UUID targetUUID;
foreach (KeyValuePair<string, UUID> target in
File.ReadAllLines(file)
.AsParallel()
.Select(o => new List<string>(wasCSVToEnumerable(o)))
.Where(o => o.Count == 2)
.ToDictionary(o => o.First(),
p =>
UUID.TryParse(p.Last(), out targetUUID)
? targetUUID
: UUID.Zero))
{
targets.Enqueue(target);
}
 
vassalForm.StatusText.Text = @"group list loaded";
vassalForm.StatusProgress.Value = 100;
}
catch (Exception ex)
{
vassalForm.StatusText.Text = ex.Message;
}
break;
}
}));
 
if (targets.Count.Equals(0)) return;
int initialQueueSize = targets.Count;
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
EstateListsGroupsGroup.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
do
{
KeyValuePair<string, UUID> target = targets.Dequeue();
 
vassalForm.Invoke((MethodInvoker) (() =>
{
StatusText.Text = @"Adding to estate list: " + target.Key;
vassalForm.StatusProgress.Value =
Math.Min((int) (100d*Math.Abs(targets.Count - initialQueueSize)/initialQueueSize), 100);
}));
 
// Skip any items that already exist.
bool run = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
run =
!EstateListGridView.Rows.AsParallel()
.Cast<DataGridViewRow>()
.Any(o => o.Cells["EstateListUUID"].Value.ToString().Equals(target.Value.ToString()));
}));
if (!run) continue;
 
// Skip broken UUIDs.
if (target.Value.Equals(UUID.Zero)) continue;
 
try
{
// Add the group to the list.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "setestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType},
{"action", "add"},
{"target", target.Value.ToString()}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
if (!success)
throw new Exception("Unable to add group");
}
catch (Exception ex)
{
vassalForm.Invoke(
(MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target.Value; }));
}
} while (!targets.Count.Equals(0));
 
// Retrieve the estate list.
try
{
// Retrieve the estate list for updates.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade.");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved.");
 
if (!success)
throw new Exception("Could not retrieve estate list.");
 
vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
.Where(x => !string.IsNullOrEmpty(x))
.Select((x, i) => new {Index = i, Value = x})
.GroupBy(x => x.Index/2)
.Select(x => x.Select(v => v.Value).ToList()))
{
vassalForm.BeginInvoke(
(MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
}
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
// Enable teleports and enable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
EstateListsGroupsGroup.Enabled = true;
}));
}
})
{IsBackground = true}.Start();
}
 
private void RequestEstateListsAddResidentsFromCSV(object sender, EventArgs e)
{
// Get the estate list type.
string selectedEstateListType = string.Empty;
bool queryEstateList = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
if (vassalForm.EstateListSelectBox.SelectedItem == null) return;
selectedEstateListType = vassalForm.EstateListSelectBox.SelectedItem.ToString();
switch (
!string.IsNullOrEmpty(selectedEstateListType) && vassalForm.EstateListSelectBox.SelectedIndex != -1)
{
case true:
queryEstateList = true;
break;
default:
queryEstateList = false;
break;
}
}));
 
// If not estate list type is selected then return.
if (!queryEstateList) return;
 
Queue<KeyValuePair<string, UUID>> targets = new Queue<KeyValuePair<string, UUID>>();
 
vassalForm.Invoke((MethodInvoker) (() =>
{
switch (vassalForm.LoadCSVFile.ShowDialog())
{
case DialogResult.OK:
string file = vassalForm.LoadCSVFile.FileName;
try
{
vassalForm.StatusText.Text = @"loading residents list...";
vassalForm.StatusProgress.Value = 0;
 
// import groups
UUID targetUUID;
foreach (KeyValuePair<string, UUID> target in
File.ReadAllLines(file)
.AsParallel()
.Select(o => new List<string>(wasCSVToEnumerable(o)))
.Where(o => o.Count == 2)
.ToDictionary(o => o.First(),
p =>
UUID.TryParse(p.Last(), out targetUUID)
? targetUUID
: UUID.Zero))
{
targets.Enqueue(target);
}
 
vassalForm.StatusText.Text = @"residents list loaded";
vassalForm.StatusProgress.Value = 100;
}
catch (Exception ex)
{
vassalForm.StatusText.Text = ex.Message;
}
break;
}
}));
 
if (targets.Count.Equals(0)) return;
int initialQueueSize = targets.Count;
 
// Block teleports and disable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = false;
EstateListsResidentsGroup.Enabled = false;
}));
 
new Thread(() =>
{
try
{
Monitor.Enter(ClientInstanceTeleportLock);
 
do
{
KeyValuePair<string, UUID> target = targets.Dequeue();
 
vassalForm.Invoke((MethodInvoker) (() =>
{
StatusText.Text = @"Adding to estate list: " + target.Key;
vassalForm.StatusProgress.Value =
Math.Min((int) (100d*Math.Abs(targets.Count - initialQueueSize)/initialQueueSize), 100);
}));
 
// Skip any items that already exist.
bool run = false;
vassalForm.Invoke((MethodInvoker) (() =>
{
run =
!EstateListGridView.Rows.AsParallel()
.Cast<DataGridViewRow>()
.Any(o => o.Cells["EstateListUUID"].Value.ToString().Equals(target.Value.ToString()));
}));
if (!run) continue;
 
// Skip broken UUIDs.
if (target.Value.Equals(UUID.Zero)) continue;
 
try
{
// Add the group to the list.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "setestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType},
{"action", "add"},
{"agent", target.Value.ToString()}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved");
 
if (!success)
throw new Exception("Unable to add resident");
}
catch (Exception ex)
{
vassalForm.Invoke(
(MethodInvoker) (() => { StatusText.Text = ex.Message + @": " + target.Value; }));
}
} while (!targets.Count.Equals(0));
 
// Retrieve the estate list.
try
{
// Retrieve the estate list for updates.
string result = wasPOST(vassalConfiguration.HTTPServerURL,
wasKeyValueEscape(new Dictionary<string, string>
{
{"command", "getestatelist"},
{"group", vassalConfiguration.Group},
{"password", vassalConfiguration.Password},
{"type", selectedEstateListType}
}), vassalConfiguration.DataTimeout);
 
if (string.IsNullOrEmpty(result))
throw new Exception("Error communicating with Corrade.");
 
bool success;
if (!bool.TryParse(wasInput(wasKeyValueGet("success", result)), out success))
throw new Exception("No success status could be retrieved.");
 
if (!success)
throw new Exception("Could not retrieve estate list.");
 
vassalForm.Invoke((MethodInvoker) (() => { EstateListGridView.Rows.Clear(); }));
foreach (List<string> data in wasCSVToEnumerable(wasInput(wasKeyValueGet("data", result)))
.Where(x => !string.IsNullOrEmpty(x))
.Select((x, i) => new {Index = i, Value = x})
.GroupBy(x => x.Index/2)
.Select(x => x.Select(v => v.Value).ToList()))
{
vassalForm.BeginInvoke(
(MethodInvoker) (() => { EstateListGridView.Rows.Add(data.First(), data.Last()); }));
}
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
}
catch (Exception ex)
{
vassalForm.Invoke((MethodInvoker) (() => { StatusText.Text = ex.Message; }));
}
finally
{
Monitor.Exit(ClientInstanceTeleportLock);
// Enable teleports and enable button.
vassalForm.Invoke((MethodInvoker) (() =>
{
RegionTeleportGroup.Enabled = true;
EstateListsResidentsGroup.Enabled = true;
}));
}
})
{IsBackground = true}.Start();
}
 
private void RequestExportEstateList(object sender, EventArgs e)
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
switch (vassalForm.ExportCSVDialog.ShowDialog())
{
case DialogResult.OK:
string file = vassalForm.ExportCSVDialog.FileName;
new Thread(() =>
{
vassalForm.BeginInvoke((MethodInvoker) (() =>
{
try
{
vassalForm.StatusText.Text = @"exporting...";
vassalForm.StatusProgress.Value = 0;
 
using (StreamWriter streamWriter = new StreamWriter(file, false, Encoding.UTF8))
{
foreach (DataGridViewRow estateListRow in EstateListGridView.Rows)
{
streamWriter.WriteLine(wasEnumerableToCSV(new[]
{
estateListRow.Cells["EstateListName"].Value.ToString(),
estateListRow.Cells["EstateListUUID"].Value.ToString()
}));
}
}
 
vassalForm.StatusText.Text = @"exported";
vassalForm.StatusProgress.Value = 100;
}
catch (Exception ex)
{
vassalForm.StatusText.Text = ex.Message;
}
}));
})
{IsBackground = true}.Start();
break;
}
}));
}
 
/// <summary>
/// Linden constants.
/// </summary>
public struct LINDEN_CONSTANTS
{
public struct ALERTS
{
public const string NO_ROOM_TO_SIT_HERE = @"No room to sit here, try another spot.";
 
public const string UNABLE_TO_SET_HOME =
@"You can only set your 'Home Location' on your land or at a mainland Infohub.";
 
public const string HOME_SET = @"Home position set.";
}
 
public struct ASSETS
{
public struct NOTECARD
{
public const string NEWLINE = "\n";
public const uint MAXIMUM_BODY_LENTH = 65536;
}
}
 
public struct AVATARS
{
public const uint SET_DISPLAY_NAME_SUCCESS = 200;
public const string LASTNAME_PLACEHOLDER = @"Resident";
public const uint MAXIMUM_DISPLAY_NAME_CHARACTERS = 31;
public const uint MINIMUM_DISPLAY_NAME_CHARACTERS = 1;
public const uint MAXIMUM_NUMBER_OF_ATTACHMENTS = 38;
 
public struct PROFILE
{
public const uint SECOND_LIFE_TEXT_SIZE = 510;
public const uint FIRST_LIFE_TEXT_SIZE = 253;
}
 
public struct PICKS
{
public const uint MAXIMUM_PICKS = 10;
public const uint MAXIMUM_PICK_DESCRIPTION_SIZE = 1022;
}
 
public struct CLASSIFIEDS
{
public const uint MAXIMUM_CLASSIFIEDS = 100;
}
}
 
public struct PRIMITIVES
{
public const uint MAXIMUM_NAME_SIZE = 63;
public const uint MAXIMUM_DESCRIPTION_SIZE = 127;
public const double MAXIMUM_REZ_HEIGHT = 4096.0;
public const double MINIMUM_SIZE_X = 0.01;
public const double MINIMUM_SIZE_Y = 0.01;
public const double MINIMUM_SIZE_Z = 0.01;
public const double MAXIMUM_SIZE_X = 64.0;
public const double MAXIMUM_SIZE_Y = 64.0;
public const double MAXIMUM_SIZE_Z = 64.0;
}
 
public struct OBJECTS
{
public const uint MAXIMUM_PRIMITIVE_COUNT = 256;
}
 
public struct DIRECTORY
{
public struct EVENT
{
public const uint SEARCH_RESULTS_COUNT = 200;
}
 
public struct GROUP
{
public const uint SEARCH_RESULTS_COUNT = 100;
}
 
public struct LAND
{
public const uint SEARCH_RESULTS_COUNT = 100;
}
 
public struct PEOPLE
{
public const uint SEARCH_RESULTS_COUNT = 100;
}
}
 
public struct ESTATE
{
public const uint REGION_RESTART_DELAY = 120;
public const uint MAXIMUM_BAN_LIST_LENGTH = 500;
public const uint MAXIMUM_GROUP_LIST_LENGTH = 63;
public const uint MAXIMUM_USER_LIST_LENGTH = 500;
public const uint MAXIMUM_MANAGER_LIST_LENGTH = 10;
 
public struct MESSAGES
{
public const string REGION_RESTART_MESSAGE = @"restart";
}
}
 
public struct PARCELS
{
public const double MAXIMUM_AUTO_RETURN_TIME = 999999;
public const uint MINIMUM_AUTO_RETURN_TIME = 0;
public const uint MAXIMUM_NAME_LENGTH = 63;
public const uint MAXIMUM_DESCRIPTION_LENGTH = 255;
}
 
public struct GRID
{
public const string SECOND_LIFE = @"Second Life";
public const string TIME_ZONE = @"Pacific Standard Time";
}
 
public struct CHAT
{
public const uint MAXIMUM_MESSAGE_LENGTH = 1024;
}
 
public struct GROUPS
{
public const uint MAXIMUM_NUMBER_OF_ROLES = 10;
public const string EVERYONE_ROLE_NAME = @"Everyone";
public const uint MAXIMUM_GROUP_NAME_LENGTH = 35;
public const uint MAXIMUM_GROUP_TITLE_LENGTH = 20;
}
 
public struct NOTICES
{
public const uint MAXIMUM_NOTICE_MESSAGE_LENGTH = 512;
}
 
public struct LSL
{
public const string CSV_DELIMITER = @", ";
public const float SENSOR_RANGE = 96;
public const string DATE_TIME_STAMP = @"yyy-MM-ddTHH:mm:ss.ffffffZ";
}
 
public struct REGION
{
public const float TELEPORT_MINIMUM_DISTANCE = 1;
public const float DEFAULT_AGENT_LIMIT = 40;
public const float DEFAULT_OBJECT_BONUS = 1;
public const bool DEFAULT_FIXED_SUN = false;
public const float DEFAULT_TERRAIN_LOWER_LIMIT = -4;
public const float DEFAULT_TERRAIN_RAISE_LIMIT = 4;
public const bool DEFAULT_USE_ESTATE_SUN = true;
public const float DEFAULT_WATER_HEIGHT = 20;
public const float SUNRISE = 6;
}
 
public struct VIEWER
{
public const float MAXIMUM_DRAW_DISTANCE = 4096;
}
 
public struct TELEPORTS
{
public struct THROTTLE
{
public const uint MAX_TELEPORTS = 10;
public const uint GRACE_SECONDS = 15;
}
}
}
 
/// <summary>
/// Constants used by Corrade.
/// </summary>
public struct VASSAL_CONSTANTS
{
/// <summary>
/// Copyright.
/// </summary>
public const string COPYRIGHT = @"(c) Copyright 2013 Wizardry and Steamworks";
 
public const string WIZARDRY_AND_STEAMWORKS = @"Wizardry and Steamworks";
public const string VASSAL = @"Vassal";
public const string WIZARDRY_AND_STEAMWORKS_WEBSITE = @"http://grimore.org";
 
/// <summary>
/// Vassal version.
/// </summary>
public static readonly string VASSAL_VERSION = Assembly.GetEntryAssembly().GetName().Version.ToString();
 
/// <summary>
/// Corrade user agent.
/// </summary>
public static readonly string USER_AGENT =
$"{VASSAL}/{VASSAL_VERSION} ({WIZARDRY_AND_STEAMWORKS_WEBSITE})";
 
/// <summary>
/// Vassal compile date.
/// </summary>
public static readonly string VASSAL_COMPILE_DATE = new DateTime(2000, 1, 1).Add(new TimeSpan(
TimeSpan.TicksPerDay*Assembly.GetEntryAssembly().GetName().Version.Build + // days since 1 January 2000
TimeSpan.TicksPerSecond*2*Assembly.GetEntryAssembly().GetName().Version.Revision)).ToLongDateString();
 
/// <summary>
/// Vassal configuration file.
/// </summary>
public static readonly string VASSAL_CONFIGURATION_FILE = @"Vassal.ini";
 
/// <summary>
/// Vassal regions file.
/// </summary>
public static readonly string VASSAL_REGIONS = @"Regions.csv";
 
/// <summary>
/// Conten-types that Corrade can send and receive.
/// </summary>
public struct CONTENT_TYPE
{
public const string TEXT_PLAIN = @"text/plain";
public const string WWW_FORM_URLENCODED = @"application/x-www-form-urlencoded";
}
}
 
#region CRYPTOGRAPHY
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Gets a sub-array from an array.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="data">the array</param>
/// <param name="start">the start index</param>
/// <param name="stop">the stop index (-1 denotes the end)</param>
/// <returns>the array slice between start and stop</returns>
public static T[] wasGetSubArray<T>(T[] data, int start, int stop)
{
if (stop.Equals(-1))
stop = data.Length - 1;
T[] result = new T[stop - start + 1];
Array.Copy(data, start, result, 0, stop - start + 1);
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Delete a sub-array and return the result.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="data">the array</param>
/// <param name="start">the start index</param>
/// <param name="stop">the stop index (-1 denotes the end)</param>
/// <returns>the array without elements between start and stop</returns>
public static T[] wasDeleteSubArray<T>(T[] data, int start, int stop)
{
if (stop.Equals(-1))
stop = data.Length - 1;
T[] result = new T[data.Length - (stop - start) - 1];
Array.Copy(data, 0, result, 0, start);
Array.Copy(data, stop + 1, result, start, data.Length - stop - 1);
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Concatenate multiple arrays.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="arrays">multiple arrays</param>
/// <returns>a flat array with all arrays concatenated</returns>
public static T[] wasConcatenateArrays<T>(params T[][] arrays)
{
int resultLength = 0;
foreach (T[] o in arrays)
{
resultLength += o.Length;
}
T[] result = new T[resultLength];
int offset = 0;
for (int x = 0; x < arrays.Length; x++)
{
arrays[x].CopyTo(result, offset);
offset += arrays[x].Length;
}
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Permutes an array in reverse a given number of times.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="input">the array</param>
/// <param name="times">the number of times to permute</param>
/// <returns>the array with the elements permuted</returns>
private static T[] wasReversePermuteArrayElements<T>(T[] input, int times)
{
if (times.Equals(0)) return input;
T[] slice = new T[input.Length];
Array.Copy(input, 1, slice, 0, input.Length - 1);
Array.Copy(input, 0, slice, input.Length - 1, 1);
return wasReversePermuteArrayElements(slice, --times);
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Permutes an array forward a given number of times.
/// </summary>
/// <typeparam name="T">the array type</typeparam>
/// <param name="input">the array</param>
/// <param name="times">the number of times to permute</param>
/// <returns>the array with the elements permuted</returns>
private static T[] wasForwardPermuteArrayElements<T>(T[] input, int times)
{
if (times.Equals(0)) return input;
T[] slice = new T[input.Length];
Array.Copy(input, input.Length - 1, slice, 0, 1);
Array.Copy(input, 0, slice, 1, input.Length - 1);
return wasForwardPermuteArrayElements(slice, --times);
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Encrypt or decrypt a message given a set of rotors, plugs and a reflector.
/// </summary>
/// <param name="message">the message to encyrpt or decrypt</param>
/// <param name="rotors">any combination of: 1, 2, 3, 4, 5, 6, 7, 8, b, g</param>
/// <param name="plugs">the letter representing the start character for the rotor</param>
/// <param name="reflector">any one of: B, b, C, c</param>
/// <returns>either a decrypted or encrypted string</returns>
private static string wasEnigma(string message, char[] rotors, char[] plugs, char reflector)
{
Dictionary<char, char[]> def_rotors = new Dictionary<char, char[]>
{
{
'1', new[]
{
'e', 'k', 'm', 'f', 'l',
'g', 'd', 'q', 'v', 'z',
'n', 't', 'o', 'w', 'y',
'h', 'x', 'u', 's', 'p',
'a', 'i', 'b', 'r', 'c',
'j'
}
},
{
'2', new[]
{
'a', 'j', 'd', 'k', 's',
'i', 'r', 'u', 'x', 'b',
'l', 'h', 'w', 't', 'm',
'c', 'q', 'g', 'z', 'n',
'p', 'y', 'f', 'v', 'o',
'e'
}
},
{
'3', new[]
{
'b', 'd', 'f', 'h', 'j',
'l', 'c', 'p', 'r', 't',
'x', 'v', 'z', 'n', 'y',
'e', 'i', 'w', 'g', 'a',
'k', 'm', 'u', 's', 'q',
'o'
}
},
{
'4', new[]
{
'e', 's', 'o', 'v', 'p',
'z', 'j', 'a', 'y', 'q',
'u', 'i', 'r', 'h', 'x',
'l', 'n', 'f', 't', 'g',
'k', 'd', 'c', 'm', 'w',
'b'
}
},
{
'5', new[]
{
'v', 'z', 'b', 'r', 'g',
'i', 't', 'y', 'u', 'p',
's', 'd', 'n', 'h', 'l',
'x', 'a', 'w', 'm', 'j',
'q', 'o', 'f', 'e', 'c',
'k'
}
},
{
'6', new[]
{
'j', 'p', 'g', 'v', 'o',
'u', 'm', 'f', 'y', 'q',
'b', 'e', 'n', 'h', 'z',
'r', 'd', 'k', 'a', 's',
'x', 'l', 'i', 'c', 't',
'w'
}
},
{
'7', new[]
{
'n', 'z', 'j', 'h', 'g',
'r', 'c', 'x', 'm', 'y',
's', 'w', 'b', 'o', 'u',
'f', 'a', 'i', 'v', 'l',
'p', 'e', 'k', 'q', 'd',
't'
}
},
{
'8', new[]
{
'f', 'k', 'q', 'h', 't',
'l', 'x', 'o', 'c', 'b',
'j', 's', 'p', 'd', 'z',
'r', 'a', 'm', 'e', 'w',
'n', 'i', 'u', 'y', 'g',
'v'
}
},
{
'b', new[]
{
'l', 'e', 'y', 'j', 'v',
'c', 'n', 'i', 'x', 'w',
'p', 'b', 'q', 'm', 'd',
'r', 't', 'a', 'k', 'z',
'g', 'f', 'u', 'h', 'o',
's'
}
},
{
'g', new[]
{
'f', 's', 'o', 'k', 'a',
'n', 'u', 'e', 'r', 'h',
'm', 'b', 't', 'i', 'y',
'c', 'w', 'l', 'q', 'p',
'z', 'x', 'v', 'g', 'j',
'd'
}
}
};
 
Dictionary<char, char[]> def_reflectors = new Dictionary<char, char[]>
{
{
'B', new[]
{
'a', 'y', 'b', 'r', 'c', 'u', 'd', 'h',
'e', 'q', 'f', 's', 'g', 'l', 'i', 'p',
'j', 'x', 'k', 'n', 'm', 'o', 't', 'z',
'v', 'w'
}
},
{
'b', new[]
{
'a', 'e', 'b', 'n', 'c', 'k', 'd', 'q',
'f', 'u', 'g', 'y', 'h', 'w', 'i', 'j',
'l', 'o', 'm', 'p', 'r', 'x', 's', 'z',
't', 'v'
}
},
{
'C', new[]
{
'a', 'f', 'b', 'v', 'c', 'p', 'd', 'j',
'e', 'i', 'g', 'o', 'h', 'y', 'k', 'r',
'l', 'z', 'm', 'x', 'n', 'w', 't', 'q',
's', 'u'
}
},
{
'c', new[]
{
'a', 'r', 'b', 'd', 'c', 'o', 'e', 'j',
'f', 'n', 'g', 't', 'h', 'k', 'i', 'v',
'l', 'm', 'p', 'w', 'q', 'z', 's', 'x',
'u', 'y'
}
}
};
 
// Setup rotors from plugs.
foreach (char rotor in rotors)
{
char plug = plugs[Array.IndexOf(rotors, rotor)];
int i = Array.IndexOf(def_rotors[rotor], plug);
if (i.Equals(0)) continue;
def_rotors[rotor] = wasConcatenateArrays(new[] {plug},
wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i, i), i, -1),
wasGetSubArray(wasDeleteSubArray(def_rotors[rotor], i + 1, -1), 0, i - 1));
}
 
StringBuilder result = new StringBuilder();
foreach (char c in message)
{
if (!char.IsLetter(c))
{
result.Append(c);
continue;
}
 
// Normalize to lower.
char l = char.ToLower(c);
 
Action<char[]> rotate = o =>
{
int i = o.Length - 1;
do
{
def_rotors[o[0]] = wasForwardPermuteArrayElements(def_rotors[o[0]], 1);
if (i.Equals(0))
{
rotors = wasReversePermuteArrayElements(o, 1);
continue;
}
l = wasGetElementAt(def_rotors[o[1]], Array.IndexOf(def_rotors[o[0]], l) - 1);
o = wasReversePermuteArrayElements(o, 1);
} while (--i > -1);
};
 
// Forward pass through the Enigma's rotors.
rotate.Invoke(rotors);
 
// Reflect
int x = Array.IndexOf(def_reflectors[reflector], l);
l = (x + 1)%2 == 0 ? def_reflectors[reflector][x - 1] : def_reflectors[reflector][x + 1];
 
// Reverse the order of the rotors.
Array.Reverse(rotors);
 
// Reverse pass through the Enigma's rotors.
rotate.Invoke(rotors);
 
if (char.IsUpper(c))
{
l = char.ToUpper(l);
}
result.Append(l);
}
 
return result.ToString();
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Expand the VIGENRE key to the length of the input.
/// </summary>
/// <param name="input">the input to expand to</param>
/// <param name="enc_key">the key to expand</param>
/// <returns>the expanded key</returns>
private static string wasVigenereExpandKey(string input, string enc_key)
{
string exp_key = string.Empty;
int i = 0, j = 0;
do
{
char p = input[i];
if (!char.IsLetter(p))
{
exp_key += p;
++i;
continue;
}
int m = j%enc_key.Length;
exp_key += enc_key[m];
++j;
++i;
} while (i < input.Length);
return exp_key;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Encrypt using VIGENERE.
/// </summary>
/// <param name="input">the input to encrypt</param>
/// <param name="enc_key">the key to encrypt with</param>
/// <returns>the encrypted input</returns>
private static string wasEncryptVIGENERE(string input, string enc_key)
{
char[] a =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
 
enc_key = wasVigenereExpandKey(input, enc_key);
string result = string.Empty;
int i = 0;
do
{
char p = input[i];
if (!char.IsLetter(p))
{
result += p;
++i;
continue;
}
char q =
wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i]))[
Array.IndexOf(a, char.ToLowerInvariant(p))];
if (char.IsUpper(p))
{
q = char.ToUpperInvariant(q);
}
result += q;
++i;
} while (i < input.Length);
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Decrypt using VIGENERE.
/// </summary>
/// <param name="input">the input to decrypt</param>
/// <param name="enc_key">the key to decrypt with</param>
/// <returns>the decrypted input</returns>
private static string wasDecryptVIGENERE(string input, string enc_key)
{
char[] a =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
 
enc_key = wasVigenereExpandKey(input, enc_key);
string result = string.Empty;
int i = 0;
do
{
char p = input[i];
if (!char.IsLetter(p))
{
result += p;
++i;
continue;
}
char q =
a[
Array.IndexOf(wasReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i])),
char.ToLowerInvariant(p))];
if (char.IsUpper(p))
{
q = char.ToUpperInvariant(q);
}
result += q;
++i;
} while (i < input.Length);
return result;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// An implementation of the ATBASH cypher for latin alphabets.
/// </summary>
/// <param name="data">the data to encrypt or decrypt</param>
/// <returns>the encrypted or decrypted data</returns>
private static string wasATBASH(string data)
{
char[] a =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
 
char[] input = data.ToArray();
 
Parallel.ForEach(Enumerable.Range(0, data.Length), i =>
{
char e = input[i];
if (!char.IsLetter(e)) return;
int x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e));
if (!char.IsUpper(e))
{
input[i] = a[x];
return;
}
input[i] = char.ToUpperInvariant(a[x]);
});
 
return new string(input);
}
 
#endregion
}
}
}