Size
4.2 KB
Version
1.2.5
Created
Nov 7, 2025
Updated
about 1 month ago
1// ==UserScript==
2// @name Gpop.io Autoplayer
3// @description Automatically plays notes in Gpop.io rhythm game with configurable timing
4// @version 1.2.5
5// @match https://gpop.io/play/*
6// @icon https://gpop.io/icon.ico?v=1.16.40
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 const AUTOPLAYER_INTERVAL = 1;
12 const HIT_OFFSET = -0.010;
13 const HIT_WINDOW_PAST = 0.050;
14
15 console.log('Gpop.io Autoplayer v1.2.4 injected...');
16
17 let autoplayerLoop = null;
18 let isAutoplayerOn = false;
19 let toggleButton = null;
20
21 function cleanupNoteState() {
22 if (typeof unsafeWindow._$W === 'undefined' || !unsafeWindow._$W._$2n) return;
23 for (const note of unsafeWindow._$W._$2n) {
24 if (note.handledByBot) delete note.handledByBot;
25 }
26 console.log('Autoplayer state cleaned.');
27 }
28
29 function startAutoplayer() {
30 if (isAutoplayerOn) return;
31 cleanupNoteState();
32
33 autoplayerLoop = setInterval(() => {
34 if (typeof unsafeWindow._$W === 'undefined' || unsafeWindow._$W === null) return;
35
36 const currentTime = unsafeWindow._$W._$ad();
37 if (typeof currentTime !== 'number') return;
38
39 const activeNotes = unsafeWindow._$W._$2n;
40 if (!activeNotes || !Array.isArray(activeNotes)) return;
41
42 for (const note of activeNotes) {
43 const noteData = note.notedata;
44
45 if (!noteData || noteData._$aP || note.handledByBot) {
46 continue;
47 }
48
49 const noteTime = noteData.time;
50 const noteKey = noteData.key;
51 const noteType = noteData.type;
52
53 const isHittable = (currentTime >= noteTime + HIT_OFFSET) && (currentTime <= noteTime + HIT_WINDOW_PAST);
54
55 if (isHittable) {
56 note.handledByBot = true;
57 unsafeWindow._$W._$q(noteKey);
58
59 if (noteType === 0) {
60 unsafeWindow._$W._$9B(noteKey);
61 } else if (noteType === 1) {
62 const holdDurationMs = noteData._$ak * 1000;
63 setTimeout(() => {
64 if (!isAutoplayerOn) return;
65 unsafeWindow._$W._$9B(noteKey);
66 }, holdDurationMs);
67 }
68 }
69 }
70 }, AUTOPLAYER_INTERVAL);
71
72 isAutoplayerOn = true;
73 toggleButton.textContent = 'Autoplayer ON';
74 toggleButton.style.backgroundColor = '#4CAF50';
75 console.log('Autoplayer started.');
76 }
77
78 function stopAutoplayer() {
79 if (!isAutoplayerOn) return;
80 clearInterval(autoplayerLoop);
81 isAutoplayerOn = false;
82 toggleButton.textContent = 'Autoplayer OFF';
83 toggleButton.style.backgroundColor = '#f44336';
84 console.log('Autoplayer stopped.');
85 }
86
87 function initialize() {
88 toggleButton = document.createElement('button');
89 toggleButton.textContent = 'Autoplayer OFF';
90 toggleButton.style.position = 'fixed';
91 toggleButton.style.bottom = '10px';
92 toggleButton.style.right = '10px';
93 toggleButton.style.zIndex = '9999';
94 toggleButton.style.border = 'none';
95 toggleButton.style.padding = '10px 20px';
96 toggleButton.style.cursor = 'pointer';
97 toggleButton.style.backgroundColor = '#f44336';
98 toggleButton.style.color = 'white';
99 toggleButton.style.borderRadius = '5px';
100 toggleButton.style.fontSize = '14px';
101 toggleButton.style.fontWeight = 'bold';
102 document.body.appendChild(toggleButton);
103
104 toggleButton.addEventListener('click', () => {
105 if (isAutoplayerOn) {
106 stopAutoplayer();
107 } else {
108 startAutoplayer();
109 }
110 });
111
112 startAutoplayer();
113 }
114
115 function init() {
116 const waitForGame = setInterval(() => {
117 if (typeof unsafeWindow._$W !== 'undefined' && unsafeWindow._$W !== null) {
118 clearInterval(waitForGame);
119 console.log('Game object `unsafeWindow._$W` found! Initializing autoplayer.');
120 initialize();
121 }
122 }, 500);
123 }
124
125 // Start the extension
126 init();
127
128})();