Greasy Fork is available in English.

ZeroAd: CrazyGames SDK

Ad bypass with singleton SDK instance, event, and Unity support

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         ZeroAd: CrazyGames SDK
// @namespace    https://greasyfork.org/users/YOUR_USER_ID
// @version      4.4.1
// @description  Ad bypass with singleton SDK instance, event, and Unity support
// @author       ZeroAd Team
// @match        *://*.crazygames.com/*
// @match        *://crazygames.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    if (window.__zeroAdInstalled) return;
    window.__zeroAdInstalled = true;

    const CONFIG = {
        DEBUG: true,
        REWARD_DELAY_MS: 500,   // Half a second feels natural
        MAX_HOOK_ATTEMPTS: 100,
        HOOK_RETRY_INTERVAL_MS: 200,
        AD_PLAYING_DURATION_MS: 5,
        SIMULATE_AD_ERROR: false
    };

    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,
        unityGameInstance: false,
        genericCrazySDK: false,
        crazySDKInstance: false,
        interceptedCalls: 0
    };

    // Singleton fake instance (created once)
    let fakeCrazySDKInstance = null;

    // ═══════════════════════════════════════════════════════════════
    // Fake CrazySDK Instance (singleton)
    // ═══════════════════════════════════════════════════════════════
    function createFakeCrazySDKInstance() {
        const listeners = {};
        let initCalled = false;
        let requestInProgress = false;

        function fireEvent(eventName, data = {}) {
            if (listeners[eventName]) {
                listeners[eventName].forEach(cb => {
                    try { cb(data); } catch (e) { warn(`Error in ${eventName} listener:`, e); }
                });
            }
        }

        return {
            init() {
                log('CrazySDK instance: init()');
                initCalled = true;
                setTimeout(() => {
                    fireEvent('initialized', {
                        userInfo: {
                            countryCode: "US",
                            browser: { name: "Chrome", version: "120" },
                            os: { name: "Windows", version: "10" },
                            device: { type: "desktop" }
                        }
                    });
                }, 50);
            },

            addEventListener(event, callback) {
                if (!listeners[event]) listeners[event] = [];
                listeners[event].push(callback);
                log(`CrazySDK instance: added listener for "${event}"`);
                if (event === 'initialized' && initCalled) {
                    setTimeout(() => callback({
                        userInfo: {
                            countryCode: "US",
                            browser: { name: "Chrome", version: "120" },
                            os: { name: "Windows", version: "10" },
                            device: { type: "desktop" }
                        }
                    }), 10);
                }
            },
            removeEventListener(event, callback) {
                if (listeners[event]) {
                    listeners[event] = listeners[event].filter(cb => cb !== callback);
                }
            },

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

                if (CONFIG.SIMULATE_AD_ERROR) {
                    fireEvent('adError', { error: 'Simulated error' });
                    return;
                }

                requestInProgress = true;
                fireEvent('adStarted', { adType: type });
                log('  → adStarted fired');

                return new Promise(resolve => {
                    setTimeout(() => {
                        requestInProgress = false;
                        fireEvent('adFinished', { adType: type });
                        log('  → adFinished fired');
                        log(`  → ✅ Reward granted for "${type}"`);
                        resolve();
                    }, CONFIG.REWARD_DELAY_MS);
                });
            },

            gameplayStart() { log('CrazySDK instance: gameplayStart() (stub)'); },
            gameplayStop() { log('CrazySDK instance: gameplayStop() (stub)'); },
            happytime() { log('CrazySDK instance: happytime() (stub)'); },
            sdkGameLoadingStart() { log('CrazySDK instance: sdkGameLoadingStart() (stub)'); },
            sdkGameLoadingStop() { log('CrazySDK instance: sdkGameLoadingStop() (stub)'); },

            async requestBanner(containers) {
                log('CrazySDK instance: requestBanner() (stub)', containers);
                if (Array.isArray(containers)) {
                    containers.forEach(c => {
                        setTimeout(() => fireEvent('bannerRendered', { containerId: c.containerId }), 50);
                    });
                }
            },
            async requestResponsiveBanner(containers) {
                log('CrazySDK instance: requestResponsiveBanner() (stub)', containers);
                if (Array.isArray(containers)) {
                    containers.forEach(c => {
                        setTimeout(() => fireEvent('bannerRendered', { containerId: c.id || c.containerId }), 50);
                    });
                }
            },
            clearBanner(containerId) { log(`CrazySDK instance: clearBanner("${containerId}") (stub)`); },
            clearAllBanners() { log('CrazySDK instance: clearAllBanners() (stub)'); },

            get hasAdblock() { return false; },
            adblockDetectionExecuted: true,

            inviteLink(params = {}) {
                log('CrazySDK instance: inviteLink() (stub)');
                const baseUrl = window.location.href.split('?')[0];
                const queryParams = new URLSearchParams(params);
                return `${baseUrl}?czy_invite=true&utm_source=invite&${queryParams.toString()}`;
            },

            get requestInProgress() { return requestInProgress; },
            set requestInProgress(val) { requestInProgress = val; }
        };
    }

    // ═══════════════════════════════════════════════════════════════
    // HOOK: CrazyGames.CrazySDK.getInstance() – SINGLETON FIX
    // ═══════════════════════════════════════════════════════════════
    function hookCrazySDKInstance() {
        if (hookState.crazySDKInstance) return true;

        // Create the singleton instance immediately
        fakeCrazySDKInstance = createFakeCrazySDKInstance();

        try {
            if (window.CrazyGames?.CrazySDK?.getInstance) {
                const originalGetInstance = window.CrazyGames.CrazySDK.getInstance;
                window.CrazyGames.CrazySDK.getInstance = function() {
                    log('✓ INTERCEPTED: CrazyGames.CrazySDK.getInstance()');
                    return fakeCrazySDKInstance;
                };
                hookState.crazySDKInstance = true;
                log('✓✓ CrazySDK.getInstance() HOOKED (existing singleton)');
                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?.CrazySDK?.getInstance && !hookState.crazySDKInstance) {
                        const originalGetInstance = newValue.CrazySDK.getInstance;
                        newValue.CrazySDK.getInstance = function() {
                            log('✓ INTERCEPTED: CrazyGames.CrazySDK.getInstance() (deferred)');
                            return fakeCrazySDKInstance;
                        };
                        hookState.crazySDKInstance = true;
                        log('✓✓ CrazySDK.getInstance() HOOKED (deferred singleton)');
                    }
                }
            });

            log('✓ CrazySDK.getInstance() singleton trap installed');
            return false;
        } catch (error) {
            warn('Failed to hook CrazySDK.getInstance():', error);
            return false;
        }
    }

    // ═══════════════════════════════════════════════════════════════
    // Legacy hooks (unchanged, kept for compatibility)
    // ═══════════════════════════════════════════════════════════════
    function createFakeAdModule() {
        let _adPlaying = false;
        let _playingTimer = null;

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

        return {
            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}")`);
                _adPlaying = true;
                if (_playingTimer) clearTimeout(_playingTimer);
                _playingTimer = setTimeout(() => { _adPlaying = false; }, CONFIG.AD_PLAYING_DURATION_MS);

                if (CONFIG.SIMULATE_AD_ERROR && typeof callbacks.adError === 'function') {
                    try { callbacks.adError({ code: 'INTERNAL_ERROR', message: 'Simulated error' }); log('  → adError() called'); } catch(e) {}
                    _adPlaying = false; clearTimeout(_playingTimer); return;
                }
                if (typeof callbacks.adStarted === 'function') { try { callbacks.adStarted(); log('  → adStarted() called'); } catch(e) {} }
                return new Promise(resolve => {
                    setTimeout(() => {
                        _adPlaying = false; clearTimeout(_playingTimer);
                        if (typeof callbacks.adFinished === 'function') { try { callbacks.adFinished(); log('  → adFinished() called'); } catch(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)'); }
        };
    }

    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: () => 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) { _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; }
    }

    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) { _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; }
    }

    function hookGenericCrazySDK() {
        if (hookState.genericCrazySDK) return true;
        const target = window.CrazySDK || window.crazysdk;
        if (target) {
            const fakeAd = createFakeAdModule();
            if (target.ad) { Object.defineProperty(target, 'ad', { configurable: true, enumerable: true, get: () => fakeAd }); log('✓✓ CrazySDK.ad HOOKED'); }
            if (target.Ad) { Object.defineProperty(target, 'Ad', { configurable: true, enumerable: true, get: () => fakeAd }); log('✓✓ CrazySDK.Ad HOOKED'); }
            hookState.genericCrazySDK = true; return true;
        }
        ['CrazySDK', 'crazysdk'].forEach(propName => {
            if (hookState.genericCrazySDK) return;
            let _val = window[propName];
            Object.defineProperty(window, propName, {
                configurable: true, enumerable: true, get() { return _val; },
                set(newValue) { _val = newValue; if (newValue && !hookState.genericCrazySDK) { const fakeAd = createFakeAdModule(); if (newValue.ad) Object.defineProperty(newValue, 'ad', { configurable: true, enumerable: true, get: () => fakeAd }); if (newValue.Ad) Object.defineProperty(newValue, 'Ad', { configurable: true, enumerable: true, get: () => fakeAd }); hookState.genericCrazySDK = true; log(`✓✓ ${propName} HOOKED (deferred)`); } }
            });
        });
        log('✓ Generic CrazySDK trap installed'); return false;
    }

    function hookUnitySendMessage() {
        if (hookState.unityGameInstance) return true;
        const candidates = Object.keys(window).filter(key => { try { const val = window[key]; return val && typeof val === 'object' && typeof val.SendMessage === 'function'; } catch(e) { return false; } });
        for (const key of candidates) {
            const instance = window[key]; if (instance.__zaHooked) continue;
            const originalSend = instance.SendMessage;
            instance.SendMessage = function(gameObject, method, param) {
                if (method === 'AdEvent' && (param === 'adStarted' || param === 'adFinished' || param === 'adError')) { log(`✓ INTERCEPTED: Unity SendMessage`); hookState.interceptedCalls++; if (param === 'adStarted') { setTimeout(() => { try { originalSend.call(this, gameObject, method, 'adFinished'); } catch(e) {} }, CONFIG.REWARD_DELAY_MS); } return; }
                return originalSend.apply(this, arguments);
            };
            instance.__zaHooked = true; hookState.unityGameInstance = true; log(`✓✓ Unity SendMessage HOOKED`); return true;
        }
        return false;
    }

    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) {
            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, 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); } }
                                    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
    // ═══════════════════════════════════════════════════════════════
    let hookAttempts = 0;
    let retryTimer = null;
    let observer = null;

    function allHooksInstalled() {
        return hookState.crazySDKInstance ||
               (hookState.crazyGamesSDK && hookState.constructSDK && hookState.crazygamesAds &&
                hookState.genericCrazySDK && hookState.unityGameInstance);
    }

    function attemptHooks() {
        hookAttempts++;

        // NEW: Primary hook for the event-listener pattern
        hookCrazySDKInstance();

        // Legacy hooks
        hookCrazyGamesSDK();
        hookConstructSDK();
        hookCrazygamesAds();
        hookGenericCrazySDK();
        hookUnitySendMessage();

        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'); }
    }

    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');
    }

    function initialize() {
        log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
        log('ZeroAd v4.4.0 - Full CrazySDK Instance & Event Support');
        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);
    }

    initialize();

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

})();