Mine Manager - Auto Proactive

Tự động chủ động gọi API không cần click giao diện

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name          Mine Manager - Auto Proactive
// @namespace     http://tampermonkey.net/
// @version       1.2.1
// @description   Tự động chủ động gọi API không cần click giao diện
// @author        Gemini
// @match        *://*/*
// @match         *://*.cnovel.com/*
// @grant         unsafeWindow
// @grant         GM_setValue
// @grant         GM_getValue
// @run-at        document-end
// ==/UserScript==
(function() {
    'use strict';
     const isGameDomain = () => {
        return /cmangax\d+\.com|cnovel|cmangapi/.test(location.hostname);
    };

    if (!isGameDomain()) return;

    // ==================== CẤU HÌNH ====================
    const CHECK_INTERVAL = 1 * 60 * 1000; // 5 phút check 1 lần
    const HARVEST_THRESHOLD = 60;        // Ngưỡng thu hoạch 60 phút

    console.log('%c[Auto Mine] Script đã nạp. Chế độ: CHỦ ĐỘNG (Proactive)', 'color: #00ff00; font-weight: bold;');

    // 1. Hàm lấy bảo mật từ window của game
    const getGameWindow = () => {
        return typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
    }
    const callGameFunc = (funcName, args = []) => {
        const targetWindow = getGameWindow();
        if (typeof targetWindow[funcName] === 'function') {
            try {
                return targetWindow[funcName](...args);
            } catch (e) {
                console.error(`Lỗi khi thực thi hàm ${funcName}:`, e);
                return null;
            }
        }
        return null;
    }
    function getSecurity() {
        if (typeof unsafeWindow.send_user_security === 'function') {
            return unsafeWindow.send_user_security();
        }
        return null;
    }

    let user_data = callGameFunc('get_user_security')
    let currentTarget = user_data.character

    // 2. HÀM QUAN TRỌNG: Tự gọi API score_list
    async function checkMineStatus() {
        console.log(`[Auto Mine] [${new Date().toLocaleTimeString()}] Đang tự động gửi request tới API...`);
        const url = `/api/score_list?type=battle_mine_target&target=${currentTarget}&_=${Date.now()}`;

        try {
            const response = await fetch(url, {
                method: 'GET',
                credentials: 'include',
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                    'Accept': 'application/json'
                }
            });

            const data = await response.json();

            if (data && data.status === 1) {
                console.log('[Auto Mine] Đã nhận dữ liệu API thành công.');
                handleResponse(data);
            } else {
                console.warn('[Auto Mine] API trả về trạng thái lỗi (có thể do session hết hạn).');
            }
        } catch (error) {
            console.error('[Auto Mine] Lỗi khi chủ động thực hiện fetch:', error);
        }
    }

    function handleResponse(responseData) {
        if (!responseData.data || responseData.data.length === 0) {
            console.log('[Auto Mine] Không có dữ liệu ngồi mỏ. Đang chiếm lại mỏ cũ...');
            const savedId = GM_getValue('lastMineId');
            if (savedId) challengeMine(savedId);
            return;
        }

        const mineEntry = responseData.data[0];
        try {
            const mineData = JSON.parse(mineEntry.data);

            // Lấy "times" ở cấp ngoài của object miner như bạn yêu cầu
            const times = mineData.miner.times || 0;

            const mineId = mineEntry.id_score;

            console.log(`[Auto Mine] Target: ${currentTarget} | Score_od: ${mineId} |Đã ngồi: ${times}/${HARVEST_THRESHOLD} phút`);

            // Lưu dữ liệu để dùng lần sau (khi F5 trang)
            GM_setValue('lastMineId', mineId);
            GM_setValue('lastMineTarget', currentTarget);

            if (times >= HARVEST_THRESHOLD) {
                console.log('%c[Auto Mine] Đủ thời gian! Thực hiện thu hoạch ngay...', 'color: orange; font-weight: bold;');
                takeMineReward();
            }
        } catch (e) {
            console.error('[Auto Mine] Lỗi phân tích JSON từ API:', e);
        }
    }

    // 4. Hàm Thu hoạch
    async function takeMineReward() {
        const security = getSecurity();
        if (!security) return;

        const formData = new FormData();
        formData.append('action', 'battle_mine_take_reward');
        formData.append('target', 'public');

        if (typeof security === 'object') {
            for (const key in security) {
                formData.append(`user_security[${key}]`, security[key]);
            }
        }

        try {
            const res = await fetch('/assets/ajax/character_activity.php', {
                method: 'POST',
                body: formData,
                credentials: 'include'
            });
            const result = await res.json();
            console.log('[Auto Mine] Kết quả thu hoạch:', result);
        } catch (e) { console.error('[Auto Mine] Lỗi thu hoạch:', e); }
    }

    // 5. Hàm Chiếm mỏ
    async function challengeMine( mineId) {
        const security = getSecurity();
        if (!security) return;

        const formData = new FormData();
        formData.append('action', 'battle_mine_challenge');
        formData.append('target', 'public');
        formData.append('mine_id', mineId);

        if (typeof security === 'object') {
            for (const key in security) {
                formData.append(`user_security[${key}]`, security[key]);
            }
        }

        try {
            const res = await fetch('/assets/ajax/character_activity.php', {
                method: 'POST',
                body: formData,
                credentials: 'include'
            });
            const result = await res.json();
            console.log('[Auto Mine] Kết quả chiếm mỏ:', result);
        } catch (e) { console.error('[Auto Mine] Lỗi chiếm mỏ:', e); }
    }

    // ==================== KHỞI CHẠY ====================
    function start() {
        // Chạy lần đầu ngay lập tức khi load trang
        checkMineStatus();

        // Thiết lập lặp lại
        setInterval(checkMineStatus, CHECK_INTERVAL);

        console.log(`[Auto Mine] Hệ thống tự động đã bắt đầu. Chu kỳ: ${CHECK_INTERVAL/60000} phút.`);
    }

    // Đợi 3 giây sau khi trang load để đảm bảo các hàm của game đã sẵn sàng
    window.addEventListener('load', () => {
        setTimeout(start, 3000);
    });

})();