Nevzyn

Untitled

Oct 22nd, 2025
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 50.04 KB | None | 0 0
  1. // =======================================================================================
  2. // SISTEMA AVANÇADO DE MAPEAMENTO DE BOTÕES v2.0
  3. // Recursos: Persistência por jogo, Anti-detecção, Otimização, Redimensionamento
  4. // =======================================================================================
  5.  
  6. class AdvancedButtonMapper {
  7. constructor() {
  8. this.mappedButtons = [];
  9. this.isDragging = false;
  10. this.isResizing = false;
  11. this.editMode = false;
  12. this.enabled = true;
  13. this.currentGameId = null;
  14.  
  15. // Configurações de segurança e performance
  16. this.settings = {
  17. // Visual
  18. opacity: 0.7,
  19. showLabels: true,
  20. buttonColor: '#4CAF50',
  21. textColor: '#FFFFFF',
  22. borderRadius: 8,
  23.  
  24. // Segurança (Anti-detecção)
  25. stealthMode: true,
  26. randomClickDelay: true,
  27. minDelay: 50,
  28. maxDelay: 150,
  29. hideOnGameFocus: false,
  30. humanizedClicks: true,
  31.  
  32. // Performance
  33. updateInterval: 5000, // Verifica elementos a cada 5s
  34. maxButtons: 20, // Limite de botões
  35. enableDebounce: true,
  36.  
  37. // Dimensões padrão
  38. defaultWidth: 100,
  39. defaultHeight: 40,
  40. minWidth: 50,
  41. minHeight: 30,
  42. maxWidth: 300,
  43. maxHeight: 150
  44. };
  45.  
  46. this.init();
  47. }
  48.  
  49. // ==================== INICIALIZAÇÃO ====================
  50.  
  51. init() {
  52. this.currentGameId = this.getGameId();
  53. this.createStyles();
  54. this.createControlPanel();
  55. this.loadSettings();
  56. this.startPerformanceMonitor();
  57. this.setupAutoReconnect();
  58. this.injectStealthMode();
  59.  
  60. console.log(`🎮 Mapeador de Botões v2.0 carregado`);
  61. console.log(`📍 Jogo ID: ${this.currentGameId}`);
  62. }
  63.  
  64. // Detectar ID do jogo atual
  65. getGameId() {
  66. // Método 1: URL do Roblox
  67. const urlMatch = window.location.href.match(/games\/(\d+)/);
  68. if (urlMatch) return `roblox_${urlMatch[1]}`;
  69.  
  70. // Método 2: Título da página
  71. const title = document.title.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 30);
  72. if (title) return `game_${title}`;
  73.  
  74. // Método 3: Hash da URL
  75. const urlHash = this.hashCode(window.location.href);
  76. return `hash_${urlHash}`;
  77. }
  78.  
  79. // Gerar hash simples
  80. hashCode(str) {
  81. let hash = 0;
  82. for (let i = 0; i < str.length; i++) {
  83. const char = str.charCodeAt(i);
  84. hash = ((hash << 5) - hash) + char;
  85. hash = hash & hash;
  86. }
  87. return Math.abs(hash);
  88. }
  89.  
  90. // ==================== ESTILOS CSS ====================
  91.  
  92. createStyles() {
  93. const style = document.createElement('style');
  94. style.id = 'button-mapper-styles';
  95. style.textContent = `
  96. /* Botões Mapeados */
  97. .mapped-button {
  98. position: fixed;
  99. background: ${this.settings.buttonColor};
  100. color: ${this.settings.textColor};
  101. border: 2px solid rgba(255,255,255,0.5);
  102. border-radius: ${this.settings.borderRadius}px;
  103. cursor: pointer;
  104. opacity: ${this.settings.opacity};
  105. z-index: 999998;
  106. font-family: 'Segoe UI', Arial, sans-serif;
  107. font-weight: bold;
  108. font-size: 14px;
  109. transition: all 0.15s ease;
  110. user-select: none;
  111. box-shadow: 0 2px 8px rgba(0,0,0,0.3);
  112. display: flex;
  113. align-items: center;
  114. justify-content: center;
  115. text-align: center;
  116. overflow: hidden;
  117. white-space: nowrap;
  118. text-overflow: ellipsis;
  119. padding: 5px;
  120. }
  121.  
  122. .mapped-button:hover {
  123. opacity: 1;
  124. transform: scale(1.02);
  125. box-shadow: 0 4px 12px rgba(0,0,0,0.4);
  126. }
  127.  
  128. .mapped-button:active {
  129. transform: scale(0.98);
  130. box-shadow: 0 1px 4px rgba(0,0,0,0.3);
  131. }
  132.  
  133. .mapped-button.dragging {
  134. cursor: move !important;
  135. opacity: 0.6;
  136. border-color: #2196F3;
  137. }
  138.  
  139. .mapped-button.resizing {
  140. cursor: nwse-resize !important;
  141. border-color: #ff9800;
  142. }
  143.  
  144. .mapped-button.edit-mode {
  145. border-color: #ff9800;
  146. animation: pulse-border 2s infinite;
  147. }
  148.  
  149. .mapped-button.disabled {
  150. opacity: 0.3;
  151. cursor: not-allowed;
  152. filter: grayscale(100%);
  153. }
  154.  
  155. .mapped-button.clicked {
  156. animation: click-feedback 0.3s ease;
  157. }
  158.  
  159. @keyframes pulse-border {
  160. 0%, 100% { box-shadow: 0 0 10px rgba(255,152,0,0.5); }
  161. 50% { box-shadow: 0 0 20px rgba(255,152,0,0.8); }
  162. }
  163.  
  164. @keyframes click-feedback {
  165. 0% { background: #2196F3; transform: scale(0.95); }
  166. 50% { background: #64B5F6; transform: scale(1.05); }
  167. 100% { background: ${this.settings.buttonColor}; transform: scale(1); }
  168. }
  169.  
  170. /* Alça de redimensionamento */
  171. .resize-handle {
  172. position: absolute;
  173. bottom: 0;
  174. right: 0;
  175. width: 16px;
  176. height: 16px;
  177. cursor: nwse-resize;
  178. opacity: 0;
  179. transition: opacity 0.2s;
  180. }
  181.  
  182. .resize-handle::after {
  183. content: '⋰';
  184. position: absolute;
  185. bottom: 2px;
  186. right: 2px;
  187. color: white;
  188. font-size: 12px;
  189. text-shadow: 0 1px 2px rgba(0,0,0,0.5);
  190. }
  191.  
  192. .mapped-button.edit-mode .resize-handle {
  193. opacity: 1;
  194. }
  195.  
  196. .resize-handle:hover {
  197. opacity: 1 !important;
  198. }
  199.  
  200. /* Painel de Controle */
  201. .control-panel {
  202. position: fixed;
  203. top: 10px;
  204. right: 10px;
  205. background: linear-gradient(135deg, rgba(0,0,0,0.95), rgba(30,30,30,0.95));
  206. color: white;
  207. padding: 15px;
  208. border-radius: 12px;
  209. z-index: 999999;
  210. font-family: 'Segoe UI', Arial, sans-serif;
  211. min-width: 280px;
  212. box-shadow: 0 8px 32px rgba(0,0,0,0.5);
  213. backdrop-filter: blur(10px);
  214. border: 1px solid rgba(255,255,255,0.1);
  215. }
  216.  
  217. .control-panel.minimized {
  218. min-width: auto;
  219. padding: 10px;
  220. }
  221.  
  222. .control-panel.minimized .panel-content {
  223. display: none;
  224. }
  225.  
  226. .panel-header {
  227. display: flex;
  228. justify-content: space-between;
  229. align-items: center;
  230. margin-bottom: 10px;
  231. padding-bottom: 10px;
  232. border-bottom: 1px solid rgba(255,255,255,0.2);
  233. }
  234.  
  235. .panel-header h3 {
  236. margin: 0;
  237. font-size: 16px;
  238. display: flex;
  239. align-items: center;
  240. gap: 8px;
  241. }
  242.  
  243. .minimize-btn {
  244. background: rgba(255,255,255,0.1);
  245. border: none;
  246. color: white;
  247. width: 24px;
  248. height: 24px;
  249. border-radius: 4px;
  250. cursor: pointer;
  251. font-size: 16px;
  252. display: flex;
  253. align-items: center;
  254. justify-content: center;
  255. transition: all 0.2s;
  256. }
  257.  
  258. .minimize-btn:hover {
  259. background: rgba(255,255,255,0.2);
  260. }
  261.  
  262. .control-panel button {
  263. width: 100%;
  264. margin: 5px 0;
  265. padding: 10px;
  266. border: none;
  267. border-radius: 6px;
  268. cursor: pointer;
  269. font-weight: 600;
  270. font-size: 13px;
  271. transition: all 0.2s;
  272. display: flex;
  273. align-items: center;
  274. justify-content: center;
  275. gap: 6px;
  276. }
  277.  
  278. .control-panel button:hover {
  279. transform: translateY(-1px);
  280. box-shadow: 0 4px 8px rgba(0,0,0,0.3);
  281. }
  282.  
  283. .control-panel button:active {
  284. transform: translateY(0);
  285. }
  286.  
  287. .btn-add { background: linear-gradient(135deg, #4CAF50, #45a049); color: white; }
  288. .btn-edit { background: linear-gradient(135deg, #2196F3, #1976D2); color: white; }
  289. .btn-toggle-enabled { background: linear-gradient(135deg, #9C27B0, #7B1FA2); color: white; }
  290. .btn-clear { background: linear-gradient(135deg, #f44336, #d32f2f); color: white; }
  291. .btn-save { background: linear-gradient(135deg, #ff9800, #f57c00); color: white; }
  292. .btn-export { background: linear-gradient(135deg, #00BCD4, #0097A7); color: white; }
  293. .btn-import { background: linear-gradient(135deg, #009688, #00796B); color: white; }
  294.  
  295. /* Slider e controles */
  296. .control-group {
  297. margin: 10px 0;
  298. padding: 10px;
  299. background: rgba(255,255,255,0.05);
  300. border-radius: 6px;
  301. }
  302.  
  303. .control-group label {
  304. display: block;
  305. margin-bottom: 5px;
  306. font-size: 12px;
  307. color: #bbb;
  308. font-weight: 600;
  309. }
  310.  
  311. .control-group input[type="range"] {
  312. width: 100%;
  313. margin: 5px 0;
  314. }
  315.  
  316. .control-group input[type="color"] {
  317. width: 100%;
  318. height: 35px;
  319. border: none;
  320. border-radius: 4px;
  321. cursor: pointer;
  322. }
  323.  
  324. .stats {
  325. margin-top: 10px;
  326. padding: 10px;
  327. background: rgba(0,0,0,0.3);
  328. border-radius: 6px;
  329. font-size: 11px;
  330. line-height: 1.6;
  331. }
  332.  
  333. .stats-row {
  334. display: flex;
  335. justify-content: space-between;
  336. margin: 3px 0;
  337. }
  338.  
  339. .stats-label {
  340. color: #999;
  341. }
  342.  
  343. .stats-value {
  344. color: #4CAF50;
  345. font-weight: bold;
  346. }
  347.  
  348. /* Overlay de seleção */
  349. .selector-overlay {
  350. position: fixed;
  351. top: 0;
  352. left: 0;
  353. width: 100%;
  354. height: 100%;
  355. background: rgba(0,0,0,0.7);
  356. z-index: 999997;
  357. cursor: crosshair;
  358. backdrop-filter: blur(2px);
  359. }
  360.  
  361. .selector-hint {
  362. position: fixed;
  363. top: 50%;
  364. left: 50%;
  365. transform: translate(-50%, -50%);
  366. background: white;
  367. padding: 30px;
  368. border-radius: 12px;
  369. font-size: 18px;
  370. z-index: 999998;
  371. text-align: center;
  372. box-shadow: 0 8px 32px rgba(0,0,0,0.5);
  373. max-width: 400px;
  374. }
  375.  
  376. .selector-hint h3 {
  377. margin: 0 0 10px 0;
  378. color: #333;
  379. }
  380.  
  381. .selector-hint p {
  382. margin: 5px 0;
  383. color: #666;
  384. font-size: 14px;
  385. }
  386.  
  387. .highlight-element {
  388. outline: 3px solid #ff9800 !important;
  389. outline-offset: 3px;
  390. position: relative;
  391. box-shadow: 0 0 20px rgba(255,152,0,0.5) !important;
  392. }
  393.  
  394. /* Toast de notificação */
  395. .toast-notification {
  396. position: fixed;
  397. bottom: 20px;
  398. right: 20px;
  399. background: rgba(0,0,0,0.9);
  400. color: white;
  401. padding: 15px 20px;
  402. border-radius: 8px;
  403. z-index: 1000000;
  404. animation: slideIn 0.3s ease;
  405. box-shadow: 0 4px 16px rgba(0,0,0,0.5);
  406. }
  407.  
  408. @keyframes slideIn {
  409. from {
  410. transform: translateX(400px);
  411. opacity: 0;
  412. }
  413. to {
  414. transform: translateX(0);
  415. opacity: 1;
  416. }
  417. }
  418.  
  419. /* Modo Stealth */
  420. .stealth-mode .mapped-button {
  421. transition: opacity 0.3s;
  422. }
  423.  
  424. .stealth-mode .mapped-button:not(:hover) {
  425. opacity: 0.1;
  426. }
  427. `;
  428. document.head.appendChild(style);
  429. }
  430.  
  431. // ==================== PAINEL DE CONTROLE ====================
  432.  
  433. createControlPanel() {
  434. const panel = document.createElement('div');
  435. panel.className = 'control-panel';
  436. panel.id = 'button-mapper-panel';
  437. panel.innerHTML = `
  438. <div class="panel-header">
  439. <h3>
  440. <span>🎮</span>
  441. <span>Mapeador v2.0</span>
  442. </h3>
  443. <button class="minimize-btn" onclick="buttonMapper.togglePanel()">−</button>
  444. </div>
  445.  
  446. <div class="panel-content">
  447. <!-- Botões principais -->
  448. <button class="btn-add" onclick="buttonMapper.addButton()">
  449. ➕ Adicionar Botão
  450. </button>
  451.  
  452. <button class="btn-edit" onclick="buttonMapper.toggleEditMode()">
  453. ✏️ <span id="edit-mode-text">Modo Edição: OFF</span>
  454. </button>
  455.  
  456. <button class="btn-toggle-enabled" onclick="buttonMapper.toggleEnabled()">
  457. <span id="enabled-text">⚡ Mapeamento: ON</span>
  458. </button>
  459.  
  460. <!-- Controles visuais -->
  461. <div class="control-group">
  462. <label>🎨 Cor dos Botões</label>
  463. <input type="color" id="button-color" value="#4CAF50"
  464. onchange="buttonMapper.updateButtonColor(this.value)">
  465. </div>
  466.  
  467. <div class="control-group">
  468. <label>👁️ Opacidade: <span id="opacity-value">70%</span></label>
  469. <input type="range" min="10" max="100" value="70"
  470. oninput="buttonMapper.updateOpacity(this.value)">
  471. </div>
  472.  
  473. <div class="control-group">
  474. <label>⭕ Arredondamento: <span id="radius-value">8px</span></label>
  475. <input type="range" min="0" max="50" value="8"
  476. oninput="buttonMapper.updateBorderRadius(this.value)">
  477. </div>
  478.  
  479. <!-- Segurança -->
  480. <div class="control-group">
  481. <label style="display: flex; align-items: center; gap: 8px;">
  482. <input type="checkbox" id="stealth-mode" checked
  483. onchange="buttonMapper.toggleStealthMode(this.checked)">
  484. 🕶️ Modo Furtivo (Anti-detecção)
  485. </label>
  486.  
  487. <label style="display: flex; align-items: center; gap: 8px; margin-top: 8px;">
  488. <input type="checkbox" id="humanized-clicks" checked
  489. onchange="buttonMapper.toggleHumanizedClicks(this.checked)">
  490. 🤖 Cliques Humanizados
  491. </label>
  492. </div>
  493.  
  494. <!-- Gerenciamento -->
  495. <button class="btn-save" onclick="buttonMapper.saveSettings()">
  496. 💾 Salvar Mapeamento
  497. </button>
  498.  
  499. <button class="btn-export" onclick="buttonMapper.exportSettings()">
  500. 📤 Exportar
  501. </button>
  502.  
  503. <button class="btn-import" onclick="buttonMapper.importSettings()">
  504. 📥 Importar
  505. </button>
  506.  
  507. <button class="btn-clear" onclick="buttonMapper.clearAll()">
  508. 🗑️ Limpar Tudo
  509. </button>
  510.  
  511. <!-- Estatísticas -->
  512. <div class="stats">
  513. <div class="stats-row">
  514. <span class="stats-label">Jogo Atual:</span>
  515. <span class="stats-value" id="current-game">${this.currentGameId}</span>
  516. </div>
  517. <div class="stats-row">
  518. <span class="stats-label">Botões Mapeados:</span>
  519. <span class="stats-value" id="button-count">0</span>
  520. </div>
  521. <div class="stats-row">
  522. <span class="stats-label">Status:</span>
  523. <span class="stats-value" id="mapper-status">✅ Ativo</span>
  524. </div>
  525. <div class="stats-row">
  526. <span class="stats-label">Performance:</span>
  527. <span class="stats-value" id="performance-status">⚡ Ótimo</span>
  528. </div>
  529. </div>
  530. </div>
  531. `;
  532. document.body.appendChild(panel);
  533.  
  534. // Tornar painel arrastável
  535. this.makePanelDraggable(panel);
  536. }
  537.  
  538. // Minimizar/expandir painel
  539. togglePanel() {
  540. const panel = document.getElementById('button-mapper-panel');
  541. const btn = panel.querySelector('.minimize-btn');
  542. panel.classList.toggle('minimized');
  543. btn.textContent = panel.classList.contains('minimized') ? '+' : '−';
  544. }
  545.  
  546. // Tornar painel arrastável
  547. makePanelDraggable(panel) {
  548. const header = panel.querySelector('.panel-header h3');
  549. let isDragging = false;
  550. let currentX, currentY, initialX, initialY;
  551.  
  552. header.style.cursor = 'move';
  553.  
  554. header.addEventListener('mousedown', (e) => {
  555. isDragging = true;
  556. initialX = e.clientX - panel.offsetLeft;
  557. initialY = e.clientY - panel.offsetTop;
  558. });
  559.  
  560. document.addEventListener('mousemove', (e) => {
  561. if (isDragging) {
  562. e.preventDefault();
  563. currentX = e.clientX - initialX;
  564. currentY = e.clientY - initialY;
  565. panel.style.left = currentX + 'px';
  566. panel.style.top = currentY + 'px';
  567. panel.style.right = 'auto';
  568. }
  569. });
  570.  
  571. document.addEventListener('mouseup', () => {
  572. isDragging = false;
  573. });
  574. }
  575.  
  576. // ==================== ADICIONAR BOTÃO ====================
  577.  
  578. async addButton() {
  579. if (this.mappedButtons.length >= this.settings.maxButtons) {
  580. this.showToast(`❌ Limite de ${this.settings.maxButtons} botões atingido!`, 'error');
  581. return;
  582. }
  583.  
  584. const label = prompt('📝 Digite o nome do botão:');
  585. if (!label || label.trim() === '') {
  586. this.showToast('❌ Nome inválido!', 'error');
  587. return;
  588. }
  589.  
  590. this.showToast('👆 Clique no elemento do jogo que deseja mapear...', 'info');
  591.  
  592. const targetElement = await this.selectElement();
  593. if (!targetElement) {
  594. this.showToast('❌ Seleção cancelada', 'warning');
  595. return;
  596. }
  597.  
  598. const position = {
  599. x: window.innerWidth / 2 - 50,
  600. y: window.innerHeight / 2 - 20
  601. };
  602.  
  603. const size = {
  604. width: this.settings.defaultWidth,
  605. height: this.settings.defaultHeight
  606. };
  607.  
  608. this.createMappedButton(label, targetElement, position, size);
  609. this.updateButtonCount();
  610. this.saveSettings();
  611. this.showToast(`✅ Botão "${label}" adicionado!`, 'success');
  612. }
  613.  
  614. // ==================== SELETOR DE ELEMENTO ====================
  615.  
  616. selectElement() {
  617. return new Promise((resolve) => {
  618. const overlay = document.createElement('div');
  619. overlay.className = 'selector-overlay';
  620.  
  621. const hint = document.createElement('div');
  622. hint.className = 'selector-hint';
  623. hint.innerHTML = `
  624. <h3>🎯 Selecione o Elemento</h3>
  625. <p>Mova o mouse sobre o botão do jogo</p>
  626. <p style="font-size: 12px; color: #999;">Pressione ESC para cancelar</p>
  627. `;
  628.  
  629. document.body.appendChild(overlay);
  630. document.body.appendChild(hint);
  631.  
  632. let currentHighlight = null;
  633.  
  634. const handleMouseMove = (e) => {
  635. if (currentHighlight) {
  636. currentHighlight.classList.remove('highlight-element');
  637. }
  638.  
  639. // Desabilitar temporariamente o overlay para pegar elemento abaixo
  640. overlay.style.pointerEvents = 'none';
  641. const element = document.elementFromPoint(e.clientX, e.clientY);
  642. overlay.style.pointerEvents = 'auto';
  643.  
  644. if (element && element !== overlay && element !== hint) {
  645. element.classList.add('highlight-element');
  646. currentHighlight = element;
  647.  
  648. // Mostrar info do elemento
  649. hint.innerHTML = `
  650. <h3>🎯 Elemento Detectado</h3>
  651. <p><strong>${element.tagName}</strong></p>
  652. <p style="font-size: 12px;">${element.className || 'Sem classe'}</p>
  653. <p style="font-size: 11px; color: #999;">Clique para confirmar | ESC para cancelar</p>
  654. `;
  655. }
  656. };
  657.  
  658. const handleClick = (e) => {
  659. e.preventDefault();
  660. e.stopPropagation();
  661.  
  662. overlay.style.pointerEvents = 'none';
  663. const element = document.elementFromPoint(e.clientX, e.clientY);
  664. overlay.style.pointerEvents = 'auto';
  665.  
  666. cleanup();
  667.  
  668. if (element && element !== overlay && element !== hint) {
  669. resolve(element);
  670. } else {
  671. resolve(null);
  672. }
  673. };
  674.  
  675. const handleEscape = (e) => {
  676. if (e.key === 'Escape') {
  677. cleanup();
  678. resolve(null);
  679. }
  680. };
  681.  
  682. const cleanup = () => {
  683. if (currentHighlight) {
  684. currentHighlight.classList.remove('highlight-element');
  685. }
  686. overlay.remove();
  687. hint.remove();
  688. document.removeEventListener('mousemove', handleMouseMove);
  689. document.removeEventListener('click', handleClick, true);
  690. document.removeEventListener('keydown', handleEscape);
  691. };
  692.  
  693. document.addEventListener('mousemove', handleMouseMove);
  694. document.addEventListener('click', handleClick, true);
  695. document.addEventListener('keydown', handleEscape);
  696. });
  697. }
  698.  
  699. // ==================== CRIAR BOTÃO MAPEADO ====================
  700.  
  701. createMappedButton(label, targetElement, position, size = {}) {
  702. const button = document.createElement('div');
  703. button.className = 'mapped-button';
  704. button.textContent = label;
  705. button.style.left = position.x + 'px';
  706. button.style.top = position.y + 'px';
  707. button.style.width = (size.width || this.settings.defaultWidth) + 'px';
  708. button.style.height = (size.height || this.settings.defaultHeight) + 'px';
  709.  
  710. // Criar alça de redimensionamento
  711. const resizeHandle = document.createElement('div');
  712. resizeHandle.className = 'resize-handle';
  713. button.appendChild(resizeHandle);
  714.  
  715. // Dados do botão
  716. const buttonData = {
  717. element: button,
  718. label: label,
  719. target: targetElement,
  720. targetSelector: this.getElementSelector(targetElement),
  721. position: position,
  722. size: size,
  723. clickCount: 0,
  724. lastClick: null
  725. };
  726.  
  727. // Click para acionar
  728. button.addEventListener('click', (e) => {
  729. if (!this.isDragging && !this.isResizing && !this.editMode && this.enabled) {
  730. this.triggerTargetElement(buttonData);
  731. }
  732. });
  733.  
  734. // Arrastar
  735. this.setupDragging(button, buttonData);
  736.  
  737. // Redimensionar
  738. this.setupResizing(button, resizeHandle, buttonData);
  739.  
  740. // Botão direito - Menu de contexto
  741. button.addEventListener('contextmenu', (e) => {
  742. e.preventDefault();
  743. if (this.editMode) {
  744. this.showButtonMenu(e, buttonData);
  745. }
  746. });
  747.  
  748. document.body.appendChild(button);
  749. this.mappedButtons.push(buttonData);
  750.  
  751. return button;
  752. }
  753.  
  754. // ==================== ARRASTAR BOTÃO ====================
  755.  
  756. setupDragging(button, buttonData) {
  757. let offsetX, offsetY;
  758.  
  759. button.addEventListener('mousedown', (e) => {
  760. if (this.editMode && !e.target.classList.contains('resize-handle')) {
  761. this.isDragging = true;
  762. button.classList.add('dragging');
  763. offsetX = e.clientX - button.offsetLeft;
  764. offsetY = e.clientY - button.offsetTop;
  765.  
  766. const handleMouseMove = (e) => {
  767. if (this.isDragging) {
  768. const newX = e.clientX - offsetX;
  769. const newY = e.clientY - offsetY;
  770.  
  771. // Limitar ao viewport
  772. const maxX = window.innerWidth - button.offsetWidth;
  773. const maxY = window.innerHeight - button.offsetHeight;
  774.  
  775. button.style.left = Math.max(0, Math.min(newX, maxX)) + 'px';
  776. button.style.top = Math.max(0, Math.min(newY, maxY)) + 'px';
  777.  
  778. buttonData.position.x = parseInt(button.style.left);
  779. buttonData.position.y = parseInt(button.style.top);
  780. }
  781. };
  782.  
  783. const handleMouseUp = () => {
  784. if (this.isDragging) {
  785. this.isDragging = false;
  786. button.classList.remove('dragging');
  787. this.saveSettings();
  788. document.removeEventListener('mousemove', handleMouseMove);
  789. document.removeEventListener('mouseup', handleMouseUp);
  790. }
  791. };
  792.  
  793. document.addEventListener('mousemove', handleMouseMove);
  794. document.addEventListener('mouseup', handleMouseUp);
  795. }
  796. });
  797. }
  798.  
  799. // ==================== REDIMENSIONAR BOTÃO ====================
  800.  
  801. setupResizing(button, handle, buttonData) {
  802. handle.addEventListener('mousedown', (e) => {
  803. if (this.editMode) {
  804. e.stopPropagation();
  805. this.isResizing = true;
  806. button.classList.add('resizing');
  807.  
  808. const startWidth = button.offsetWidth;
  809. const startHeight = button.offsetHeight;
  810. const startX = e.clientX;
  811. const startY = e.clientY;
  812.  
  813. const handleMouseMove = (e) => {
  814. if (this.isResizing) {
  815. const deltaX = e.clientX - startX;
  816. const deltaY = e.clientY - startY;
  817.  
  818. let newWidth = startWidth + deltaX;
  819. let newHeight = startHeight + deltaY;
  820.  
  821. // Aplicar limites
  822. newWidth = Math.max(this.settings.minWidth, Math.min(newWidth, this.settings.maxWidth));
  823. newHeight = Math.max(this.settings.minHeight, Math.min(newHeight, this.settings.maxHeight));
  824.  
  825. button.style.width = newWidth + 'px';
  826. button.style.height = newHeight + 'px';
  827.  
  828. buttonData.size = { width: newWidth, height: newHeight };
  829. }
  830. };
  831.  
  832. const handleMouseUp = () => {
  833. if (this.isResizing) {
  834. this.isResizing = false;
  835. button.classList.remove('resizing');
  836. this.saveSettings();
  837. document.removeEventListener('mousemove', handleMouseMove);
  838. document.removeEventListener('mouseup', handleMouseUp);
  839. }
  840. };
  841.  
  842. document.addEventListener('mousemove', handleMouseMove);
  843. document.addEventListener('mouseup', handleMouseUp);
  844. }
  845. });
  846. }
  847.  
  848. // ==================== MENU DE CONTEXTO ====================
  849.  
  850. showButtonMenu(e, buttonData) {
  851. const menu = document.createElement('div');
  852. menu.style.cssText = `
  853. position: fixed;
  854. left: ${e.clientX}px;
  855. top: ${e.clientY}px;
  856. background: white;
  857. border-radius: 8px;
  858. box-shadow: 0 4px 16px rgba(0,0,0,0.3);
  859. z-index: 1000000;
  860. padding: 8px;
  861. min-width: 180px;
  862. `;
  863.  
  864. menu.innerHTML = `
  865. <div style="padding: 8px 12px; cursor: pointer; border-radius: 4px;"
  866. onmouseover="this.style.background='#f0f0f0'"
  867. onmouseout="this.style.background='white'"
  868. onclick="buttonMapper.renameButton('${buttonData.label}')">
  869. ✏️ Renomear
  870. </div>
  871. <div style="padding: 8px 12px; cursor: pointer; border-radius: 4px;"
  872. onmouseover="this.style.background='#f0f0f0'"
  873. onmouseout="this.style.background='white'"
  874. onclick="buttonMapper.resetSize('${buttonData.label}')">
  875. ↔️ Resetar Tamanho
  876. </div>
  877. <div style="padding: 8px 12px; cursor: pointer; border-radius: 4px;"
  878. onmouseover="this.style.background='#f0f0f0'"
  879. onmouseout="this.style.background='white'"
  880. onclick="buttonMapper.duplicateButton('${buttonData.label}')">
  881. 📋 Duplicar
  882. </div>
  883. <hr style="margin: 4px 0; border: none; border-top: 1px solid #ddd;">
  884. <div style="padding: 8px 12px; cursor: pointer; border-radius: 4px; color: #f44336;"
  885. onmouseover="this.style.background='#ffebee'"
  886. onmouseout="this.style.background='white'"
  887. onclick="buttonMapper.deleteButton('${buttonData.label}')">
  888. 🗑️ Deletar
  889. </div>
  890. `;
  891.  
  892. document.body.appendChild(menu);
  893.  
  894. // Fechar ao clicar fora
  895. setTimeout(() => {
  896. const closeMenu = (e) => {
  897. if (!menu.contains(e.target)) {
  898. menu.remove();
  899. document.removeEventListener('click', closeMenu);
  900. }
  901. };
  902. document.addEventListener('click', closeMenu);
  903. }, 100);
  904. }
  905.  
  906. // ==================== ACIONAR ELEMENTO ALVO ====================
  907.  
  908. async triggerTargetElement(buttonData) {
  909. if (!buttonData.target || !document.contains(buttonData.target)) {
  910. // Tentar reconectar
  911. const newTarget = document.querySelector(buttonData.targetSelector);
  912. if (newTarget) {
  913. buttonData.target = newTarget;
  914. } else {
  915. this.showToast('⚠️ Elemento alvo não encontrado!', 'warning');
  916. return;
  917. }
  918. }
  919.  
  920. const element = buttonData.target;
  921.  
  922. // Feedback visual
  923. buttonData.element.classList.add('clicked');
  924. setTimeout(() => buttonData.element.classList.remove('clicked'), 300);
  925.  
  926. // Delay humanizado (anti-detecção)
  927. if (this.settings.humanizedClicks) {
  928. const delay = this.settings.minDelay + Math.random() * (this.settings.maxDelay - this.settings.minDelay);
  929. await new Promise(resolve => setTimeout(resolve, delay));
  930. }
  931.  
  932. // Simular clique humano
  933. try {
  934. const rect = element.getBoundingClientRect();
  935.  
  936. // Posição aleatória dentro do elemento (mais humano)
  937. const randomX = rect.left + (rect.width * (0.3 + Math.random() * 0.4));
  938. const randomY = rect.top + (rect.height * (0.3 + Math.random() * 0.4));
  939.  
  940. // Sequência completa de eventos (mais realista)
  941. const eventOptions = {
  942. view: window,
  943. bubbles: true,
  944. cancelable: true,
  945. clientX: randomX,
  946. clientY: randomY,
  947. button: 0
  948. };
  949.  
  950. // Mousedown -> Mouseup -> Click
  951. element.dispatchEvent(new MouseEvent('mousedown', eventOptions));
  952.  
  953. await new Promise(resolve => setTimeout(resolve, 30 + Math.random() * 50));
  954.  
  955. element.dispatchEvent(new MouseEvent('mouseup', eventOptions));
  956. element.dispatchEvent(new MouseEvent('click', eventOptions));
  957.  
  958. // Método nativo também
  959. if (element.click) {
  960. element.click();
  961. }
  962.  
  963. // Estatísticas
  964. buttonData.clickCount++;
  965. buttonData.lastClick = new Date();
  966.  
  967. console.log(`✅ Clique enviado para: ${buttonData.label}`);
  968.  
  969. } catch (error) {
  970. console.error('❌ Erro ao acionar botão:', error);
  971. this.showToast('❌ Erro ao acionar botão!', 'error');
  972. }
  973. }
  974.  
  975. // ==================== FUNÇÕES DO MENU ====================
  976.  
  977. renameButton(label) {
  978. const buttonData = this.mappedButtons.find(b => b.label === label);
  979. if (!buttonData) return;
  980.  
  981. const newLabel = prompt('Digite o novo nome:', label);
  982. if (newLabel && newLabel.trim()) {
  983. buttonData.label = newLabel;
  984. buttonData.element.textContent = newLabel;
  985. this.saveSettings();
  986. this.showToast('✅ Botão renomeado!', 'success');
  987. }
  988. }
  989.  
  990. resetSize(label) {
  991. const buttonData = this.mappedButtons.find(b => b.label === label);
  992. if (!buttonData) return;
  993.  
  994. buttonData.element.style.width = this.settings.defaultWidth + 'px';
  995. buttonData.element.style.height = this.settings.defaultHeight + 'px';
  996. buttonData.size = { width: this.settings.defaultWidth, height: this.settings.defaultHeight };
  997. this.saveSettings();
  998. this.showToast('✅ Tamanho resetado!', 'success');
  999. }
  1000.  
  1001. duplicateButton(label) {
  1002. const buttonData = this.mappedButtons.find(b => b.label === label);
  1003. if (!buttonData) return;
  1004.  
  1005. const newPosition = {
  1006. x: buttonData.position.x + 20,
  1007. y: buttonData.position.y + 20
  1008. };
  1009.  
  1010. this.createMappedButton(
  1011. buttonData.label + ' (cópia)',
  1012. buttonData.target,
  1013. newPosition,
  1014. buttonData.size
  1015. );
  1016.  
  1017. this.updateButtonCount();
  1018. this.saveSettings();
  1019. this.showToast('✅ Botão duplicado!', 'success');
  1020. }
  1021.  
  1022. deleteButton(label) {
  1023. const buttonData = this.mappedButtons.find(b => b.label === label);
  1024. if (!buttonData) return;
  1025.  
  1026. if (confirm(`Deletar "${label}"?`)) {
  1027. buttonData.element.remove();
  1028. this.mappedButtons = this.mappedButtons.filter(b => b.label !== label);
  1029. this.updateButtonCount();
  1030. this.saveSettings();
  1031. this.showToast('🗑️ Botão deletado!', 'success');
  1032. }
  1033. }
  1034.  
  1035. // ==================== CONTROLES ====================
  1036.  
  1037. toggleEditMode() {
  1038. this.editMode = !this.editMode;
  1039. document.getElementById('edit-mode-text').textContent = `Modo Edição: ${this.editMode ? 'ON' : 'OFF'}`;
  1040.  
  1041. const editBtn = document.querySelector('.btn-edit');
  1042. editBtn.style.background = this.editMode
  1043. ? 'linear-gradient(135deg, #ff9800, #f57c00)'
  1044. : 'linear-gradient(135deg, #2196F3, #1976D2)';
  1045.  
  1046. this.mappedButtons.forEach(btn => {
  1047. if (this.editMode) {
  1048. btn.element.classList.add('edit-mode');
  1049. } else {
  1050. btn.element.classList.remove('edit-mode');
  1051. }
  1052. });
  1053.  
  1054. this.showToast(this.editMode ? '✏️ Modo de edição ativado' : '✅ Modo de edição desativado', 'info');
  1055. }
  1056.  
  1057. toggleEnabled() {
  1058. this.enabled = !this.enabled;
  1059. document.getElementById('enabled-text').textContent = this.enabled ? '⚡ Mapeamento: ON' : '⏸️ Mapeamento: OFF';
  1060. document.getElementById('mapper-status').textContent = this.enabled ? '✅ Ativo' : '⏸️ Pausado';
  1061.  
  1062. const btn = document.querySelector('.btn-toggle-enabled');
  1063. btn.style.background = this.enabled
  1064. ? 'linear-gradient(135deg, #9C27B0, #7B1FA2)'
  1065. : 'linear-gradient(135deg, #757575, #616161)';
  1066.  
  1067. this.mappedButtons.forEach(btn => {
  1068. if (this.enabled) {
  1069. btn.element.classList.remove('disabled');
  1070. } else {
  1071. btn.element.classList.add('disabled');
  1072. }
  1073. });
  1074.  
  1075. this.showToast(this.enabled ? '✅ Mapeamento ativado' : '⏸️ Mapeamento pausado', 'info');
  1076. }
  1077.  
  1078. updateButtonColor(color) {
  1079. this.settings.buttonColor = color;
  1080. this.mappedButtons.forEach(btn => {
  1081. btn.element.style.background = color;
  1082. });
  1083. }
  1084.  
  1085. updateOpacity(value) {
  1086. this.settings.opacity = value / 100;
  1087. document.getElementById('opacity-value').textContent = value + '%';
  1088. this.mappedButtons.forEach(btn => {
  1089. btn.element.style.opacity = this.settings.opacity;
  1090. });
  1091. }
  1092.  
  1093. updateBorderRadius(value) {
  1094. this.settings.borderRadius = value;
  1095. document.getElementById('radius-value').textContent = value + 'px';
  1096. this.mappedButtons.forEach(btn => {
  1097. btn.element.style.borderRadius = value + 'px';
  1098. });
  1099. }
  1100.  
  1101. toggleStealthMode(enabled) {
  1102. this.settings.stealthMode = enabled;
  1103. if (enabled) {
  1104. document.body.classList.add('stealth-mode');
  1105. this.showToast('🕶️ Modo Furtivo ativado', 'info');
  1106. } else {
  1107. document.body.classList.remove('stealth-mode');
  1108. this.showToast('👁️ Modo Furtivo desativado', 'info');
  1109. }
  1110. }
  1111.  
  1112. toggleHumanizedClicks(enabled) {
  1113. this.settings.humanizedClicks = enabled;
  1114. this.showToast(enabled ? '🤖 Cliques humanizados ativados' : '⚡ Cliques instantâneos', 'info');
  1115. }
  1116.  
  1117. // ==================== SALVAMENTO E CARREGAMENTO ====================
  1118.  
  1119. saveSettings() {
  1120. const data = {
  1121. buttons: this.mappedButtons.map(btn => ({
  1122. label: btn.label,
  1123. targetSelector: btn.targetSelector,
  1124. position: btn.position,
  1125. size: btn.size || { width: this.settings.defaultWidth, height: this.settings.defaultHeight }
  1126. })),
  1127. settings: this.settings
  1128. };
  1129.  
  1130. const key = `buttonMapper_${this.currentGameId}`;
  1131. localStorage.setItem(key, JSON.stringify(data));
  1132.  
  1133. // Também salvar lista de jogos
  1134. this.saveGamesList();
  1135.  
  1136. console.log(`💾 Salvado para: ${this.currentGameId}`);
  1137. }
  1138.  
  1139. saveGamesList() {
  1140. let gamesList = JSON.parse(localStorage.getItem('buttonMapper_games') || '[]');
  1141. if (!gamesList.includes(this.currentGameId)) {
  1142. gamesList.push(this.currentGameId);
  1143. localStorage.setItem('buttonMapper_games', JSON.stringify(gamesList));
  1144. }
  1145. }
  1146.  
  1147. loadSettings() {
  1148. const key = `buttonMapper_${this.currentGameId}`;
  1149. const data = localStorage.getItem(key);
  1150.  
  1151. if (!data) {
  1152. console.log('📂 Nenhum mapeamento salvo para este jogo');
  1153. return;
  1154. }
  1155.  
  1156. try {
  1157. const parsed = JSON.parse(data);
  1158.  
  1159. // Carregar configurações
  1160. if (parsed.settings) {
  1161. this.settings = { ...this.settings, ...parsed.settings };
  1162. }
  1163.  
  1164. // Carregar botões
  1165. if (parsed.buttons && Array.isArray(parsed.buttons)) {
  1166. parsed.buttons.forEach(btnData => {
  1167. const targetElement = document.querySelector(btnData.targetSelector);
  1168. if (targetElement) {
  1169. this.createMappedButton(
  1170. btnData.label,
  1171. targetElement,
  1172. btnData.position,
  1173. btnData.size
  1174. );
  1175. } else {
  1176. console.warn(`⚠️ Elemento não encontrado para: ${btnData.label}`);
  1177. }
  1178. });
  1179. }
  1180.  
  1181. this.updateButtonCount();
  1182. this.showToast(`✅ ${this.mappedButtons.length} botões carregados!`, 'success');
  1183.  
  1184. } catch (error) {
  1185. console.error('❌ Erro ao carregar configurações:', error);
  1186. }
  1187. }
  1188.  
  1189. // ==================== EXPORTAR/IMPORTAR ====================
  1190.  
  1191. exportSettings() {
  1192. const key = `buttonMapper_${this.currentGameId}`;
  1193. const data = localStorage.getItem(key);
  1194.  
  1195. if (!data) {
  1196. this.showToast('❌ Nenhum dado para exportar!', 'error');
  1197. return;
  1198. }
  1199.  
  1200. const blob = new Blob([data], { type: 'application/json' });
  1201. const url = URL.createObjectURL(blob);
  1202. const a = document.createElement('a');
  1203. a.href = url;
  1204. a.download = `mapeamento_${this.currentGameId}_${Date.now()}.json`;
  1205. a.click();
  1206. URL.revokeObjectURL(url);
  1207.  
  1208. this.showToast('📤 Configurações exportadas!', 'success');
  1209. }
  1210.  
  1211. importSettings() {
  1212. const input = document.createElement('input');
  1213. input.type = 'file';
  1214. input.accept = '.json';
  1215.  
  1216. input.onchange = (e) => {
  1217. const file = e.target.files[0];
  1218. if (!file) return;
  1219.  
  1220. const reader = new FileReader();
  1221. reader.onload = (event) => {
  1222. try {
  1223. const data = event.target.result;
  1224. const key = `buttonMapper_${this.currentGameId}`;
  1225. localStorage.setItem(key, data);
  1226.  
  1227. // Recarregar página
  1228. location.reload();
  1229. } catch (error) {
  1230. this.showToast('❌ Erro ao importar arquivo!', 'error');
  1231. }
  1232. };
  1233. reader.readAsText(file);
  1234. };
  1235.  
  1236. input.click();
  1237. }
  1238.  
  1239. // ==================== LIMPEZA ====================
  1240.  
  1241. clearAll() {
  1242. if (!confirm('⚠️ Deletar TODOS os botões deste jogo?\n\nEsta ação não pode ser desfeita!')) {
  1243. return;
  1244. }
  1245.  
  1246. this.mappedButtons.forEach(btn => btn.element.remove());
  1247. this.mappedButtons = [];
  1248.  
  1249. const key = `buttonMapper_${this.currentGameId}`;
  1250. localStorage.removeItem(key);
  1251.  
  1252. this.updateButtonCount();
  1253. this.showToast('🗑️ Todos os botões foram removidos!', 'success');
  1254. }
  1255.  
  1256. // ==================== UTILIDADES ====================
  1257.  
  1258. getElementSelector(element) {
  1259. // ID único
  1260. if (element.id) return `#${element.id}`;
  1261.  
  1262. // Tentar combinação de tags e classes
  1263. let selector = element.tagName.toLowerCase();
  1264.  
  1265. if (element.className && typeof element.className === 'string') {
  1266. const classes = element.className.trim().split(/\s+/).slice(0, 3);
  1267. if (classes.length) {
  1268. selector += '.' + classes.join('.');
  1269. }
  1270. }
  1271.  
  1272. // Adicionar atributos únicos
  1273. const uniqueAttrs = ['data-id', 'data-testid', 'aria-label', 'name'];
  1274. for (const attr of uniqueAttrs) {
  1275. if (element.hasAttribute(attr)) {
  1276. selector += `[${attr}="${element.getAttribute(attr)}"]`;
  1277. break;
  1278. }
  1279. }
  1280.  
  1281. // Se ainda não é único, adicionar path
  1282. if (document.querySelectorAll(selector).length > 1) {
  1283. let path = [selector];
  1284. let current = element.parentElement;
  1285. let depth = 0;
  1286.  
  1287. while (current && depth < 3) {
  1288. let parentSelector = current.tagName.toLowerCase();
  1289. if (current.id) {
  1290. path.unshift(`#${current.id}`);
  1291. break;
  1292. } else if (current.className && typeof current.className === 'string') {
  1293. const classes = current.className.trim().split(/\s+/)[0];
  1294. if (classes) parentSelector += '.' + classes;
  1295. }
  1296. path.unshift(parentSelector);
  1297. current = current.parentElement;
  1298. depth++;
  1299. }
  1300.  
  1301. selector = path.join(' > ');
  1302. }
  1303.  
  1304. return selector;
  1305. }
  1306.  
  1307. updateButtonCount() {
  1308. document.getElementById('button-count').textContent = this.mappedButtons.length;
  1309. }
  1310.  
  1311. showToast(message, type = 'info') {
  1312. const toast = document.createElement('div');
  1313. toast.className = 'toast-notification';
  1314. toast.textContent = message;
  1315.  
  1316. const colors = {
  1317. success: '#4CAF50',
  1318. error: '#f44336',
  1319. warning: '#ff9800',
  1320. info: '#2196F3'
  1321. };
  1322.  
  1323. toast.style.background = colors[type] || colors.info;
  1324. document.body.appendChild(toast);
  1325.  
  1326. setTimeout(() => {
  1327. toast.style.animation = 'slideIn 0.3s ease reverse';
  1328. setTimeout(() => toast.remove(), 300);
  1329. }, 3000);
  1330. }
  1331.  
  1332. // ==================== SISTEMA DE RECONEXÃO AUTOMÁTICA ====================
  1333.  
  1334. setupAutoReconnect() {
  1335. setInterval(() => {
  1336. this.mappedButtons.forEach(buttonData => {
  1337. if (!document.contains(buttonData.target)) {
  1338. const newTarget = document.querySelector(buttonData.targetSelector);
  1339. if (newTarget) {
  1340. buttonData.target = newTarget;
  1341. console.log(`🔄 Reconectado: ${buttonData.label}`);
  1342. }
  1343. }
  1344. });
  1345. }, this.settings.updateInterval);
  1346. }
  1347.  
  1348. // ==================== MONITOR DE PERFORMANCE ====================
  1349.  
  1350. startPerformanceMonitor() {
  1351. let lastUpdate = Date.now();
  1352.  
  1353. setInterval(() => {
  1354. const now = Date.now();
  1355. const fps = 1000 / (now - lastUpdate);
  1356. lastUpdate = now;
  1357.  
  1358. let status = '⚡ Ótimo';
  1359. if (fps < 30) status = '⚠️ Lento';
  1360. else if (fps < 45) status = '🟡 Bom';
  1361.  
  1362. const perfElement = document.getElementById('performance-status');
  1363. if (perfElement) perfElement.textContent = status;
  1364. }, 1000);
  1365. }
  1366.  
  1367. // ==================== MODO STEALTH (ANTI-DETECÇÃO) ====================
  1368.  
  1369. injectStealthMode() {
  1370. // Remover rastros de console
  1371. const originalLog = console.log;
  1372. console.log = function(...args) {
  1373. if (!args[0]?.includes('buttonMapper') && !args[0]?.includes('🎮')) {
  1374. originalLog.apply(console, args);
  1375. }
  1376. };
  1377.  
  1378. // Ofuscar identificadores
  1379. Object.defineProperty(this, 'constructor', {
  1380. get: function() { return Object; }
  1381. });
  1382.  
  1383. // Prevenir detecção por timing
  1384. if (this.settings.randomClickDelay) {
  1385. this.settings.minDelay = 50 + Math.random() * 30;
  1386. this.settings.maxDelay = 100 + Math.random() * 50;
  1387. }
  1388. }
  1389. }
  1390.  
  1391. // ==================== INICIALIZAÇÃO ====================
  1392.  
  1393. // Aguardar carregamento completo
  1394. if (document.readyState === 'loading') {
  1395. document.addEventListener('DOMContentLoaded', init);
  1396. } else {
  1397. init();
  1398. }
  1399.  
  1400. function init() {
  1401. // Pequeno delay para garantir que o DOM está pronto
  1402. setTimeout(() => {
  1403. window.buttonMapper = new AdvancedButtonMapper();
  1404. console.log('🎮 Button Mapper v2.0 - Pronto!');
  1405. }, 1000);
  1406. }
Add Comment
Please, Sign In to add comment