Gamee Score Modifier

提交你想要的 Gamee 分数

目前為 2025-03-03 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Gamee Score Modifier
// @version      1.3.1
// @description  提交你想要的 Gamee 分数
// @author       People11
// @match        https://prizes.gamee.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @namespace    https://gf.qytechs.cn/users/1143233
// @require      https://update.gf.qytechs.cn/scripts/490306/1345896/Mini%20Md5.js
// ==/UserScript==

(function() {
    'use strict';
    let lastData = null, authToken = null, uuid = null, isSubmitting = false;

    // 注入样式
    GM_addStyle(`
        #g-badge{position:fixed;bottom:10px;right:10px;color:#fff;padding:5px 10px;border-radius:5px;font-size:12px;z-index:9999;cursor:pointer}
        #g-badge.r{background:#f44336}
        #g-badge.y{background:#FFC107}
        #g-badge.g{background:#4CAF50}
        #g-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);z-index:9999}
        #g-dialog{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:#fff;padding:20px;border-radius:5px;box-shadow:0 0 10px rgba(0,0,0,.5);z-index:10000;width:500px;max-height:80vh;overflow-y:auto}
        #g-dialog h2{margin-bottom:15px}
        #g-dialog input,#g-dialog textarea{width:100%;padding:8px;box-sizing:border-box;margin:5px 0}
        #g-dialog textarea{height:150px;font-family:monospace}
        #g-dialog label{display:block;margin-top:15px;font-weight:700}
        #g-dialog .result{margin-top:15px;padding:10px;background:#f5f5f5;border-radius:5px;border:1px solid #ddd}
        .g-btn{padding:8px 16px;color:#fff;border:none;border-radius:4px;cursor:pointer}
        .g-btn.preview{display:block;width:100%;margin-top:15px;background:#2196F3}
        .g-btns{display:flex;justify-content:space-between;margin-top:15px}
        .g-btn.submit{background:#4CAF50;flex:1;margin-right:10px}
        .g-btn.cancel{background:#f44336;flex:1}
    `);

    // 工具函数
    const tools = {
        checksum: (score, time, url, state, id) =>
            shenchanran_md5(`${score}:${time}:${url}:${state || ""}:${id}:crmjbjm3lczhlgnek9uaxz2l9svlfjw14npauhen`),
        uuid: () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
            const r = Math.random() * 16 | 0;
            return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        }),
        time: () => {
            const d = new Date(),
                  o = d.getTimezoneOffset(),
                  z = o <= 0 ? '+' : '-',
                  h = String(Math.abs(Math.floor(o / 60))).padStart(2, '0'),
                  m = String(Math.abs(o % 60)).padStart(2, '0');
            return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}T${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}:${String(d.getSeconds()).padStart(2,'0')}${z}${h}:${m}`;
        },
        nextId: () => {
            let max = localStorage.getItem('gsm_maxId');
            if (!max && lastData?.metadata?.gameplayId) max = lastData.metadata.gameplayId;
            max = max ? parseInt(max, 10) : 555;
            localStorage.setItem('gsm_maxId', (max + 1).toString());
            return max + 1;
        },
        cookie: name => document.cookie.split(';')
            .map(c => c.trim())
            .find(c => c.startsWith(name + '='))
            ?.substring(name.length + 1) || null
    };

    // 设置网络捕获
    function setupCapture() {
        try {
            authToken = tools.cookie('authentication');
            if (authToken) authToken = "Bearer " + authToken;
            uuid = tools.cookie('uuid');
        } catch (e) {}

        // 拦截XHR
        const xhrOpen = XMLHttpRequest.prototype.open;
        const xhrSend = XMLHttpRequest.prototype.send;

        XMLHttpRequest.prototype.open = function(m, u) {
            this._url = u;
            return xhrOpen.apply(this, arguments);
        };

        XMLHttpRequest.prototype.send = function(b) {
            if (this._url?.includes('api.gamee.com') && !isSubmitting && b && typeof b === 'string') {
                try {
                    const d = JSON.parse(b);
                    if (d.method === 'game.saveWebGameplay' && d.params?.gameplayData) {
                        lastData = d.params.gameplayData;
                        updateBadge();
                    }
                } catch (e) {}
            }
            return xhrSend.apply(this, arguments);
        };

        // 拦截fetch
        const origFetch = window.fetch;
        window.fetch = function(i, init) {
            if (i?.includes?.('api.gamee.com') && !isSubmitting && init?.body && typeof init.body === 'string') {
                try {
                    const d = JSON.parse(init.body);
                    if (d.method === 'game.saveWebGameplay' && d.params?.gameplayData) {
                        lastData = d.params.gameplayData;
                        updateBadge();
                    }
                } catch (e) {}
            }
            return origFetch.apply(this, arguments);
        };
    }

    // UI函数
    function addBadge() {
        const b = document.getElementById('g-badge') || document.createElement('div');
        b.id = 'g-badge';
        b.className = 'r';
        b.textContent = '未就绪';
        b.title = '点击打开分数修改器';
        b.addEventListener('click', openDialog);
        document.body.appendChild(b);
        updateBadge();
    }

    function updateBadge() {
        const b = document.getElementById('g-badge');
        if (!b) return;

        if (!authToken || !uuid) {
            b.className = 'r';
            b.textContent = '未就绪';
        } else if (lastData) {
            b.className = 'g';
            b.textContent = `已捕获: ${lastData.gameId} (${lastData.score})`;
        } else {
            b.className = 'y';
            b.textContent = '已就绪,未捕获';
        }
    }

    function openDialog() {
        if (!authToken || !uuid) {
            alert('未找到认证信息,请确保已登录(不可用)并刷新页面');
            return;
        }

        if (!lastData) {
            alert('尚未捕获到分数,请先玩一次游戏并提交分数');
            return;
        }

        // 创建UI元素
        const overlay = document.createElement('div');
        overlay.id = 'g-overlay';

        const dialog = document.createElement('div');
        dialog.id = 'g-dialog';
        dialog.innerHTML = `
            <h2>修改游戏分数</h2>
            <div>
                <p><strong>游戏ID:</strong> ${lastData.gameId}</p>
                <p><strong>当前分数:</strong> ${lastData.score}</p>
                <p><strong>当前时长:</strong> ${lastData.playTime} 秒</p>
            </div>
            <label>目标分数:</label>
            <input type="number" id="g-score" value="${lastData.score}">
            <div class="result" id="g-result" style="display:none"></div>
            <button class="g-btn preview" id="g-preview">预览修改结果</button>
            ${lastData.gameStateData ? '<label>其他数据:</label><textarea id="g-state"></textarea>' : ''}
            <div class="g-btns">
                <button class="g-btn submit" id="g-submit">提交修改后的分数</button>
                <button class="g-btn cancel" id="g-cancel">取消</button>
            </div>
        `;

        document.body.appendChild(overlay);
        document.body.appendChild(dialog);

        // 如果有游戏状态数据,填充文本框
        if (lastData.gameStateData) {
            try {
                document.getElementById('g-state').value = JSON.stringify(JSON.parse(lastData.gameStateData), null, 2);
            } catch (e) {
                document.getElementById('g-state').value = lastData.gameStateData;
            }
        }

        // 添加事件监听
        document.getElementById('g-preview').addEventListener('click', previewScore);
        document.getElementById('g-submit').addEventListener('click', submitScore);
        document.getElementById('g-cancel').addEventListener('click', () => {
            document.body.removeChild(dialog);
            document.body.removeChild(overlay);
        });
    }

    function previewScore() {
        const score = parseInt(document.getElementById('g-score').value, 10);
        if (isNaN(score) || score <= 0) {
            alert('请输入有效的分数值');
            return;
        }

        const mult = score / lastData.score;
        const time = Math.round(lastData.playTime * mult);
        const id = tools.uuid();
        const state = document.getElementById('g-state')?.value || lastData.gameStateData;
        const checksum = tools.checksum(score, time, lastData.gameUrl, state, id);

        document.getElementById('g-result').innerHTML = `
            <p><strong>修改后分数:</strong> ${score} (${mult.toFixed(2)}倍)</p>
            <p><strong>修改后时长:</strong> ${time} 秒</p>
            <p><strong>UUID:</strong> ${id}</p>
            <p><strong>Checksum:</strong> ${checksum}</p>
        `;
        document.getElementById('g-result').style.display = 'block';
    }

    function submitScore() {
        const score = parseInt(document.getElementById('g-score').value, 10);
        if (isNaN(score) || score <= 0) {
            alert('请输入有效的分数值');
            return;
        }

        const mult = score / lastData.score;
        const time = Math.round(lastData.playTime * mult);
        const newUuid = tools.uuid();
        const newTime = tools.time();
        const newId = tools.nextId();
        let state = lastData.gameStateData;

        // 检查状态数据
        if (document.getElementById('g-state')) {
            try {
                state = document.getElementById('g-state').value;
                JSON.parse(state); // 验证JSON
            } catch (e) {
                alert('游戏状态数据不是有效的JSON格式');
                return;
            }
        }

        // 修改的游戏数据
        const modData = {
            ...lastData,
            score: score,
            playTime: time,
            uuid: newUuid,
            createdTime: newTime,
            gameStateData: state,
            metadata: {
                ...(lastData.metadata || {}),
                gameplayId: newId
            }
        };

        // 计算新校验和
        modData.checksum = tools.checksum(score, time, modData.gameUrl, state, newUuid);

        isSubmitting = true;

        GM_xmlhttpRequest({
            method: "POST",
            url: "https://api.gamee.com/",
            headers: {
                "Content-Type": "text/plain;charset=UTF-8",
                "Authorization": authToken,
                "X-Install-UUID": uuid,
                "X-Bot-Header": "gamee",
                "Origin": "https://prizes.gamee.com",
                "Referer": "https://prizes.gamee.com/",
                "User-Agent": navigator.userAgent
            },
            data: JSON.stringify({
                jsonrpc: "2.0",
                id: "game.saveWebGameplay",
                method: "game.saveWebGameplay",
                params: { gameplayData: modData }
            }),
            onload: function(response) {
                try {
                    const result = JSON.parse(response.responseText);
                    if (result.result) {
                        alert('分数修改成功!');
                        window.location.reload();
                    } else {
                        alert('分数修改失败:' + JSON.stringify(result.error || '未知错误'));
                    }
                } catch (e) {
                    alert('解析响应失败:' + e.message);
                }
                isSubmitting = false;
            },
            onerror: function(error) {
                alert('请求出错:' + error.message);
                isSubmitting = false;
            }
        });

        // 关闭对话框
        document.body.removeChild(document.getElementById('g-dialog'));
        document.body.removeChild(document.getElementById('g-overlay'));
    }

    // 初始化
    (document.readyState === 'loading') ?
        document.addEventListener('DOMContentLoaded', () => { setupCapture(); addBadge(); }) :
        (setupCapture(), addBadge());
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址