AFK Macro

Idle Mafia Macro/Source/src/Native.cs

Native.cs

Windows calls: the Roblox window, its picture, the mouse · 744 lines · 32 KB

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
namespace IdleMafiaBot
{
static class Native
{
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
[StructLayout(LayoutKind.Sequential)] public struct POINT { public int X, Y; }
[StructLayout(LayoutKind.Sequential)] public struct LASTINPUTINFO { public uint cbSize; public uint dwTime; }
[DllImport("user32.dll")] public static extern bool SetProcessDpiAwarenessContext(IntPtr ctx);
[DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int value);
[DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
[DllImport("user32.dll")] public static extern bool IsProcessDPIAware();
[DllImport("user32.dll")] static extern IntPtr SetThreadDpiAwarenessContext(IntPtr ctx);
public static IntPtr RealPixels()
{
try { return SetThreadDpiAwarenessContext(new IntPtr(-4)); }
catch (Exception) { return IntPtr.Zero; }
}
public static void RestorePixels(IntPtr before)
{
if (before == IntPtr.Zero) return;
try { SetThreadDpiAwarenessContext(before); }
catch (Exception) { }
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] static extern uint GetLongPathName(string path, System.Text.StringBuilder longPath, uint size);
[DllImport("user32.dll")] public static extern bool GetClientRect(IntPtr h, out RECT r);
[DllImport("user32.dll")] public static extern bool ClientToScreen(IntPtr h, ref POINT p);
[DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr h, IntPtr hdc, uint flags);
[DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h);
[DllImport("user32.dll")] public static extern bool IsWindow(IntPtr h);
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr h, int cmd);
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
[DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr h);
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, IntPtr pid);
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
[DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId();
[DllImport("user32.dll")] public static extern bool AttachThreadInput(uint a, uint b, bool attach);
[DllImport("user32.dll")] public static extern void keybd_event(byte vk, byte scan, uint flags, UIntPtr extra);
[DllImport("user32.dll")] public static extern uint MapVirtualKey(uint code, uint type);
[DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")] public static extern bool ClipCursor(IntPtr rect);
[DllImport("user32.dll")] public static extern IntPtr MonitorFromPoint(POINT pt, uint flags);
[DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT p);
[DllImport("user32.dll")] public static extern void mouse_event(uint flags, int dx, int dy, int data, UIntPtr extra);
[DllImport("user32.dll")] public static extern bool GetLastInputInfo(ref LASTINPUTINFO lii);
[DllImport("user32.dll")] public static extern IntPtr WindowFromPoint(POINT p);
[DllImport("user32.dll")] public static extern IntPtr GetAncestor(IntPtr h, uint flags);
[DllImport("user32.dll")] public static extern IntPtr GetWindow(IntPtr h, uint cmd);
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
[DllImport("user32.dll")] public static extern int GetWindowLong(IntPtr h, int index);
[DllImport("dwmapi.dll")] static extern int DwmGetWindowAttribute(IntPtr h, int attr, out int value, int size);
[DllImport("dwmapi.dll")] static extern int DwmGetWindowAttribute(IntPtr h, int attr, out RECT value, int size);
public static bool Cloaked(IntPtr h)
{
int c;
try { return DwmGetWindowAttribute(h, 14, out c, 4) == 0 && c != 0; }
catch (Exception) { return false; }
}
public static bool DrawnRect(IntPtr h, out RECT r)
{
try { if (DwmGetWindowAttribute(h, 9, out r, Marshal.SizeOf(typeof(RECT))) == 0) return true; }
catch (Exception) { }
return GetWindowRect(h, out r);
}
[DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowText(IntPtr h, System.Text.StringBuilder s, int max);
[DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetClassName(IntPtr h, System.Text.StringBuilder s, int max);
[DllImport("user32.dll")] public static extern bool RegisterHotKey(IntPtr h, int id, uint mods, uint vk);
[DllImport("user32.dll")] public static extern bool UnregisterHotKey(IntPtr h, int id);
public const uint MOUSE_MOVE = 0x0001, MOUSE_LDOWN = 0x0002, MOUSE_LUP = 0x0004, MOUSE_WHEEL = 0x0800;
public static uint LastInputTick()
{
var lii = new LASTINPUTINFO();
lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
GetLastInputInfo(ref lii);
return lii.dwTime;
}
public static uint Now { get { return unchecked((uint)Environment.TickCount); } }
public static string LongPath(string path)
{
string full = System.IO.Path.GetFullPath(path);
var sb = new System.Text.StringBuilder(1024);
uint n = GetLongPathName(full, sb, (uint)sb.Capacity);
return n > 0 && n < sb.Capacity ? sb.ToString() : full;
}
[StructLayout(LayoutKind.Sequential)]
struct MEMORYSTATUSEX
{
public uint Length, MemoryLoad;
public ulong TotalPhys, AvailPhys, TotalPageFile, AvailPageFile, TotalVirtual, AvailVirtual, AvailExtendedVirtual;
}
[DllImport("kernel32.dll")] static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX m);
public static bool PcMemory(out long total, out long free, out long more)
{
total = free = more = -1;
var m = new MEMORYSTATUSEX { Length = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX)) };
try { if (!GlobalMemoryStatusEx(ref m)) return false; }
catch (Exception) { return false; }
total = (long)m.TotalPhys;
free = (long)m.AvailPhys;
more = (long)m.AvailPageFile;
return true;
}
public static long BotMemory()
{
try { using (var p = Process.GetCurrentProcess()) return p.PrivateMemorySize64; }
catch (Exception) { return -1; }
}
public static string Size(long bytes)
{
var ci = System.Globalization.CultureInfo.InvariantCulture;
double gb = bytes / (1024.0 * 1024 * 1024);
if (gb < 1) return (bytes >> 20).ToString(ci) + " MB";
return gb.ToString(gb >= 10 ? "0" : "0.0", ci) + " GB";
}
public static string MemoryText()
{
long total, free, more, own = BotMemory();
string bot = own >= 0 ? "the bot uses " + Size(own) : "the bot's own memory isn't known";
if (!PcMemory(out total, out free, out more)) return bot + "; Windows doesn't say how much memory this PC has";
return bot + "; this PC has " + Size(free) + " of " + Size(total) + " free (" + Size(more) + " more can be handed out)";
}
}
sealed class OutOfMemoryPause : Exception { public OutOfMemoryPause(Exception e) : base("the PC ran out of memory", e) { } }
sealed class WindowChangedException : Exception { public WindowChangedException(string m) : base(m) { } }
sealed class UserBusyException : Exception { public UserBusyException() : base("you started using the PC") { RobloxWindow.NoteUser(); } }
sealed class RobloxWindow
{
public IntPtr Handle { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
static uint lastBotInput;
static uint userSeen;
IntPtr returnTo = IntPtr.Zero;
public IntPtr Pinned;
public bool NoFallback;
public static volatile IntPtr[] Taken = new IntPtr[0];
public static List<IntPtr> All()
{
var all = new List<IntPtr>();
foreach (var p in Process.GetProcessesByName("RobloxPlayerBeta").Concat(Process.GetProcessesByName("Windows10Universal")))
{
if (p.MainWindowHandle == IntPtr.Zero) continue;
if (p.ProcessName == "Windows10Universal" && p.MainWindowTitle != "Roblox") continue;
all.Add(p.MainWindowHandle);
}
return all;
}
public bool Find()
{
var pin = Pinned;
if (pin != IntPtr.Zero && Handle != pin && Native.IsWindow(pin)) Handle = pin;
if (Handle == IntPtr.Zero || !Native.IsWindow(Handle))
{
Handle = IntPtr.Zero;
if (NoFallback && pin != IntPtr.Zero) return false;
var taken = Taken;
foreach (var h in All())
{
if (Array.IndexOf(taken, h) >= 0) continue;
Handle = h;
break;
}
if (Handle == IntPtr.Zero) return false;
}
Native.RECT r;
Native.GetClientRect(Handle, out r);
Width = r.Right - r.Left;
Height = r.Bottom - r.Top;
return true;
}
public bool Minimized { get { return Handle != IntPtr.Zero && Native.IsIconic(Handle); } }
public Frame Capture()
{
if (Handle == IntPtr.Zero || !Native.IsWindow(Handle)) throw new WindowChangedException("Roblox was closed");
if (Native.IsIconic(Handle)) throw new WindowChangedException("Roblox was minimized");
if (ScreenFirst) return ScreenFirstCapture();
bool ok;
var f = Printed(out ok);
if (ok && !f.LooksEmpty()) return f;
var s = InSight() ? FromScreen() : null;
if (s != null && !s.LooksEmpty())
{
f.Dispose();
EmptyPictures++;
ScreenCopies++;
ScreenFirst = true;
return s;
}
if (s != null) { s.Dispose(); return f; }
f.Dispose();
Thread.Sleep(100);
f = Printed(out ok);
if (ok && !f.LooksEmpty()) return f;
EmptyPictures++;
return f;
}
public static volatile bool ScreenFirst;
public bool ScreenOnly;
public static int EmptyPictures, ScreenCopies, Asked;
public static int HalfDrawn;
static int emptyAt = Environment.TickCount - 60000;
internal static bool TestWhite = false;
int barDrawnAt = Environment.TickCount - 60000;
Frame ScreenFirstCapture()
{
Frame s;
if (InSight() && (s = FromScreen()) != null)
{
for (int again = 0; again < 4 && !s.TopBarDrawn() && unchecked(Environment.TickCount - barDrawnAt) < 20000; again++)
{
Thread.Sleep(250);
var next = InSight() ? FromScreen() : null;
if (next == null) break;
s.Dispose();
s = next;
HalfDrawn++;
}
if (s.TopBarDrawn()) barDrawnAt = Environment.TickCount;
return s;
}
if (ScreenOnly || unchecked(Environment.TickCount - emptyAt) < 60000) return White();
bool ok;
var f = Printed(out ok);
if (ok && !f.LooksEmpty()) return f;
EmptyPictures++;
emptyAt = Environment.TickCount;
return f;
}
Frame White()
{
var bmp = new Bitmap(Math.Max(1, Width), Math.Max(1, Height), PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(bmp)) g.Clear(Color.White);
return new Frame(bmp, true);
}
Frame Printed(out bool ok)
{
Interlocked.Increment(ref Asked);
var bmp = new Bitmap(Math.Max(1, Width), Math.Max(1, Height), PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(bmp))
{
IntPtr dc;
try { dc = g.GetHdc(); }
catch (ArgumentException) { ok = false; return new Frame(bmp, true); }
catch (System.Runtime.InteropServices.ExternalException) { ok = false; return new Frame(bmp, true); }
ok = Native.PrintWindow(Handle, dc, 3);
g.ReleaseHdc(dc);
if (TestWhite) g.Clear(Color.White);
}
return new Frame(bmp, true);
}
public static string OtherWindow() { return null; }
public bool InSight() { return InSight(false); }
bool InSight(bool strict)
{
if (Width < 50 || Height < 50) return false;
IntPtr root = Native.GetAncestor(Handle, 2);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 3; j++)
{
var p = new Native.POINT { X = Width * (2 * i + 1) / 8, Y = Height * (2 * j + 1) / 6 };
if (!Native.ClientToScreen(Handle, ref p)) return false;
IntPtr at = Native.WindowFromPoint(p);
if (at == IntPtr.Zero || Native.GetAncestor(at, 2) != root) return false;
}
return !Overlapped(root, strict);
}
bool Overlapped(IntPtr root, bool strict)
{
var p = new Native.POINT();
if (!Native.ClientToScreen(Handle, ref p)) return true;
int l = p.X, t = p.Y, r = p.X + Width, b = p.Y + Height;
int n = 0;
for (IntPtr w = Native.GetWindow(root, 3); w != IntPtr.Zero && n < 2000; w = Native.GetWindow(w, 3), n++)
{
if (!Native.IsWindowVisible(w) || Native.IsIconic(w) || Native.Cloaked(w)) continue;
int ex = Native.GetWindowLong(w, -20);
if (!strict && (ex & 0x80020) == 0x80020) continue;
Native.RECT o;
if (!Native.DrawnRect(w, out o) || o.Right <= o.Left || o.Bottom <= o.Top) continue;
if (o.Left < r && o.Right > l && o.Top < b && o.Bottom > t)
{
if (strict) NoteCover(w, (ex & 0x80020) == 0x80020);
return true;
}
}
return false;
}
public static volatile string CoveredBy;
uint coverPid;
string coverName;
void NoteCover(IntPtr w, bool overlay)
{
uint pid;
Native.GetWindowThreadProcessId(w, out pid);
if (coverName == null || pid != coverPid)
{
coverPid = pid;
try { using (var p = System.Diagnostics.Process.GetProcessById((int)pid)) coverName = p.ProcessName; }
catch (Exception) { coverName = "Another program"; }
}
CoveredBy = overlay ? coverName + "'s overlay" : coverName;
}
Frame FromScreen()
{
var p = new Native.POINT();
if (!Native.ClientToScreen(Handle, ref p)) return null;
Bitmap bmp = null;
try
{
bool clear = InSight(true);
bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
using (var g = Graphics.FromImage(bmp)) g.CopyFromScreen(p.X, p.Y, 0, 0, new Size(Width, Height));
if (!clear || !InSight(true)) bmp.Tag = Frame.NotSendable;
else CoveredBy = null;
return new Frame(bmp, true);
}
catch (Exception) { if (bmp != null) bmp.Dispose(); return null; }
}
public static void NoteUser() { userSeen = Native.Now; }
public bool UserActiveWithin(int ms)
{
if (userSeen != 0 && unchecked(Native.Now - userSeen) < (uint)ms) return true;
uint last = Native.LastInputTick();
bool ours = lastBotInput != 0 && unchecked((int)(last - lastBotInput)) <= 400;
return !ours && unchecked(Native.Now - last) < (uint)ms;
}
public bool UserInputSinceBot()
{
return unchecked((int)(Native.LastInputTick() - lastBotInput)) > 250;
}
public bool BeginAct()
{
lastBotInput = Native.Now;
IntPtr fg = Native.GetForegroundWindow();
if (Minimized) { Native.ShowWindow(Handle, 9); Thread.Sleep(600); Find(); }
if (fg == Handle) return true;
returnTo = fg;
bool ok = Activate(Handle);
lastBotInput = Native.Now;
if (!ok) return false;
Thread.Sleep(250);
return true;
}
public bool Front()
{
if (Handle == IntPtr.Zero || Minimized) return false;
if (IsForeground) return true;
lastBotInput = Native.Now;
returnTo = Native.GetForegroundWindow();
bool ok = Activate(Handle);
lastBotInput = Native.Now;
return ok;
}
public void EndAct(bool giveFocusBack, bool park = true)
{
bool userMoved = UserInputSinceBot();
if (park) Park();
if (giveFocusBack && IsForeground && returnTo != IntPtr.Zero && Native.IsWindow(returnTo) && Native.IsWindowVisible(returnTo))
{
Activate(returnTo);
if (!userMoved) lastBotInput = Native.Now;
}
returnTo = IntPtr.Zero;
}
public bool IsForeground { get { return Handle != IntPtr.Zero && Native.GetForegroundWindow() == Handle; } }
public const string PlaceId = "73897506680154";
public static void StartGame()
{
using (Process.Start(new ProcessStartInfo("roblox://experiences/start?placeId=" + PlaceId) { UseShellExecute = true })) { }
}
public void GiveFocusBack(IntPtr w)
{
if (w == IntPtr.Zero || w == Handle || !IsForeground || !Native.IsWindow(w) || !Native.IsWindowVisible(w)) return;
Activate(w);
lastBotInput = Native.Now;
}
static bool Activate(IntPtr h)
{
if (!Native.IsWindow(h) || Native.IsIconic(h)) return false;
IntPtr fg = Native.GetForegroundWindow();
if (fg == h) return true;
uint fgThread = Native.GetWindowThreadProcessId(fg, IntPtr.Zero);
uint me = Native.GetCurrentThreadId();
Native.AttachThreadInput(me, fgThread, true);
Native.BringWindowToTop(h);
Native.SetForegroundWindow(h);
Native.AttachThreadInput(me, fgThread, false);
if (Native.GetForegroundWindow() == h) return true;
Native.keybd_event(0x12, 0, 0, UIntPtr.Zero);
Native.SetForegroundWindow(h);
Native.keybd_event(0x12, 0, 2, UIntPtr.Zero);
Thread.Sleep(50);
return Native.GetForegroundWindow() == h;
}
Native.POINT ToScreen(int x, int y)
{
if (Handle == IntPtr.Zero || !Native.IsWindow(Handle)) throw new WindowChangedException("Roblox was closed");
if (Native.IsIconic(Handle)) throw new WindowChangedException("Roblox was minimized");
Native.RECT r;
if (!Native.GetClientRect(Handle, out r) || r.Right - r.Left != Width || r.Bottom - r.Top != Height)
throw new WindowChangedException("the Roblox window changed size");
var p = new Native.POINT { X = x, Y = y };
if (!Native.ClientToScreen(Handle, ref p)) throw new WindowChangedException("Roblox was closed");
return p;
}
void CheckSpot(Native.POINT p)
{
IntPtr at = Native.WindowFromPoint(p);
if (at != IntPtr.Zero && Native.GetAncestor(at, 2) == Native.GetAncestor(Handle, 2)) return;
var title = new System.Text.StringBuilder(80);
if (at != IntPtr.Zero)
{
Native.GetClassName(Native.GetAncestor(at, 2), title, title.Capacity);
string cls = title.ToString();
if (cls == "Shell_TrayWnd" || cls == "Shell_SecondaryTrayWnd")
throw new WindowChangedException("the bottom of the Roblox window is behind the taskbar - maximize Roblox or move it up");
title.Clear();
Native.GetWindowText(Native.GetAncestor(at, 2), title, title.Capacity);
}
throw new WindowChangedException("another window" + (title.Length > 0 ? " (\"" + title + "\")" : "") + " covers the game where it has to click");
}
void PutCursor(Native.POINT p)
{
Native.SetCursorPos(p.X, p.Y);
Native.POINT c;
if (Native.GetCursorPos(out c) && c.X == p.X && c.Y == p.Y) return;
string spot = p.X + "," + p.Y;
if (Native.MonitorFromPoint(p, 0) == IntPtr.Zero)
throw new WindowChangedException("part of the Roblox window is off the screen (" + spot + " lies past its edge) - maximize Roblox or press F11 in it");
for (int i = 0; i < 6; i++)
{
if (i == 3) Native.ClipCursor(IntPtr.Zero);
Thread.Sleep(250);
lastBotInput = Native.Now;
Native.SetCursorPos(p.X, p.Y);
if (Native.GetCursorPos(out c) && Math.Abs(c.X - p.X) <= 3 && Math.Abs(c.Y - p.Y) <= 3) return;
}
throw new WindowChangedException("the mouse didn't go to " + spot + " on the screen (it stayed at " + c.X + "," + c.Y + ")");
}
Native.POINT MoveTo(int x, int y)
{
var p = ToScreen(x, y);
if (!IsForeground)
{
bool ok = Activate(Handle);
lastBotInput = Native.Now;
if (!ok) throw new WindowChangedException("couldn't bring Roblox to the front");
Thread.Sleep(200);
}
CheckSpot(p);
PutCursor(p);
Thread.Sleep(25);
Native.mouse_event(Native.MOUSE_MOVE, 1, 0, 0, UIntPtr.Zero);
Thread.Sleep(25);
Native.mouse_event(Native.MOUSE_MOVE, -1, 0, 0, UIntPtr.Zero);
Thread.Sleep(45);
lastBotInput = Native.Now;
return p;
}
void StillOn(Native.POINT p)
{
Native.POINT c;
if (!Native.GetCursorPos(out c) || Math.Abs(c.X - p.X) > 3 || Math.Abs(c.Y - p.Y) > 3) throw new UserBusyException();
CheckSpot(p);
}
public void Click(int x, int y)
{
StillOn(MoveTo(x, y));
Native.mouse_event(Native.MOUSE_LDOWN, 0, 0, 0, UIntPtr.Zero);
Thread.Sleep(40);
Native.mouse_event(Native.MOUSE_LUP, 0, 0, 0, UIntPtr.Zero);
lastBotInput = Native.Now;
LastInput = DateTime.UtcNow;
Thread.Sleep(60);
Park();
}
public void SlowClick(int x, int y)
{
var p = MoveTo(x, y);
var from = ToScreen(Math.Min(Width - 1, x + Math.Max(40, Width / 30)), y);
CheckSpot(from);
Native.POINT at = from;
for (int i = 0; i <= 8; i++)
{
if (i > 0)
{
Native.POINT c;
if (!Native.GetCursorPos(out c) || Math.Abs(c.X - at.X) > 3 || Math.Abs(c.Y - at.Y) > 3) throw new UserBusyException();
}
at = new Native.POINT { X = from.X + (p.X - from.X) * i / 8, Y = p.Y };
Native.SetCursorPos(at.X, at.Y);
Native.mouse_event(Native.MOUSE_MOVE, 1, 0, 0, UIntPtr.Zero);
Thread.Sleep(10);
Native.mouse_event(Native.MOUSE_MOVE, -1, 0, 0, UIntPtr.Zero);
Thread.Sleep(20);
}
lastBotInput = Native.Now;
Thread.Sleep(150);
StillOn(p);
Native.mouse_event(Native.MOUSE_LDOWN, 0, 0, 0, UIntPtr.Zero);
Thread.Sleep(120);
Native.mouse_event(Native.MOUSE_LUP, 0, 0, 0, UIntPtr.Zero);
lastBotInput = Native.Now;
LastInput = DateTime.UtcNow;
Thread.Sleep(60);
Park();
}
public void TypeKeys(string keys)
{
foreach (char ch in keys ?? "")
{
if (!IsForeground) throw new WindowChangedException("another window took the keyboard");
if (UserInputSinceBot()) throw new UserBusyException();
byte vk = ch == (char)8 ? (byte)0x08 : ch == (char)13 ? (byte)0x0D : ch == ' ' ? (byte)0x20
: char.IsLetterOrDigit(ch) && ch < 128 ? (byte)char.ToUpperInvariant(ch) : (byte)0;
if (vk == 0) continue;
byte sc = (byte)Native.MapVirtualKey(vk, 0);
Native.keybd_event(vk, sc, 0, UIntPtr.Zero);
Thread.Sleep(30);
Native.keybd_event(vk, sc, 2, UIntPtr.Zero);
lastBotInput = Native.Now;
LastInput = DateTime.UtcNow;
Thread.Sleep(50);
}
}
public void PressKey(byte vk)
{
if (!IsForeground)
{
bool ok = Activate(Handle);
lastBotInput = Native.Now;
if (!ok) throw new WindowChangedException("couldn't bring Roblox to the front");
Thread.Sleep(200);
}
if (UserInputSinceBot()) throw new UserBusyException();
byte sc = (byte)Native.MapVirtualKey(vk, 0);
Native.keybd_event(vk, sc, 0, UIntPtr.Zero);
Thread.Sleep(30);
Native.keybd_event(vk, sc, 2, UIntPtr.Zero);
lastBotInput = Native.Now;
LastInput = DateTime.UtcNow;
Thread.Sleep(300);
}
public void Hover(int x, int y) { StillOn(MoveTo(x, y)); }
public void LeaveToPark()
{
if (Handle == IntPtr.Zero || !Native.IsWindow(Handle) || Native.IsIconic(Handle)) return;
Native.POINT from;
if (!Native.GetCursorPos(out from)) return;
var end = ToScreen(ParkAt.X, ParkAt.Y);
CheckSpot(end);
Native.POINT at = from;
for (int i = 1; i <= 10; i++)
{
Native.POINT c;
if (!Native.GetCursorPos(out c) || Math.Abs(c.X - at.X) > 3 || Math.Abs(c.Y - at.Y) > 3) throw new UserBusyException();
at = new Native.POINT { X = from.X + (end.X - from.X) * i / 10, Y = from.Y + (end.Y - from.Y) * i / 10 };
Native.SetCursorPos(at.X, at.Y);
Native.mouse_event(Native.MOUSE_MOVE, 1, 0, 0, UIntPtr.Zero);
Thread.Sleep(10);
Native.mouse_event(Native.MOUSE_MOVE, -1, 0, 0, UIntPtr.Zero);
lastBotInput = Native.Now;
Thread.Sleep(25);
}
lastBotInput = Native.Now;
}
public void SweepFromTop()
{
var top = ToScreen(Width / 2, 2);
if (!IsForeground)
{
bool ok = Activate(Handle);
lastBotInput = Native.Now;
if (!ok) throw new WindowChangedException("couldn't bring Roblox to the front");
Thread.Sleep(200);
}
if (!RobloxAt(top)) CheckSpot(top);
var end = ToScreen(ParkAt.X, ParkAt.Y);
CheckSpot(end);
Native.POINT at = top;
for (int i = 0; i <= 12; i++)
{
if (i > 0)
{
Native.POINT c;
if (!Native.GetCursorPos(out c) || Math.Abs(c.X - at.X) > 3 || Math.Abs(c.Y - at.Y) > 3) throw new UserBusyException();
at = new Native.POINT { X = top.X + (end.X - top.X) * i / 12, Y = top.Y + (end.Y - top.Y) * i / 12 };
}
Native.SetCursorPos(at.X, at.Y);
Native.mouse_event(Native.MOUSE_MOVE, 1, 0, 0, UIntPtr.Zero);
Thread.Sleep(15);
Native.mouse_event(Native.MOUSE_MOVE, -1, 0, 0, UIntPtr.Zero);
lastBotInput = Native.Now;
Thread.Sleep(i == 0 ? 600 : 30);
}
lastBotInput = Native.Now;
}
public string FrontWindow()
{
IntPtr fg = Native.GetForegroundWindow();
if (fg == IntPtr.Zero) return "none";
if (Handle != IntPtr.Zero && Native.GetAncestor(fg, 2) == Native.GetAncestor(Handle, 2)) return "Roblox";
uint pid;
Native.GetWindowThreadProcessId(fg, out pid);
string program = "?";
try { using (var p = System.Diagnostics.Process.GetProcessById((int)pid)) program = p.ProcessName; }
catch (Exception) { }
return program;
}
bool RobloxAt(Native.POINT p)
{
IntPtr at = Native.WindowFromPoint(p);
if (at == IntPtr.Zero) return false;
if (Native.GetAncestor(at, 2) == Native.GetAncestor(Handle, 2)) return true;
uint mine, theirs;
Native.GetWindowThreadProcessId(Handle, out mine);
Native.GetWindowThreadProcessId(at, out theirs);
return mine != 0 && mine == theirs;
}
public DateTime LastInput { get; private set; }
public void Scroll(int x, int y, int notches)
{
var p = MoveTo(x, y);
int step = notches > 0 ? 120 : -120;
for (int i = 0; i < Math.Abs(notches); i++)
{
StillOn(p);
Native.mouse_event(Native.MOUSE_WHEEL, 0, 0, step, UIntPtr.Zero);
lastBotInput = Native.Now;
LastInput = DateTime.UtcNow;
Thread.Sleep(12);
}
Thread.Sleep(350);
Park();
}
public Point ParkAt = new Point(600, 170);
public void Park()
{
if (Handle == IntPtr.Zero || !Native.IsWindow(Handle) || Native.IsIconic(Handle)) return;
if (UserInputSinceBot()) return;
var p = new Native.POINT { X = ParkAt.X, Y = ParkAt.Y };
if (!Native.ClientToScreen(Handle, ref p)) return;
Native.SetCursorPos(p.X, p.Y);
Native.mouse_event(Native.MOUSE_MOVE, 1, 0, 0, UIntPtr.Zero);
Thread.Sleep(10);
Native.mouse_event(Native.MOUSE_MOVE, -1, 0, 0, UIntPtr.Zero);
lastBotInput = Native.Now;
}
}
}