ZeroAd: CrazyGames

Ad bypass with deep hooks, stateful ad simulation & race condition handling

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         ZeroAd: CrazyGames
// @namespace    https://greasyfork.org/users/YOUR_USER_ID
// @version      4.1.0
// @description  Ad bypass with deep hooks, stateful ad simulation & race condition handling
// @author       ZeroAd Team
// @match        *://*.crazygames.com/*
// @match        *://crazygames.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Prevent double execution
    if (window.__zeroAdInstalled) return;
    window.__zeroAdInstalled = true;

    // ═══════════════════════════════════════════════════════════════
    // CONFIGURATION
    // ═══════════════════════════════════════════════════════════════
    const CONFIG = {
        DEBUG: true,
        REWARD_DELAY_MS: 10,
        MAX_HOOK_ATTEMPTS: 100,
        HOOK_RETRY_INTERVAL_MS: 200,
        MUTATION_OBSERVER_ENABLED: true,
        AD_PLAYING_DURATION_MS: 5   // how long isAdPlaying stays true (ms)
    };

    const log = (...args) => CONFIG.DEBUG && console.log('[ZeroAd]', ...args);
    const warn = (...args) => CONFIG.DEBUG && console.warn('[ZeroAd]', ...args);

    const hookState = {
        crazyGamesSDK: false,
        constructSDK: false,
        crazygamesAds: false,
        interceptedCalls: 0
    };

    // ═══════════════════════════════════════════════════════════════
    // FAKE AD MODULE (stateful isAdPlaying)
    // ═══════════════════════════════════════════════════════════════
    function createFakeAdModule() {
        let _adPlaying = false;
        let _playingTimer = null;

        // Dispatch common reward events
        function dispatchRewardEvents() {
            const events = [
                'rewardedComplete', 'rewardGranted', 'adComplete',
                'crazy_ad_finished', 'adReward', 'adFinished'
            ];
            events.forEach(ev => {
                try { window.dispatchEvent(new CustomEvent(ev)); } catch (e) {}
            });
        }

        const module = {
            get isAdPlaying() {
                log(`isAdPlaying checked → ${_adPlaying}`);
                return _adPlaying;
            },
            get requestInProgress() {
                log('requestInProgress checked → false');
                return false;
            },
            get hasAdblock() {
                log('hasAdblock checked → false');
                return false;
            },

            async prefetchAd(type) {
                hookState.interceptedCalls++;
                log(`✓ INTERCEPTED: prefetchAd("${type}")`);
                return Promise.resolve();
            },

            async requestAd(type, callbacks = {}) {
                hookState.interceptedCalls++;
                log(`✓ INTERCEPTED: requestAd("${type}")`);

                // Set ad playing state
                _adPlaying = true;
                if (_playingTimer) clearTimeout(_playingTimer);
                _playingTimer = setTimeout(() => { _adPlaying = false; }, CONFIG.AD_PLAYING_DURATION_MS);

                // adStarted callback
                if (typeof callbacks.adStarted === 'function') {
                    try {
                        callbacks.adStarted();
                        log('  → adStarted() called');
                    } catch(e) {
                        warn('adStarted error:', e);
                    }
                }

                // Resolve after reward delay
                return new Promise(resolve => {
                    setTimeout(() => {
                        _adPlaying = false;
                        if (_playingTimer) {
                            clearTimeout(_playingTimer);
                            _playingTimer = null;
                        }

                        if (typeof callbacks.adFinished === 'function') {
                            try {
                                callbacks.adFinished();
                                log('  → adFinished() called');
                            } catch(e) {
                                warn('adFinished error:', e);
                            }
                        }

                        dispatchRewardEvents();
                        log(`  → ✅ Reward granted for "${type}"`);
                        resolve();
                    }, CONFIG.REWARD_DELAY_MS);
                });
            },

            async hasAdblockEnabled() {
                hookState.interceptedCalls++;
                log('✓ INTERCEPTED: hasAdblockEnabled() → false');
                return false;
            },

            addAdblockPopupListener() { log('addAdblockPopupListener (stub)'); },
            removeAdblockPopupListener() { log('removeAdblockPopupListener (stub)'); }
        };

        return module;
    }

    // ═══════════════════════════════════════════════════════════════
    // HOOK: CrazyGames.SDK.ad
    // ═══════════════════════════════════════════════════════════════
    function hookCrazyGamesSDK() {
        if (hookState.crazyGamesSDK) return true;

        try {
            if (window.CrazyGames?.SDK) {
                const fakeAd = createFakeAdModule();
                Object.defineProperty(window.CrazyGames.SDK, 'ad', {
                    configurable: true,
                    enumerable: true,
                    get: () => {
                        log('SDK.ad accessed (getter)');
                        return fakeAd;
                    }
                });
                hookState.crazyGamesSDK = true;
                log('✓✓ CrazyGames.SDK.ad HOOKED (existing)');
                return true;
            }

            let _crazyGames = window.CrazyGames;
            Object.defineProperty(window, 'CrazyGames', {
                configurable: true,
                enumerable: true,
                get() { return _crazyGames; },
                set(newValue) {
                    log('CrazyGames object assigned');
                    _crazyGames = newValue;
                    if (newValue?.SDK && !hookState.crazyGamesSDK) {
                        const fakeAd = createFakeAdModule();
                        Object.defineProperty(newValue.SDK, 'ad', {
                            configurable: true,
                            enumerable: true,
                            get: () => fakeAd
                        });
                        hookState.crazyGamesSDK = true;
                        log('✓✓ CrazyGames.SDK.ad HOOKED (deferred)');
                    }
                }
            });
            log('✓ CrazyGames trap installed');
            return false;
        } catch (error) {
            warn('Failed to hook CrazyGames.SDK:', error);
            return false;
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // HOOK: ConstructCrazySDK.ad
    // ═══════════════════════════════════════════════════════════════
    function hookConstructSDK() {
        if (hookState.constructSDK) return true;

        try {
            if (window.ConstructCrazySDK) {
                const fakeAd = createFakeAdModule();
                Object.defineProperty(window.ConstructCrazySDK, 'ad', {
                    configurable: true,
                    enumerable: true,
                    get: () => fakeAd
                });
                hookState.constructSDK = true;
                log('✓✓ ConstructCrazySDK.ad HOOKED (existing)');
                return true;
            }

            let _construct = window.ConstructCrazySDK;
            Object.defineProperty(window, 'ConstructCrazySDK', {
                configurable: true,
                enumerable: true,
                get() { return _construct; },
                set(newValue) {
                    log('ConstructCrazySDK object assigned');
                    _construct = newValue;
                    if (newValue && !hookState.constructSDK) {
                        const fakeAd = createFakeAdModule();
                        Object.defineProperty(newValue, 'ad', {
                            configurable: true,
                            enumerable: true,
                            get: () => fakeAd
                        });
                        hookState.constructSDK = true;
                        log('✓✓ ConstructCrazySDK.ad HOOKED (deferred)');
                    }
                }
            });
            log('✓ ConstructCrazySDK trap installed');
            return false;
        } catch (error) {
            warn('Failed to hook ConstructCrazySDK:', error);
            return false;
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // HOOK: CrazygamesAds (Proxy with improved adblock matching)
    // ═══════════════════════════════════════════════════════════════
    function hookCrazygamesAds() {
        if (hookState.crazygamesAds) return true;

        const AD_METHODS = [
            'requestAd', 'requestAds', 'showAd', 'showRewardedAd',
            'displayAd', 'displayRewardedAd', 'displayMidrollAd',
            'requestRewardedAd', 'showRewardedVideo', 'requestRewardedVideo',
            'showInterstitial', 'requestOnly', 'render', 'preloadAd'
        ];

        function isAdMethod(prop) {
            return AD_METHODS.includes(prop);
        }

        function isAdblockMethod(prop) {
            // case-insensitive match for variations
            const lower = prop.toLowerCase();
            return lower === 'hasadblock' || lower === 'hasadblockenabled' || lower === 'isadblockactive';
        }

        function createAdsProxy(target) {
            if (!target || target.__zaProxied) return target;

            const handler = {
                get(obj, prop) {
                    const original = obj[prop];

                    if (isAdMethod(prop) && typeof original === 'function') {
                        return function(...args) {
                            hookState.interceptedCalls++;
                            log(`✓ INTERCEPTED: CrazygamesAds.${prop}()`);

                            let onStarted = null;
                            let onFinished = null;

                            for (const arg of args) {
                                if (arg && typeof arg === 'object') {
                                    onStarted = arg.adStarted || arg.onAdStarted || arg.onStart;
                                    onFinished = arg.adFinished || arg.onAdFinished || arg.onComplete || arg.onReward;
                                }
                            }

                            if (typeof onStarted === 'function') {
                                try { onStarted(); } catch(e) { warn('onStarted error:', e); }
                            }

                            if (prop === 'requestOnly' || prop === 'preloadAd') {
                                return Promise.resolve({ success: true });
                            }

                            return new Promise(resolve => {
                                setTimeout(() => {
                                    if (typeof onFinished === 'function') {
                                        try { onFinished(); } catch(e) { warn('onFinished error:', e); }
                                    }
                                    // Dispatch events
                                    const events = [
                                        'rewardedComplete', 'adComplete', 'crazy_ad_finished'
                                    ];
                                    events.forEach(ev => {
                                        try { window.dispatchEvent(new CustomEvent(ev)); } catch(e) {}
                                    });
                                    resolve({ success: true, completed: true });
                                }, CONFIG.REWARD_DELAY_MS);
                            });
                        };
                    }

                    if (isAdblockMethod(prop) && typeof original === 'function') {
                        return async () => {
                            log(`✓ INTERCEPTED: CrazygamesAds.${prop}() → false`);
                            return false;
                        };
                    }

                    return original;
                }
            };

            const proxied = new Proxy(target, handler);
            proxied.__zaProxied = true;
            return proxied;
        }

        try {
            if (window.CrazygamesAds) {
                window.CrazygamesAds = createAdsProxy(window.CrazygamesAds);
                hookState.crazygamesAds = true;
                log('✓✓ CrazygamesAds HOOKED (existing)');
                return true;
            }

            let _ads = window.CrazygamesAds;
            Object.defineProperty(window, 'CrazygamesAds', {
                configurable: true,
                enumerable: true,
                get() { return _ads; },
                set(newValue) {
                    log('CrazygamesAds object assigned');
                    _ads = newValue ? createAdsProxy(newValue) : newValue;
                    if (_ads && !hookState.crazygamesAds) {
                        hookState.crazygamesAds = true;
                        log('✓✓ CrazygamesAds HOOKED (deferred)');
                    }
                }
            });
            log('✓ CrazygamesAds trap installed');
            return false;
        } catch (error) {
            warn('Failed to hook CrazygamesAds:', error);
            return false;
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // ORCHESTRATION & RETRY LOGIC
    // ═══════════════════════════════════════════════════════════════
    let hookAttempts = 0;
    let retryTimer = null;
    let observer = null;

    function allHooksInstalled() {
        return hookState.crazyGamesSDK && hookState.constructSDK && hookState.crazygamesAds;
    }

    function attemptHooks() {
        hookAttempts++;
        hookCrazyGamesSDK();
        hookConstructSDK();
        hookCrazygamesAds();

        if (allHooksInstalled()) {
            log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
            log('✅ ALL HOOKS INSTALLED SUCCESSFULLY');
            log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
            cleanup();
            return true;
        }

        if (hookAttempts >= CONFIG.MAX_HOOK_ATTEMPTS) {
            warn('⚠️  Hook installation incomplete after max attempts');
            warn('Hooked:', hookState);
            cleanup();
            return false;
        }

        return false;
    }

    function cleanup() {
        if (retryTimer) {
            clearInterval(retryTimer);
            retryTimer = null;
        }
        if (observer) {
            observer.disconnect();
            observer = null;
            log('✓ MutationObserver disconnected');
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // MUTATION OBSERVER: Watch for SDK script injection
    // ═══════════════════════════════════════════════════════════════
    function setupMutationObserver() {
        if (!CONFIG.MUTATION_OBSERVER_ENABLED) return;

        observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    if (node.tagName === 'SCRIPT') {
                        const src = node.src || '';
                        if (src.includes('crazygames') || src.includes('sdk')) {
                            log(`Script detected: ${src.substring(0, 80)}...`);
                            node.addEventListener('load', () => {
                                log('SDK script loaded, re-attempting hooks');
                                setTimeout(attemptHooks, 50);
                            });
                        }
                    }
                }
            }
        });

        observer.observe(document.documentElement, {
            childList: true,
            subtree: true
        });

        log('✓ MutationObserver watching for SDK scripts');
    }

    // ═══════════════════════════════════════════════════════════════
    // INITIALIZATION
    // ═══════════════════════════════════════════════════════════════
    function initialize() {
        log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
        log('ZeroAd v4.1.0 - Fixed & Enhanced');
        log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');

        attemptHooks();
        setupMutationObserver();

        retryTimer = setInterval(() => {
            if (!allHooksInstalled() && hookAttempts < CONFIG.MAX_HOOK_ATTEMPTS) {
                attemptHooks();
                log(`Hook attempt ${hookAttempts}/${CONFIG.MAX_HOOK_ATTEMPTS}`);
            } else {
                cleanup();
            }
        }, CONFIG.HOOK_RETRY_INTERVAL_MS);

        setTimeout(() => {
            log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
            log('Status Report:');
            log('  Hooks installed:', hookState);
            log('  Intercepted calls:', hookState.interceptedCalls);
            log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
        }, 5000);
    }

    // Run immediately
    initialize();

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', attemptHooks);
    }

})();