using System.Text.RegularExpressions; public static string Folder(string dir, string name) { return Path.Combine(Path.Combine(dir, "accounts"), Profile.Key(name)); } public static string Ini(string dir, string name) { return Path.Combine(Folder(dir, name), "IdleMafiaBot.ini"); } public static string Jobs(string dir, string name) { return Path.Combine(Folder(dir, name), "jobs.txt"); } public static string Fights(string dir, string name) { return Path.Combine(Folder(dir, name), "fight memory.txt"); } public static bool Plausible(string name) { return name != null && Regex.IsMatch(name.Trim(), @"^[A-Za-z0-9_]{3,20}$"); } public static bool Same(string a, string b) string x = Parse.Key(a ?? ""), y = Parse.Key(b ?? ""); if (x.Length == 0 || y.Length == 0) return false; if (Math.Min(x.Length, y.Length) < 8 || View.Distance(x, y) > 1) return false; if (x.Length != y.Length) return !(x.StartsWith(y) || y.StartsWith(x)); string p = Plain(a), q = Plain(b); while (i < x.Length && x[i] == y[i]) i++; if (p.Length == x.Length && q.Length == y.Length) return !char.IsDigit(p[i]) && !char.IsDigit(q[i]); return !char.IsDigit(x[i]) && !char.IsDigit(y[i]); public static string Tidy(string name) { return name == null ? null : name.Trim().Replace('-', '_'); } public static bool Alike(string a, string b) a = Tidy(a); b = Tidy(b); if (a == null || b == null || a.Length != b.Length) return false; for (int i = 0; i < a.Length; i++) if (a[i] != b[i] && !("Il".IndexOf(a[i]) >= 0 && "Il".IndexOf(b[i]) >= 0)) return false; public static bool Part(string whole, string part) if (whole == null || part == null || part.Trim().Length < 3 || !whole.Contains("_")) return false; string p = Profile.Key(part.Trim()); return !string.Equals(Profile.Key(whole.Trim()), p, StringComparison.OrdinalIgnoreCase) && Array.Exists(whole.Trim().Split('_'), w => w.Length > 0 && string.Equals(Profile.Key(w), p, StringComparison.OrdinalIgnoreCase)); public static string Known(string dir, string name) if (name == null || dir == null) return name; string root = Path.Combine(dir, "accounts"); if (n.Length < 3 || !Directory.Exists(root)) return n; if (Directory.Exists(Folder(dir, n))) return OneOfTwins(root, n); string cut = n.Length > 3 && "0Oo".IndexOf(n[n.Length - 1]) >= 0 ? Parse.Key(n.Substring(0, n.Length - 1)) : null; string whole = Parse.Key(n), badged = null; foreach (var d in Directory.GetDirectories(root)) string a = Path.GetFileName(d); if (!Plausible(a)) continue; if (Parse.Key(a) == whole) return a; if (cut != null && Parse.Key(a) == cut) badged = a; catch (Exception) { return n; } static string OneOfTwins(string root, string n) var bestAt = DateTime.MinValue; foreach (var d in Directory.GetDirectories(root)) string a = Path.GetFileName(d); if (!Plausible(a) || !Alike(a, n)) continue; string ini = Path.Combine(d, "IdleMafiaBot.ini"); var at = File.Exists(ini) ? File.GetLastWriteTimeUtc(ini) : DateTime.MinValue; if (at > bestAt || (at == bestAt && a == n)) { best = a; bestAt = at; } static readonly string[] LevelPicks = { "PropertySeen", "JobMode", "OneJob", "OperationOnly", "PropertyOnly" }; public static Settings NewFrom(Settings from) foreach (var f in Preset.Fields()) if (Array.IndexOf(LevelPicks, f.Name) < 0) f.SetValue(s, f.GetValue(from)); if (from.JobMode != JobMode.OneJob) s.JobMode = from.JobMode; s.GroupsOff = from.GroupsOff; static string Plain(string s) var sb = new System.Text.StringBuilder(); foreach (char ch in (s ?? "").ToUpperInvariant()) if (char.IsLetterOrDigit(ch)) sb.Append(ch); public static void ForgetLink(string dir, string playing) string root = Path.Combine(dir, "accounts"); if (!Directory.Exists(root)) return; foreach (var ini in Directory.GetFiles(root, "IdleMafiaBot.ini", SearchOption.AllDirectories)) if (!string.IsNullOrEmpty(playing) && string.Equals(ini, Ini(dir, playing), StringComparison.OrdinalIgnoreCase)) continue; var o = Settings.Load(ini); if (o.Unreadable == null && (o.DiscordLink ?? "").Trim().Length > 0) o.Save(ini, true); public static string OwnerHint(string dir) var files = Directory.GetFiles(dir, "profile-*.txt"); if (files.Length != 1) return null; var p = Profile.Load(files[0]); return p != null && Plausible(p.Name) ? p.Name.Trim() : null; catch (Exception) { return null; }