Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Исходник Rainbow Six Mobile — AI Aimbot Base (YOLOv8 + Screen Capture)

Sloppy
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
703
Реакции
20
Наткнулся на интересную базу для Rainbow Six Mobile. Автор забросил проект из-за слабого железа, но выкатил вполне рабочий скелет для создания AI-аимбота. Это не классическая паста на перехвате пакетов, а современный подход через захват экрана и нейронку.

Техническая начинка:
  1. Стек: Kotlin + Jetpack Compose.
  2. Детект: TensorFlow Lite + YOLOv8 (модель обучена под операторов R6M).
  3. Захват: MediaProjection API (стриминг экрана в буфер).
  4. Аим: Через Accessibility Service (имитация жестов, что позволяет обходить некоторые ограничения песочницы).
  5. Оптимизация: Инференс на GPU через GpuDelegate, ресайз инпута до 416x416 для стабильного FPS.

Код:
Expand Collapse Copy
Project Structure: 
app/plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}
 
android {
    namespace = "com.aim.r6m"
    compileSdk = 34
 
    defaultConfig {
        applicationId = "com.aim.r6m"
        minSdk = 28
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    }
 
    buildFeatures { compose = true }
    composeOptions { kotlinCompilerExtensionVersion = "1.5.8" }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions { jvmTarget = "17" }
    androidResources { noCompress += "tflite" }
}
 
dependencies {
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.activity:activity-compose:1.8.2")
    implementation(platform("androidx.compose:compose-bom:2024.02.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("org.tensorflow:tensorflow-lite:2.14.0")
    implementation("org.tensorflow:tensorflow-lite-support:0.4.4")
    implementation("org.tensorflow:tensorflow-lite-gpu:2.14.0")
}
├── build.gradle.kts
├── src/main/
│   ├── AndroidManifest.xml
│   ├── assets/r6m_operators.tflite
│   ├── res/xml/accessibility_config.xml
│   └── java/com/aim/r6m/
│       ├── MainActivity.kt
│       ├── CaptureService.kt
│       ├── TargetDetector.kt
│       ├── AimAccessibilityService.kt
│       ├── FovOverlay.kt
│       ├── OverlayService.kt
│       └── Config.kt
 
app/build.gradle.kts:
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}
 
android {
    namespace = "com.aim.r6m"
    compileSdk = 34
 
    defaultConfig {
        applicationId = "com.aim.r6m"
        minSdk = 28
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    }
 
    buildFeatures { compose = true }
    composeOptions { kotlinCompilerExtensionVersion = "1.5.8" }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions { jvmTarget = "17" }
    androidResources { noCompress += "tflite" }
}
 
dependencies {
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.activity:activity-compose:1.8.2")
    implementation(platform("androidx.compose:compose-bom:2024.02.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("org.tensorflow:tensorflow-lite:2.14.0")
    implementation("org.tensorflow:tensorflow-lite-support:0.4.4")
    implementation("org.tensorflow:tensorflow-lite-gpu:2.14.0")
}plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}
 
android {
    namespace = "com.aim.r6m"
    compileSdk = 34
 
    defaultConfig {
        applicationId = "com.aim.r6m"
        minSdk = 28
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    }
 
    buildFeatures { compose = true }
    composeOptions { kotlinCompilerExtensionVersion = "1.5.8" }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions { jvmTarget = "17" }
    androidResources { noCompress += "tflite" }
}
 
dependencies {
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.activity:activity-compose:1.8.2")
    implementation(platform("androidx.compose:compose-bom:2024.02.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("org.tensorflow:tensorflow-lite:2.14.0")
    implementation("org.tensorflow:tensorflow-lite-support:0.4.4")
    implementation("org.tensorflow:tensorflow-lite-gpu:2.14.0")
}
AndroidManifest.XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
 
    <application
        android:label="R6M Aim"
        android:icon="@android:drawable/ic_menu_compass"
        android:theme="@android:style/Theme.Material.Light.NoActionBar">
 
        <activity android:name=".MainActivity" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
 
        <service
            android:name=".CaptureService"
            android:foregroundServiceType="mediaProjection"
            android:exported="false" />
 
        <service
            android:name=".OverlayService"
            android:exported="false" />
 
        <service
            android:name=".AimAccessibilityService"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
            android:exported="true">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice.as"
                android:resource="@xml/accessibility_config" />
        </service>
    </application>
</manifest>
 
res/xml/accessibility_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagDefault"
    android:canPerformGestures="true"
    android:notificationTimeout="100" />
 
Config.kt:
package com.aim.r6m
 
object Config {
    data class Settings(
        var fovPercent: Float = 25f,
        var adsFovPercent: Float = 12f,
        var smoothing: Float = 6f,
        var headOffset: Float = 0.28f, // R6M operator head sits ~28% from top of bbox
        var confidence: Float = 0.40f,
        var enabled: Boolean = false,
        var adsMode: Boolean = false,
        var triggerbot: Boolean = false,
        var showFovCircle: Boolean = true
    )
    val current = Settings()
}
 
MainActivity.kt:
package com.aim.r6m
 
import android.app.Activity
import android.content.Intent
import android.media.projection.MediaProjectionManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings as AndroidSettings
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
 
class MainActivity : ComponentActivity() {
 
    private val projectionLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK && result.data != null) {
            val intent = Intent(this, CaptureService::class.java).apply {
                putExtra("code", result.resultCode)
                putExtra("data", result.data)
            }
            ContextCompat.startForegroundService(this, intent)
            startService(Intent(this, OverlayService::class.java))
            Config.current.enabled = true
        }
    }
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { MaterialTheme { SettingsScreen() } }
    }
 
     @composable
    fun SettingsScreen() {
        var fov by remember { mutableStateOf(Config.current.fovPercent) }
        var adsFov by remember { mutableStateOf(Config.current.adsFovPercent) }
        var smooth by remember { mutableStateOf(Config.current.smoothing) }
        var headOff by remember { mutableStateOf(Config.current.headOffset) }
        var conf by remember { mutableStateOf(Config.current.confidence) }
        var ads by remember { mutableStateOf(Config.current.adsMode) }
        var trig by remember { mutableStateOf(Config.current.triggerbot) }
        var showCircle by remember { mutableStateOf(Config.current.showFovCircle) }
 
        Column(
            Modifier.fillMaxSize().padding(20.dp).verticalScroll(rememberScrollState()),
            verticalArrangement = Arrangement.spacedBy(12.dp)
        ) {
            Text("R6M Aim — Test Build", style = MaterialTheme.typography.headlineSmall)
 
            Button(onClick = {
                if (!AndroidSettings.canDrawOverlays(this@MainActivity)) {
                    startActivity(Intent(
                        AndroidSettings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:$packageName")
                    ))
                    return@Button
                }
                val mpm = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
                projectionLauncher.launch(mpm.createScreenCaptureIntent())
            }) { Text("Start Capture") }
 
            Button(onClick = {
                stopService(Intent(this@MainActivity, CaptureService::class.java))
                stopService(Intent(this@MainActivity, OverlayService::class.java))
                Config.current.enabled = false
            }) { Text("Stop") }
 
            Button(onClick = {
                startActivity(Intent(AndroidSettings.ACTION_ACCESSIBILITY_SETTINGS))
            }) { Text("Open Accessibility Settings") }
 
            Divider()
 
            Text("Hipfire FOV: ${fov.toInt()}%")
            Slider(value = fov, valueRange = 5f..60f,
                onValueChange = { fov = it; Config.current.fovPercent = it })
 
            Text("ADS FOV: ${adsFov.toInt()}%")
            Slider(value = adsFov, valueRange = 3f..30f,
                onValueChange = { adsFov = it; Config.current.adsFovPercent = it })
 
            Text("Smoothing: ${smooth.toInt()} (lower = snappier)")
            Slider(value = smooth, valueRange = 1f..25f,
                onValueChange = { smooth = it; Config.current.smoothing = it })
 
            Text("Head Offset: ${"%.2f".format(headOff)} (0=center, 0.4=top of head)")
            Slider(value = headOff, valueRange = 0f..0.45f,
                onValueChange = { headOff = it; Config.current.headOffset = it })
 
            Text("Confidence Threshold: ${"%.2f".format(conf)}")
            Slider(value = conf, valueRange = 0.2f..0.9f,
                onValueChange = { conf = it; Config.current.confidence = it })
 
            Row(verticalAlignment = androidx.compose.ui.Alignment.CenterVertically) {
                Switch(checked = ads, onCheckedChange = { ads = it; Config.current.adsMode = it })
                Spacer(Modifier.width(8.dp)); Text("ADS Mode (tighter FOV)")
            }
            Row(verticalAlignment = androidx.compose.ui.Alignment.CenterVertically) {
                Switch(checked = trig, onCheckedChange = { trig = it; Config.current.triggerbot = it })
                Spacer(Modifier.width(8.dp)); Text("Triggerbot")
            }
            Row(verticalAlignment = androidx.compose.ui.Alignment.CenterVertically) {
                Switch(checked = showCircle, onCheckedChange = { showCircle = it; Config.current.showFovCircle = it })
                Spacer(Modifier.width(8.dp)); Text("Show FOV Circle")
            }
        }
    }
}
 
CaptureService.kt:
package com.aim.r6m
 
import android.app.*
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.media.Image
import android.media.ImageReader
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
import android.os.IBinder
import androidx.core.app.NotificationCompat
import kotlin.math.sqrt
 
class CaptureService : Service() {
 
    private lateinit var projection: MediaProjection
    private lateinit var reader: ImageReader
    private var virtualDisplay: VirtualDisplay? = null
    private val detector by lazy { TargetDetector(this) }
    private lateinit var thread: HandlerThread
 
    override fun onBind(intent: Intent?): IBinder? = null
 
    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        startForeground(1, buildNotif())
        val code = intent.getIntExtra("code", 0)
        val data: Intent = intent.getParcelableExtra("data")!!
        val mpm = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
        projection = mpm.getMediaProjection(code, data)
 
        val m = resources.displayMetrics
        // downscale capture to 720p for inference speed
        val capW = 1280; val capH = (1280f * m.heightPixels / m.widthPixels).toInt()
 
        reader = ImageReader.newInstance(capW, capH, PixelFormat.RGBA_8888, 2)
        thread = HandlerThread("cap").also { it.start() }
        val handler = Handler(thread.looper)
 
        virtualDisplay = projection.createVirtualDisplay(
            "r6m", capW, capH, m.densityDpi,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
            reader.surface, null, handler
        )
 
        reader.setOnImageAvailableListener({ r ->
            if (!Config.current.enabled) { r.acquireLatestImage()?.close(); return@setOnImageAvailableListener }
            val img = r.acquireLatestImage() ?: return@setOnImageAvailableListener
            try {
                val bmp = imageToBitmap(img, capW, capH)
                processFrame(bmp, m.widthPixels.toFloat(), m.heightPixels.toFloat(), capW.toFloat(), capH.toFloat())
            } finally { img.close() }
        }, handler)
 
        return START_STICKY
    }
 
    private fun processFrame(bmp: Bitmap, screenW: Float, screenH: Float, capW: Float, capH: Float) {
        val cfg = Config.current
        val cx = capW / 2f; val cy = capH / 2f
        val fovPct = if (cfg.adsMode) cfg.adsFovPercent else cfg.fovPercent
        val fovPx = (minOf(capW, capH) * fovPct / 100f) / 2f
 
        val targets = detector.detect(bmp, cfg.confidence)
        if (targets.isEmpty()) return
 
        // pick closest enemy in FOV, prefer head-aimed point
        val best = targets.mapNotNull { t ->
            val aimY = t.y - t.h * cfg.headOffset
            val dx = t.x - cx; val dy = aimY - cy
            val d = sqrt(dx * dx + dy * dy)
            if (d <= fovPx) Triple(t.x, aimY, d) else null
        }.minByOrNull { it.third } ?: return
 
        // map capture coords back to screen coords
        val sx = best.first * (screenW / capW)
        val sy = best.second * (screenH / capH)
 
        AimAccessibilityService.instance?.aimAt(sx, sy, cfg.smoothing, cfg.triggerbot)
    }
 
    private fun imageToBitmap(image: Image, w: Int, h: Int): Bitmap {
        val plane = image.planes[0]
        val buf = plane.buffer
        val pixelStride = plane.pixelStride
        val rowStride = plane.rowStride
        val rowPadding = rowStride - pixelStride * w
        val full = Bitmap.createBitmap(w + rowPadding / pixelStride, h, Bitmap.Config.ARGB_8888)
        full.copyPixelsFromBuffer(buf)
        return Bitmap.createBitmap(full, 0, 0, w, h)
    }
 
    private fun buildNotif(): Notification {
        val ch = "cap"
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val nm = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            nm.createNotificationChannel(NotificationChannel(ch, "Capture", NotificationManager.IMPORTANCE_LOW))
        }
        return NotificationCompat.Builder(this, ch)
            .setContentTitle("R6M Aim active")
            .setSmallIcon(android.R.drawable.ic_menu_compass)
            .build()
    }
 
    override fun onDestroy() {
        super.onDestroy()
        virtualDisplay?.release()
        reader.close()
        if (::projection.isInitialized) projection.stop()
        if (::thread.isInitialized) thread.quitSafely()
    }
}
 
TargetDetector.kt:
package com.aim.r6m
 
import android.content.Context
import android.graphics.Bitmap
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.gpu.CompatibilityList
import org.tensorflow.lite.gpu.GpuDelegate
import org.tensorflow.lite.support.common.FileUtil
import java.nio.ByteBuffer
import java.nio.ByteOrder
import kotlin.math.max
import kotlin.math.min
 
data class Target(val x: Float, val y: Float, val w: Float, val h: Float, val conf: Float)
 
class TargetDetector(ctx: Context) {
 
    private val inputSize = 416 // smaller = faster on mobile
    private val interpreter: Interpreter
 
    init {
        val opts = Interpreter.Options()
        val compat = CompatibilityList()
        if (compat.isDelegateSupportedOnThisDevice) {
            opts.addDelegate(GpuDelegate(compat.bestOptionsForThisDevice))
        } else {
            opts.setNumThreads(4)
        }
        interpreter = Interpreter(FileUtil.loadMappedFile(ctx, "r6m_operators.tflite"), opts)
    }
 
    fun detect(bmp: Bitmap, confThreshold: Float): List<Target> {
        val scaled = Bitmap.createScaledBitmap(bmp, inputSize, inputSize, true)
        val input = preprocess(scaled)
        // YOLOv8 output shape [1, 5, 3549] for 416 input, single class (operator)
        val numBoxes = 3549
        val output = Array(1) { Array(5) { FloatArray(numBoxes) } }
        interpreter.run(input, output)
 
        val results = mutableListOf<Target>()
        val sx = bmp.width / inputSize.toFloat()
        val sy = bmp.height / inputSize.toFloat()
 
        for (i in 0 until numBoxes) {
            val conf = output[0][4][i]
            if (conf < confThreshold) continue
            val cx = output[0][0][i] * sx
            val cy = output[0][1][i] * sy
            val w  = output[0][2][i] * sx
            val h  = output[0][3][i] * sy
            results += Target(cx, cy, w, h, conf)
        }
        return nms(results, 0.45f)
    }
 
    private fun preprocess(bmp: Bitmap): ByteBuffer {
        val buf = ByteBuffer.allocateDirect(4 * inputSize * inputSize * 3).order(ByteOrder.nativeOrder())
        val px = IntArray(inputSize * inputSize)
        bmp.getPixels(px, 0, inputSize, 0, 0, inputSize, inputSize)
        for (p in px) {
            buf.putFloat(((p shr 16) and 0xFF) / 255f)
            buf.putFloat(((p shr 8) and 0xFF) / 255f)
            buf.putFloat((p and 0xFF) / 255f)
        }
        buf.rewind()
        return buf
    }
 
    private fun nms(boxes: List<Target>, iouThresh: Float): List<Target> {
        val sorted = boxes.sortedByDescending { it.conf }.toMutableList()
        val keep = mutableListOf<Target>()
        while (sorted.isNotEmpty()) {
            val a = sorted.removeAt(0)
            keep += a
            sorted.removeAll { iou(a, it) > iouThresh }
        }
        return keep
    }
 
    private fun iou(a: Target, b: Target): Float {
        val ax1 = a.x - a.w/2; val ay1 = a.y - a.h/2
        val ax2 = a.x + a.w/2; val ay2 = a.y + a.h/2
        val bx1 = b.x - b.w/2; val by1 = b.y - b.h/2
        val bx2 = b.x + b.w/2; val by2 = b.y + b.h/2

Что внутри:
В проекте реализован раздельный FOV для стрельбы от бедра и ADS (прицеливания), нормальный смуч (smoothing) и даже зачатки триггербота. Вся математика по поиску ближайшей цели в FOV и расчет смещения на голову (head offset) уже на месте. Код чистый, без лишнего мусора, отлично подойдет как фундамент для своего чита на любую мобильную игру.

Нюансы по детекту:
Так как метод использует Screen Capture и Accessibility Services, это безопаснее, чем лезть в память процесса, но современные античиты (типа того же ACE или защит в Siege) могут триггериться на сам факт использования спец. возможностей или активный оверлей сверху игры. Для легитной игры стоит подкрутить смуч и не выставлять FOV на пол-экрана.

Как завести:
Нужен Android Studio и прямые руки. Не забудьте закинуть свою обученную модель r6m_operators.tflite в assets. Если модель качественная, то бот липнет к противникам очень бодро.

Кто готов допилить это до полноценного релиза или планирует форкнуть под другие мобильные шутеры?
 
Назад
Сверху Снизу