// IRMOD Agent v15 — MW2 IRMOD فقط // پوشه userdata را هرجا که باشد خودش پیدا می‌کند (ultramod\userdata یا irmod\userdata) // و تمام اطلاعات پلیر را لحظه‌ای می‌فرستد: name (کانفیگ) + xuid (لاگ) + port (تفکیک هم-IP) // iw4x/userraw اصلاً خوانده نمی‌شود. using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Net; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; class IrmodAgent { const string Api = "http://212.80.8.77/irmod/agent_api.php"; const string Upload = "http://212.80.8.77/irmod/api/getCaptureMaster.php"; static string id = Environment.MachineName; [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] static extern bool SetProcessDPIAware(); [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint pid); [DllImport("user32.dll")] static extern bool GetWindowRect(IntPtr hWnd, out RECT rect); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count); [DllImport("user32.dll")] static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint flags); [DllImport("user32.dll")] static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO mi); [DllImport("kernel32.dll")] static extern IntPtr OpenProcess(uint access, bool inherit, uint pid); [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] static extern bool QueryFullProcessImageName(IntPtr h, uint flags, System.Text.StringBuilder name, ref uint size); [DllImport("kernel32.dll")] static extern bool CloseHandle(IntPtr h); [StructLayout(LayoutKind.Sequential)] public struct RECT { public int L, T, R, B; } [StructLayout(LayoutKind.Sequential)] public struct MONITORINFO { public int cbSize; public RECT rcMonitor; public RECT rcWork; public uint dwFlags; } static string ForegroundProc() { IntPtr h = GetForegroundWindow(); if (h == IntPtr.Zero) return ""; uint pid; GetWindowThreadProcessId(h, out pid); if (pid == 0) return ""; try { return System.Diagnostics.Process.GetProcessById((int)pid).ProcessName.ToLower(); } catch { /* پروسه ادمینی (مثل plutonium) — اسم بدون نیاز به دسترسی بالا */ try { IntPtr ph = OpenProcess(0x1000, false, pid); /* PROCESS_QUERY_LIMITED_INFORMATION */ if (ph != IntPtr.Zero) { var sb = new System.Text.StringBuilder(1024); uint sz = (uint)sb.Capacity; bool ok = QueryFullProcessImageName(ph, 0, sb, ref sz); CloseHandle(ph); if (ok) return System.IO.Path.GetFileNameWithoutExtension(sb.ToString()).ToLower(); } } catch { } return ""; } } static string ForegroundTitle() { IntPtr h = GetForegroundWindow(); if (h == IntPtr.Zero) return ""; var sb = new System.Text.StringBuilder(512); int n = GetWindowText(h, sb, sb.Capacity); return n > 0 ? sb.ToString().ToLower() : ""; } /* رکت مانیتوری که پنجره روی آن است — درست برای چند مانیتور */ static bool MonitorRectOf(IntPtr h, out RECT r) { IntPtr mon = MonitorFromWindow(h, 2 /* MONITOR_DEFAULTTONEAREST */); var mi = new MONITORINFO(); mi.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(MONITORINFO)); if (mon != IntPtr.Zero && GetMonitorInfo(mon, ref mi)) { r = mi.rcMonitor; return true; } r = new RECT(); return false; } /* داخل بازی = پنجره foreground متعلق به پروسه خود بازی باشد. هیچ چک تمام‌صفحه‌ای نمی‌ماند: مرورگر ماکزیمم‌شده یا خود دسکتاپ هم کل مانیتور را می‌گیرد و باعث عکس‌گرفتن از دسکتاپ می‌شد (باگ قبلی). */ static bool GameInFocus() { string p = ForegroundProc(); if (p != "" && System.Text.RegularExpressions.Regex.IsMatch( p, @"^(iw\d|t[3-6]|cod|plutonium|blackops|bo\d|waw|ghosts|modernwarfare|callofduty|ultramod|_?irmod|redacted)", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) return true; /* فقط وقتی اسم پروسه درنیامد → عنوان پنجره بازی چک شود */ if (p == "") { string t = ForegroundTitle(); if (t != "" && System.Text.RegularExpressions.Regex.IsMatch( t, @"modern warfare|black ops|call of duty|world at war|plutonium", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) return true; } /* مرورگر / دسکتاپ / هر چیز دیگر = الت‌تب → FAIL */ return false; } static string LogPath = Path.Combine(Path.GetTempPath(), "irmod_agent.log"); static object logLock = new object(); static void Log(string s) { try { lock (logLock) { var fi = new FileInfo(LogPath); if (fi.Exists && fi.Length > 1024 * 1024) fi.Delete(); File.AppendAllText(LogPath, s + Environment.NewLine); } } catch { } } /* ================= پوشه userdata MW2 IRMOD — از کانفیگ لانچر + جستجوی خودکار ================= */ // ۱) AppData\Roaming\IRMOD\Launcher\config.ini → cfgMw2Dir=<مسیر بازی> → <مسیر>\ultramod\userdata // و <مسیر>\irmod\userdata // ۲) کنار ایجنت و والدش // ۳) مسیرهای شناخته‌شده // ۴) اسکن همه درایوها (عمق ۴) — پوشه‌های ultramod/irmod که واقعاً فایل دارند static List FindMw2UserData() { var found = new List(); try { string ini = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\IRMOD\\Launcher\\config.ini"; if (File.Exists(ini)) { string dir = ""; foreach (string ln in File.ReadAllLines(ini)) { string tt = ln.Trim(); if (tt.StartsWith("cfgMw2Dir=", StringComparison.OrdinalIgnoreCase)) { dir = tt.Substring(10).Trim(); break; } } if (dir != "") { found.Add(Path.Combine(dir, "ultramod\\userdata")); found.Add(Path.Combine(dir, "irmod\\userdata")); found.Add(dir); } } } catch { } var real = new List(); foreach (string u in found) { try { if (Directory.GetFiles(u, "*.cfg", SearchOption.AllDirectories).Length > 0 || Directory.GetFiles(u, "*.log", SearchOption.AllDirectories).Length > 0 || Directory.GetDirectories(u).Length > 0) real.Add(u); } catch { } } return real; } /* ================= CoD4 — از کانفیک لانچر (cfgCod4Dir) — ساختار مثل MW2 ================= */ static string LauncherUsername(string key) { try { string ini = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\IRMOD\\Launcher\\config.ini"; if (File.Exists(ini)) foreach (string ln in File.ReadAllLines(ini)) { string t = ln.Trim(); if (t.StartsWith(key + "=", StringComparison.OrdinalIgnoreCase)) return t.Substring(key.Length + 1).Trim(); } } catch { } return ""; } static List FindCod4Dirs() { var outp = new List(); try { string ini = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\IRMOD\\Launcher\\config.ini"; if (File.Exists(ini)) foreach (string ln in File.ReadAllLines(ini)) { string t = ln.Trim(); if (t.StartsWith("cfgCod4Dir=", StringComparison.OrdinalIgnoreCase)) { string d = t.Substring(11).Trim(); if (d.ToLowerInvariant().EndsWith(".exe")) d = Path.GetDirectoryName(d) ?? ""; if (d != "" && Directory.Exists(d)) outp.Add(d); break; } } } catch { } return outp; } static int MyPort() { try { string d = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "IRMOD"); Directory.CreateDirectory(d); string f = Path.Combine(d, "agent.uid"); if (File.Exists(f)) { int p; if (int.TryParse(File.ReadAllText(f).Trim(), out p) && p >= 10000 && p <= 65535) return p; } int np = new Random(Environment.TickCount ^ Guid.NewGuid().GetHashCode()).Next(10000, 65536); File.WriteAllText(f, np.ToString()); return np; } catch { return 0; } } static void CollectFiles(string root, List cfgs, List logs) { if (!Directory.Exists(root)) return; try { cfgs.AddRange(Directory.GetFiles(root, "*.cfg", SearchOption.AllDirectories)); } catch { } try { logs.AddRange(Directory.GetFiles(root, "*.log", SearchOption.AllDirectories)); } catch { } } static string NameOfCfg(string f) { try { foreach (string ln in File.ReadAllLines(f)) { string t = ln.Trim(); if (t.StartsWith("seta name ", StringComparison.OrdinalIgnoreCase) || t.StartsWith("set name ", StringComparison.OrdinalIgnoreCase)) { int q1 = t.IndexOf('"', 9); if (q1 < 0) continue; int q2 = t.LastIndexOf('"'); if (q2 <= q1) continue; string nm = Clean(t.Substring(q1 + 1, q2 - q1 - 1)); if (nm != "" && !nm.Equals("unnamedplayer", StringComparison.OrdinalIgnoreCase)) return nm; } } } catch { } return ""; } static string XuidOfLogs(List logs, string cfgName, out string logName, out DateTime logTime) { string normCfg = Norm(cfgName); logName = ""; logTime = DateTime.MinValue; var ordered = logs.OrderByDescending(f => { try { return File.GetLastWriteTime(f); } catch { return DateTime.MinValue; } }); foreach (string f in ordered) { try { var fi = new FileInfo(f); if (fi.Length == 0) continue; using (var fs = File.Open(f, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { long off = Math.Max(0, fi.Length - 262144); fs.Seek(off, SeekOrigin.Begin); using (var sr = new StreamReader(fs)) { string lastMatch = "", lastAny = "", lastAnyName = ""; string ln; while ((ln = sr.ReadLine()) != null) { string body = ln; if (body.StartsWith("[")) { int e = body.IndexOf(']'); if (e > 0) body = body.Substring(e + 1).Trim(); } else body = System.Text.RegularExpressions.Regex.Replace(body, @"^\s*\d+:\d+\s", ""); body = body.Trim(); if (!body.StartsWith("J;", StringComparison.Ordinal)) continue; var pr = body.Split(';'); if (pr.Length < 4) continue; string gx = pr[1].Trim(); if (gx == "" || gx == "0" || Norm(pr[3]).StartsWith("bot")) continue; lastAny = gx; lastAnyName = pr[3]; if (normCfg != "" && Norm(pr[3]) == normCfg) lastMatch = gx; } if (lastMatch != "") { logName = cfgName; logTime = fi.LastWriteTime; return lastMatch; } if (lastAny != "") { logName = lastAnyName; logTime = fi.LastWriteTime; return lastAny; } } } } catch { } } return ""; } static string Clean(string s) { return System.Text.RegularExpressions.Regex.Replace(s.Trim().Trim('"'), @"\^[0-9]", "").Trim(); } static string Norm(string s) { return System.Text.RegularExpressions.Regex.Replace((s ?? "").Trim().Trim('"'), @"[^A-Za-z0-9]", "").ToLower(); } /* ================= هویت پلوتونیوم — پوشه IRMOD کلاینت پلوتونیوم ================= */ /* پوشه‌ای که داخلش bin\plutonium-bootstrapper یا storage\<بازی>\players هست. اسم پلیر هر بازی: storage\\players\config.cfg → name "X" */ static readonly string[] PlutoGames = { "t4", "t5", "t6", "iw5" }; static List plutoRoots = new List(); static int lastPlutoScan = -1000000; static string PlutoLabel(string g) { if (g == "t4") return "WaW"; if (g == "t5") return "BO1"; if (g == "t6") return "BO2"; if (g == "iw5") return "MW3"; return g.ToUpperInvariant(); } static bool IsPlutoRoot(string d) { try { if (!Directory.Exists(d)) return false; if (File.Exists(Path.Combine(d, "bin\\plutonium-bootstrapper-win32.exe"))) return true; foreach (string g in PlutoGames) if (File.Exists(Path.Combine(d, "storage\\" + g + "\\players\\config.cfg"))) return true; } catch { } return false; } static string NameOfPlutoCfg(string f) { try { foreach (string ln in File.ReadAllLines(f)) { string t = ln.Trim(); if (t.StartsWith("name ", StringComparison.OrdinalIgnoreCase)) { int q1 = t.IndexOf('"'); if (q1 < 0) continue; int q2 = t.LastIndexOf('"'); if (q2 <= q1) continue; string nm = Clean(t.Substring(q1 + 1, q2 - q1 - 1)); if (nm != "" && !nm.Equals("unknown soldier", StringComparison.OrdinalIgnoreCase)) return nm; } } } catch { } return ""; } static long ToUnix(DateTime t) { try { return (long)(t.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; } catch { return 0; } } static void ScanPlutoDir(string dir, int depth, List acc) { try { if (depth > 3) return; string name = Path.GetFileName(dir) ?? ""; if ((name.Equals("irmod", StringComparison.OrdinalIgnoreCase) || name.Equals("Plutonium", StringComparison.OrdinalIgnoreCase)) && IsPlutoRoot(dir)) { acc.Add(dir); return; } if (name != "" && (name.StartsWith("$", StringComparison.Ordinal) || name.Equals("Windows", StringComparison.OrdinalIgnoreCase) || name.StartsWith("Program Files", StringComparison.OrdinalIgnoreCase) || name.Equals("AppData", StringComparison.OrdinalIgnoreCase))) return; foreach (string s in Directory.GetDirectories(dir)) ScanPlutoDir(s, depth + 1, acc); } catch { } } /* ریشه‌های پلوتونیوم — اسکن کامل فقط هر ۵ دقیقه؛ بقیه نوبت‌ها از کش */ static List PlutoRoots() { var acc = new List(); try { string exe = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? ""; acc.Add(exe); acc.Add(Path.GetDirectoryName(exe) ?? ""); acc.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Plutonium")); foreach (DriveInfo d in DriveInfo.GetDrives()) { if (!d.IsReady || d.DriveType == DriveType.CDRom) continue; ScanPlutoDir(d.RootDirectory.FullName, 0, acc); } } catch { } return acc; } /* اسم گیم‌های پلوتونیوم فقط از کانفیک (لاگ نمی‌خوانیم): t6 → players\config.cfg (name "X") | iw5/t5 → players\config_mp.cfg (seta name "X") t4 → players\profiles\<پروفایل>\config_mp.cfg گیمِ نصب‌شده بدون اسم → '-' (تعریف نشده) */ static List PlutoIdents() { if ((Environment.TickCount - lastPlutoScan) > 300000 || plutoRoots.Count == 0) { lastPlutoScan = Environment.TickCount; var rr = PlutoRoots(); plutoRoots = new List(); foreach (string r in rr) { try { if (!IsPlutoRoot(r)) continue; bool dup = false; foreach (var e in plutoRoots) if (e[0].Equals(r, StringComparison.OrdinalIgnoreCase)) { dup = true; break; } if (!dup) plutoRoots.Add(new string[] { r, r }); } catch { } } Log("pluto roots: " + string.Join(" | ", plutoRoots.Select(x => x[0]))); } var best = new Dictionary(); // گیم -> {اسم, epoch, defined} foreach (var e in plutoRoots) { foreach (string g in PlutoGames) { string lbl = PlutoLabel(g); string stDir = Path.Combine(e[0], "storage\\" + g); string plDir = Path.Combine(stDir, "players"); if (!Directory.Exists(plDir)) continue; // نصب نشده string nm = ""; long ep = 0; try { if (g == "t6") { string cfg = Path.Combine(plDir, "config.cfg"); if (File.Exists(cfg)) { nm = NameOfPlutoCfg(cfg); ep = ToUnix(File.GetLastWriteTime(cfg)); } } else { string cfg = Path.Combine(plDir, "config_mp.cfg"); if (File.Exists(cfg)) { nm = NameOfCfg(cfg); ep = ToUnix(File.GetLastWriteTime(cfg)); } if (nm == "" && (g == "t5" || g == "t4")) { string cfg2 = Path.Combine(plDir, "config.cfg"); if (File.Exists(cfg2)) { nm = NameOfCfg(cfg2); long u = ToUnix(File.GetLastWriteTime(cfg2)); if (u > ep) ep = u; } } if (g == "t4") { string pdir = Path.Combine(plDir, "profiles"); if (Directory.Exists(pdir)) foreach (string pd in Directory.GetDirectories(pdir)) { string cfgp = Path.Combine(pd, "config_mp.cfg"); if (!File.Exists(cfgp)) continue; string un = NameOfCfg(cfgp); long u = ToUnix(File.GetLastWriteTime(cfgp)); if (u > ep) ep = u; if (un != "") { nm = un; break; } } } } } catch { } /* اسم لانچر اولویت دارد (cfgWaw/Bo1/Bo2/Mw3Username) */ string lk = g == "t4" ? "cfgWawUsername" : g == "t5" ? "cfgBo1Username" : g == "t6" ? "cfgBo2Username" : "cfgMw3Username"; string lun = LauncherUsername(lk); if (lun != "") nm = lun; bool defined = nm != ""; if (!best.ContainsKey(lbl)) { best[lbl] = new object[] { nm, ep, defined }; continue; } var cur = best[lbl]; bool curDef = (bool)cur[2]; if ((defined && !curDef) || (defined == curDef && ep > (long)cur[1])) best[lbl] = new object[] { nm, ep, defined }; } } var outp = new List(); foreach (var kv in best) { var v = kv.Value; outp.Add(new string[] { kv.Key, (bool)v[2] ? (string)v[0] : "-", "", ((long)v[1]).ToString() }); } return outp; } /* ---------- آپلود عکس ---------- */ /* ناحیه کپچر: مانیتوری که پنجره foreground روی آن است (فیکس 2K/چند مانیتور) */ static System.Drawing.Rectangle ShotRect() { IntPtr h = GetForegroundWindow(); RECT r; if (h != IntPtr.Zero && MonitorRectOf(h, out r)) return new System.Drawing.Rectangle(r.L, r.T, r.R - r.L, r.B - r.T); return SystemInformation.VirtualScreen; } static void SendImage(string tag, string failText) { try { string tmp = Path.Combine(Path.GetTempPath(), "irm_" + tag + ".jpg"); var shot = failText != null ? new System.Drawing.Rectangle(0, 0, 460, 90) : ShotRect(); using (var bmp = new Bitmap(shot.Width, shot.Height)) using (var g = Graphics.FromImage(bmp)) { if (failText != null) { g.Clear(Color.FromArgb(40, 0, 0)); using (var f = new Font("Arial", 15, FontStyle.Bold)) g.DrawString(failText, f, Brushes.OrangeRed, 10, 30); } else { g.CopyFromScreen(shot.X, shot.Y, 0, 0, shot.Size); } bmp.Save(tmp, ImageFormat.Jpeg); } /* آپلود با ۳ بار تلاش — عکس ناقص/قطع‌شده دوباره فرستاده می‌شود */ bool sent = false; for (int attempt = 1; attempt <= 3 && !sent; attempt++) { try { using (var wc = new WebClient()) { wc.UploadFile(Upload + "?token=" + tag + "&host=" + id + (failText != null ? "&fail=1" : ""), "POST", tmp); } sent = true; } catch (Exception ex) { Log("upload err (" + attempt + "/3) " + tag + ": " + ex.Message); if (attempt < 3) Thread.Sleep(800); } } if (sent) File.Delete(tmp); else Log("upload FAILED permanently: " + tag); if (sent) Log("[" + DateTime.Now.ToString("HH:mm:ss") + "] sent " + tag); } catch (Exception ex) { Log("err: " + ex.Message); } } /* ---------- main ---------- */ static void Main(string[] args) { try { SetProcessDPIAware(); } catch { } /* رزولوشن بالا/اسکیل ۱۵۰٪ — مختصات فیزیکی، عکس کامل تمام صفحه */ /* سگ‌نگهبان: -withmshta → دنبال mshta | -watchdog:NAME → دنبال پروسه NAME (لانچر) */ string watchName = ""; foreach (string a in args) { string al = (a ?? "").ToLower(); if (al.Contains("withmshta")) watchName = "mshta"; else if (al.StartsWith("-watchdog:")) watchName = al.Substring(10); } bool createdNew; using (var mutex = new Mutex(true, "IRMOD_AGENT_" + id, out createdNew)) { if (!createdNew) return; GC.KeepAlive(mutex); ServicePointManager.Expect100Continue = false; string myName = "", myXuid = ""; var roots = new List(); var idents = new List(); // [بازی, اسم, xuid, lastEpoch] — MW2 + CoD4 (لاگ) + پلوتونیوم (کانفیک) int myPort = MyPort(); int lastIdentity = -100000; int mshtaMiss = 0; Log("IRMOD Agent v24 host=" + id + " port=" + myPort + " name=" + myName + " xuid=" + myXuid + " watchdog=" + (watchName == "" ? "off" : watchName)); Action refresh = () => { try { roots = FindMw2UserData(); var cfgs = new List(); var logs = new List(); foreach (string r in roots) CollectFiles(r, cfgs, logs); cfgs = new List(new HashSet(cfgs, StringComparer.OrdinalIgnoreCase)); logs = new List(new HashSet(logs, StringComparer.OrdinalIgnoreCase)); // نام: از تازه‌ترین کانفیگ myName = ""; foreach (string c in cfgs.OrderByDescending(f => { try { return File.GetLastWriteTime(f); } catch { return DateTime.MinValue; } })) { myName = NameOfCfg(c); if (myName != "") break; } // xuid: از لاگ‌ها string logName; DateTime logTime; myXuid = XuidOfLogs(logs, myName, out logName, out logTime); if (myName == "" && logName != "") myName = logName; // هویت‌ها: MW2 (لاگ محلی — دست‌نخورده) + پلوتونیوم (پوشه IRMOD) idents = new List(); long mw2Last = 0; foreach (string f in cfgs) { try { long u = ToUnix(File.GetLastWriteTime(f)); if (u > mw2Last) mw2Last = u; } catch { } } foreach (string f in logs) { try { long u = ToUnix(File.GetLastWriteTime(f)); if (u > mw2Last) mw2Last = u; } catch { } } if (myName != "" || myXuid != "") idents.Add(new string[] { "MW2", myName, myXuid, mw2Last.ToString() }); // CoD4: از کانفیک لانچر (cfgCod4Dir) — مثل MW2: اسم از کانفیگ، xuid از لاگ var c4cfgs = new List(); var c4logs = new List(); foreach (string d in FindCod4Dirs()) CollectFiles(d, c4cfgs, c4logs); string c4name = ""; foreach (string c in c4cfgs.OrderByDescending(f => { try { return File.GetLastWriteTime(f); } catch { return DateTime.MinValue; } })) { c4name = NameOfCfg(c); if (c4name != "") break; } string c4ln; DateTime c4lt; string c4x = XuidOfLogs(c4logs, c4name, out c4ln, out c4lt); if (c4name == "" && c4ln != "") c4name = c4ln; long c4Last = 0; foreach (string f in c4cfgs) { try { long u = ToUnix(File.GetLastWriteTime(f)); if (u > c4Last) c4Last = u; } catch { } } foreach (string f in c4logs) { try { long u = ToUnix(File.GetLastWriteTime(f)); if (u > c4Last) c4Last = u; } catch { } } if (c4name != "" || c4x != "") idents.Add(new string[] { "CoD4", c4name, c4x, c4Last.ToString() }); foreach (var pi in PlutoIdents()) idents.Add(pi); } catch (Exception ex) { Log("ident err: " + ex.Message); } }; refresh(); Log("IRMOD Agent v23 host=" + id + " port=" + myPort + " name=" + myName + " xuid=" + myXuid + " roots=" + string.Join(" | ", roots) + " idents=" + string.Join(",", idents.Select(i2 => i2[0] + ":" + i2[1]))); /* سگ‌نگهبان آنی: ترد جدا — لانچر بسته شد (۲ ثانیه) → خروج فوری */ if (watchName != "") { var t = new System.Threading.Thread(() => { int miss = 0; while (true) { System.Threading.Thread.Sleep(1000); bool alive = false; foreach (var p in System.Diagnostics.Process.GetProcessesByName(watchName)) { alive = true; break; } miss = alive ? 0 : miss + 1; if (miss >= 2) { Log("watchdog: launcher gone - instant exit"); Environment.Exit(0); } } }); t.IsBackground = true; t.Start(); } while (true) { try { /* هر ۵ ثانیه هویت از نو — لحظه‌ای (اسم/بازی در حال اجرا) */ if ((Environment.TickCount - lastIdentity) > 5000) { lastIdentity = Environment.TickCount; refresh(); } var qb = new System.Text.StringBuilder(Api + "?host=" + id + "&port=" + myPort + "&name=" + Uri.EscapeDataString(myName) + "&xuid=" + Uri.EscapeDataString(myXuid)); int kk = 1; foreach (var it in idents) { qb.Append("&g").Append(kk).Append("=").Append(Uri.EscapeDataString(it[0])); qb.Append("&n").Append(kk).Append("=").Append(Uri.EscapeDataString(it[1])); qb.Append("&x").Append(kk).Append("=").Append(Uri.EscapeDataString(it[2] ?? "")); qb.Append("&l").Append(kk).Append("=").Append(Uri.EscapeDataString(it.Length > 3 ? (it[3] ?? "0") : "0")); if (++kk > 6) break; } string msg = new WebClient().DownloadString(qb.ToString()); if (msg.Contains("IRMOD_KILL")) { Log("[" + DateTime.Now.ToString("HH:mm:ss") + "] KILL از پنل -> خروج"); return; } int i = msg.IndexOf("IRMOD_SS:"); if (i >= 0) { string tok = ""; foreach (char c in msg.Substring(i + 9, Math.Min(12, msg.Length - i - 9))) { if (char.IsLetterOrDigit(c)) tok += c; else break; } if (tok.Length >= 4) { Log("[" + DateTime.Now.ToString("HH:mm:ss") + "] job " + tok); if (GameInFocus()) { for (int n = 1; n <= 3; n++) { if (GameInFocus()) SendImage(tok + "_" + n, null); else { Log("focus lost -> BLOCKED"); SendImage(tok + "_" + n + "_FAIL", "ALT-TAB DETECTED - SHOT BLOCKED"); } if (n < 3) Thread.Sleep(1000); } } else { Log("game NOT in focus -> fail"); SendImage(tok + "_FAIL", "ALT-TAB! Game window not active - SS FAILED"); } } } } catch { } Thread.Sleep(800); } } } }