Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // =======================================================================================
- // SISTEMA AVANÇADO DE MAPEAMENTO DE BOTÕES v2.0
- // Recursos: Persistência por jogo, Anti-detecção, Otimização, Redimensionamento
- // =======================================================================================
- class AdvancedButtonMapper {
- constructor() {
- this.mappedButtons = [];
- this.isDragging = false;
- this.isResizing = false;
- this.editMode = false;
- this.enabled = true;
- this.currentGameId = null;
- // Configurações de segurança e performance
- this.settings = {
- // Visual
- opacity: 0.7,
- showLabels: true,
- buttonColor: '#4CAF50',
- textColor: '#FFFFFF',
- borderRadius: 8,
- // Segurança (Anti-detecção)
- stealthMode: true,
- randomClickDelay: true,
- minDelay: 50,
- maxDelay: 150,
- hideOnGameFocus: false,
- humanizedClicks: true,
- // Performance
- updateInterval: 5000, // Verifica elementos a cada 5s
- maxButtons: 20, // Limite de botões
- enableDebounce: true,
- // Dimensões padrão
- defaultWidth: 100,
- defaultHeight: 40,
- minWidth: 50,
- minHeight: 30,
- maxWidth: 300,
- maxHeight: 150
- };
- this.init();
- }
- // ==================== INICIALIZAÇÃO ====================
- init() {
- this.currentGameId = this.getGameId();
- this.createStyles();
- this.createControlPanel();
- this.loadSettings();
- this.startPerformanceMonitor();
- this.setupAutoReconnect();
- this.injectStealthMode();
- console.log(`🎮 Mapeador de Botões v2.0 carregado`);
- console.log(`📍 Jogo ID: ${this.currentGameId}`);
- }
- // Detectar ID do jogo atual
- getGameId() {
- // Método 1: URL do Roblox
- const urlMatch = window.location.href.match(/games\/(\d+)/);
- if (urlMatch) return `roblox_${urlMatch[1]}`;
- // Método 2: Título da página
- const title = document.title.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 30);
- if (title) return `game_${title}`;
- // Método 3: Hash da URL
- const urlHash = this.hashCode(window.location.href);
- return `hash_${urlHash}`;
- }
- // Gerar hash simples
- hashCode(str) {
- let hash = 0;
- for (let i = 0; i < str.length; i++) {
- const char = str.charCodeAt(i);
- hash = ((hash << 5) - hash) + char;
- hash = hash & hash;
- }
- return Math.abs(hash);
- }
- // ==================== ESTILOS CSS ====================
- createStyles() {
- const style = document.createElement('style');
- style.id = 'button-mapper-styles';
- style.textContent = `
- /* Botões Mapeados */
- .mapped-button {
- position: fixed;
- background: ${this.settings.buttonColor};
- color: ${this.settings.textColor};
- border: 2px solid rgba(255,255,255,0.5);
- border-radius: ${this.settings.borderRadius}px;
- cursor: pointer;
- opacity: ${this.settings.opacity};
- z-index: 999998;
- font-family: 'Segoe UI', Arial, sans-serif;
- font-weight: bold;
- font-size: 14px;
- transition: all 0.15s ease;
- user-select: none;
- box-shadow: 0 2px 8px rgba(0,0,0,0.3);
- display: flex;
- align-items: center;
- justify-content: center;
- text-align: center;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- padding: 5px;
- }
- .mapped-button:hover {
- opacity: 1;
- transform: scale(1.02);
- box-shadow: 0 4px 12px rgba(0,0,0,0.4);
- }
- .mapped-button:active {
- transform: scale(0.98);
- box-shadow: 0 1px 4px rgba(0,0,0,0.3);
- }
- .mapped-button.dragging {
- cursor: move !important;
- opacity: 0.6;
- border-color: #2196F3;
- }
- .mapped-button.resizing {
- cursor: nwse-resize !important;
- border-color: #ff9800;
- }
- .mapped-button.edit-mode {
- border-color: #ff9800;
- animation: pulse-border 2s infinite;
- }
- .mapped-button.disabled {
- opacity: 0.3;
- cursor: not-allowed;
- filter: grayscale(100%);
- }
- .mapped-button.clicked {
- animation: click-feedback 0.3s ease;
- }
- @keyframes pulse-border {
- 0%, 100% { box-shadow: 0 0 10px rgba(255,152,0,0.5); }
- 50% { box-shadow: 0 0 20px rgba(255,152,0,0.8); }
- }
- @keyframes click-feedback {
- 0% { background: #2196F3; transform: scale(0.95); }
- 50% { background: #64B5F6; transform: scale(1.05); }
- 100% { background: ${this.settings.buttonColor}; transform: scale(1); }
- }
- /* Alça de redimensionamento */
- .resize-handle {
- position: absolute;
- bottom: 0;
- right: 0;
- width: 16px;
- height: 16px;
- cursor: nwse-resize;
- opacity: 0;
- transition: opacity 0.2s;
- }
- .resize-handle::after {
- content: '⋰';
- position: absolute;
- bottom: 2px;
- right: 2px;
- color: white;
- font-size: 12px;
- text-shadow: 0 1px 2px rgba(0,0,0,0.5);
- }
- .mapped-button.edit-mode .resize-handle {
- opacity: 1;
- }
- .resize-handle:hover {
- opacity: 1 !important;
- }
- /* Painel de Controle */
- .control-panel {
- position: fixed;
- top: 10px;
- right: 10px;
- background: linear-gradient(135deg, rgba(0,0,0,0.95), rgba(30,30,30,0.95));
- color: white;
- padding: 15px;
- border-radius: 12px;
- z-index: 999999;
- font-family: 'Segoe UI', Arial, sans-serif;
- min-width: 280px;
- box-shadow: 0 8px 32px rgba(0,0,0,0.5);
- backdrop-filter: blur(10px);
- border: 1px solid rgba(255,255,255,0.1);
- }
- .control-panel.minimized {
- min-width: auto;
- padding: 10px;
- }
- .control-panel.minimized .panel-content {
- display: none;
- }
- .panel-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 10px;
- padding-bottom: 10px;
- border-bottom: 1px solid rgba(255,255,255,0.2);
- }
- .panel-header h3 {
- margin: 0;
- font-size: 16px;
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .minimize-btn {
- background: rgba(255,255,255,0.1);
- border: none;
- color: white;
- width: 24px;
- height: 24px;
- border-radius: 4px;
- cursor: pointer;
- font-size: 16px;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: all 0.2s;
- }
- .minimize-btn:hover {
- background: rgba(255,255,255,0.2);
- }
- .control-panel button {
- width: 100%;
- margin: 5px 0;
- padding: 10px;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- font-weight: 600;
- font-size: 13px;
- transition: all 0.2s;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 6px;
- }
- .control-panel button:hover {
- transform: translateY(-1px);
- box-shadow: 0 4px 8px rgba(0,0,0,0.3);
- }
- .control-panel button:active {
- transform: translateY(0);
- }
- .btn-add { background: linear-gradient(135deg, #4CAF50, #45a049); color: white; }
- .btn-edit { background: linear-gradient(135deg, #2196F3, #1976D2); color: white; }
- .btn-toggle-enabled { background: linear-gradient(135deg, #9C27B0, #7B1FA2); color: white; }
- .btn-clear { background: linear-gradient(135deg, #f44336, #d32f2f); color: white; }
- .btn-save { background: linear-gradient(135deg, #ff9800, #f57c00); color: white; }
- .btn-export { background: linear-gradient(135deg, #00BCD4, #0097A7); color: white; }
- .btn-import { background: linear-gradient(135deg, #009688, #00796B); color: white; }
- /* Slider e controles */
- .control-group {
- margin: 10px 0;
- padding: 10px;
- background: rgba(255,255,255,0.05);
- border-radius: 6px;
- }
- .control-group label {
- display: block;
- margin-bottom: 5px;
- font-size: 12px;
- color: #bbb;
- font-weight: 600;
- }
- .control-group input[type="range"] {
- width: 100%;
- margin: 5px 0;
- }
- .control-group input[type="color"] {
- width: 100%;
- height: 35px;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- }
- .stats {
- margin-top: 10px;
- padding: 10px;
- background: rgba(0,0,0,0.3);
- border-radius: 6px;
- font-size: 11px;
- line-height: 1.6;
- }
- .stats-row {
- display: flex;
- justify-content: space-between;
- margin: 3px 0;
- }
- .stats-label {
- color: #999;
- }
- .stats-value {
- color: #4CAF50;
- font-weight: bold;
- }
- /* Overlay de seleção */
- .selector-overlay {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: rgba(0,0,0,0.7);
- z-index: 999997;
- cursor: crosshair;
- backdrop-filter: blur(2px);
- }
- .selector-hint {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: white;
- padding: 30px;
- border-radius: 12px;
- font-size: 18px;
- z-index: 999998;
- text-align: center;
- box-shadow: 0 8px 32px rgba(0,0,0,0.5);
- max-width: 400px;
- }
- .selector-hint h3 {
- margin: 0 0 10px 0;
- color: #333;
- }
- .selector-hint p {
- margin: 5px 0;
- color: #666;
- font-size: 14px;
- }
- .highlight-element {
- outline: 3px solid #ff9800 !important;
- outline-offset: 3px;
- position: relative;
- box-shadow: 0 0 20px rgba(255,152,0,0.5) !important;
- }
- /* Toast de notificação */
- .toast-notification {
- position: fixed;
- bottom: 20px;
- right: 20px;
- background: rgba(0,0,0,0.9);
- color: white;
- padding: 15px 20px;
- border-radius: 8px;
- z-index: 1000000;
- animation: slideIn 0.3s ease;
- box-shadow: 0 4px 16px rgba(0,0,0,0.5);
- }
- @keyframes slideIn {
- from {
- transform: translateX(400px);
- opacity: 0;
- }
- to {
- transform: translateX(0);
- opacity: 1;
- }
- }
- /* Modo Stealth */
- .stealth-mode .mapped-button {
- transition: opacity 0.3s;
- }
- .stealth-mode .mapped-button:not(:hover) {
- opacity: 0.1;
- }
- `;
- document.head.appendChild(style);
- }
- // ==================== PAINEL DE CONTROLE ====================
- createControlPanel() {
- const panel = document.createElement('div');
- panel.className = 'control-panel';
- panel.id = 'button-mapper-panel';
- panel.innerHTML = `
- <div class="panel-header">
- <h3>
- <span>🎮</span>
- <span>Mapeador v2.0</span>
- </h3>
- <button class="minimize-btn" onclick="buttonMapper.togglePanel()">−</button>
- </div>
- <div class="panel-content">
- <!-- Botões principais -->
- <button class="btn-add" onclick="buttonMapper.addButton()">
- ➕ Adicionar Botão
- </button>
- <button class="btn-edit" onclick="buttonMapper.toggleEditMode()">
- ✏️ <span id="edit-mode-text">Modo Edição: OFF</span>
- </button>
- <button class="btn-toggle-enabled" onclick="buttonMapper.toggleEnabled()">
- <span id="enabled-text">⚡ Mapeamento: ON</span>
- </button>
- <!-- Controles visuais -->
- <div class="control-group">
- <label>🎨 Cor dos Botões</label>
- <input type="color" id="button-color" value="#4CAF50"
- onchange="buttonMapper.updateButtonColor(this.value)">
- </div>
- <div class="control-group">
- <label>👁️ Opacidade: <span id="opacity-value">70%</span></label>
- <input type="range" min="10" max="100" value="70"
- oninput="buttonMapper.updateOpacity(this.value)">
- </div>
- <div class="control-group">
- <label>⭕ Arredondamento: <span id="radius-value">8px</span></label>
- <input type="range" min="0" max="50" value="8"
- oninput="buttonMapper.updateBorderRadius(this.value)">
- </div>
- <!-- Segurança -->
- <div class="control-group">
- <label style="display: flex; align-items: center; gap: 8px;">
- <input type="checkbox" id="stealth-mode" checked
- onchange="buttonMapper.toggleStealthMode(this.checked)">
- 🕶️ Modo Furtivo (Anti-detecção)
- </label>
- <label style="display: flex; align-items: center; gap: 8px; margin-top: 8px;">
- <input type="checkbox" id="humanized-clicks" checked
- onchange="buttonMapper.toggleHumanizedClicks(this.checked)">
- 🤖 Cliques Humanizados
- </label>
- </div>
- <!-- Gerenciamento -->
- <button class="btn-save" onclick="buttonMapper.saveSettings()">
- 💾 Salvar Mapeamento
- </button>
- <button class="btn-export" onclick="buttonMapper.exportSettings()">
- 📤 Exportar
- </button>
- <button class="btn-import" onclick="buttonMapper.importSettings()">
- 📥 Importar
- </button>
- <button class="btn-clear" onclick="buttonMapper.clearAll()">
- 🗑️ Limpar Tudo
- </button>
- <!-- Estatísticas -->
- <div class="stats">
- <div class="stats-row">
- <span class="stats-label">Jogo Atual:</span>
- <span class="stats-value" id="current-game">${this.currentGameId}</span>
- </div>
- <div class="stats-row">
- <span class="stats-label">Botões Mapeados:</span>
- <span class="stats-value" id="button-count">0</span>
- </div>
- <div class="stats-row">
- <span class="stats-label">Status:</span>
- <span class="stats-value" id="mapper-status">✅ Ativo</span>
- </div>
- <div class="stats-row">
- <span class="stats-label">Performance:</span>
- <span class="stats-value" id="performance-status">⚡ Ótimo</span>
- </div>
- </div>
- </div>
- `;
- document.body.appendChild(panel);
- // Tornar painel arrastável
- this.makePanelDraggable(panel);
- }
- // Minimizar/expandir painel
- togglePanel() {
- const panel = document.getElementById('button-mapper-panel');
- const btn = panel.querySelector('.minimize-btn');
- panel.classList.toggle('minimized');
- btn.textContent = panel.classList.contains('minimized') ? '+' : '−';
- }
- // Tornar painel arrastável
- makePanelDraggable(panel) {
- const header = panel.querySelector('.panel-header h3');
- let isDragging = false;
- let currentX, currentY, initialX, initialY;
- header.style.cursor = 'move';
- header.addEventListener('mousedown', (e) => {
- isDragging = true;
- initialX = e.clientX - panel.offsetLeft;
- initialY = e.clientY - panel.offsetTop;
- });
- document.addEventListener('mousemove', (e) => {
- if (isDragging) {
- e.preventDefault();
- currentX = e.clientX - initialX;
- currentY = e.clientY - initialY;
- panel.style.left = currentX + 'px';
- panel.style.top = currentY + 'px';
- panel.style.right = 'auto';
- }
- });
- document.addEventListener('mouseup', () => {
- isDragging = false;
- });
- }
- // ==================== ADICIONAR BOTÃO ====================
- async addButton() {
- if (this.mappedButtons.length >= this.settings.maxButtons) {
- this.showToast(`❌ Limite de ${this.settings.maxButtons} botões atingido!`, 'error');
- return;
- }
- const label = prompt('📝 Digite o nome do botão:');
- if (!label || label.trim() === '') {
- this.showToast('❌ Nome inválido!', 'error');
- return;
- }
- this.showToast('👆 Clique no elemento do jogo que deseja mapear...', 'info');
- const targetElement = await this.selectElement();
- if (!targetElement) {
- this.showToast('❌ Seleção cancelada', 'warning');
- return;
- }
- const position = {
- x: window.innerWidth / 2 - 50,
- y: window.innerHeight / 2 - 20
- };
- const size = {
- width: this.settings.defaultWidth,
- height: this.settings.defaultHeight
- };
- this.createMappedButton(label, targetElement, position, size);
- this.updateButtonCount();
- this.saveSettings();
- this.showToast(`✅ Botão "${label}" adicionado!`, 'success');
- }
- // ==================== SELETOR DE ELEMENTO ====================
- selectElement() {
- return new Promise((resolve) => {
- const overlay = document.createElement('div');
- overlay.className = 'selector-overlay';
- const hint = document.createElement('div');
- hint.className = 'selector-hint';
- hint.innerHTML = `
- <h3>🎯 Selecione o Elemento</h3>
- <p>Mova o mouse sobre o botão do jogo</p>
- <p style="font-size: 12px; color: #999;">Pressione ESC para cancelar</p>
- `;
- document.body.appendChild(overlay);
- document.body.appendChild(hint);
- let currentHighlight = null;
- const handleMouseMove = (e) => {
- if (currentHighlight) {
- currentHighlight.classList.remove('highlight-element');
- }
- // Desabilitar temporariamente o overlay para pegar elemento abaixo
- overlay.style.pointerEvents = 'none';
- const element = document.elementFromPoint(e.clientX, e.clientY);
- overlay.style.pointerEvents = 'auto';
- if (element && element !== overlay && element !== hint) {
- element.classList.add('highlight-element');
- currentHighlight = element;
- // Mostrar info do elemento
- hint.innerHTML = `
- <h3>🎯 Elemento Detectado</h3>
- <p><strong>${element.tagName}</strong></p>
- <p style="font-size: 12px;">${element.className || 'Sem classe'}</p>
- <p style="font-size: 11px; color: #999;">Clique para confirmar | ESC para cancelar</p>
- `;
- }
- };
- const handleClick = (e) => {
- e.preventDefault();
- e.stopPropagation();
- overlay.style.pointerEvents = 'none';
- const element = document.elementFromPoint(e.clientX, e.clientY);
- overlay.style.pointerEvents = 'auto';
- cleanup();
- if (element && element !== overlay && element !== hint) {
- resolve(element);
- } else {
- resolve(null);
- }
- };
- const handleEscape = (e) => {
- if (e.key === 'Escape') {
- cleanup();
- resolve(null);
- }
- };
- const cleanup = () => {
- if (currentHighlight) {
- currentHighlight.classList.remove('highlight-element');
- }
- overlay.remove();
- hint.remove();
- document.removeEventListener('mousemove', handleMouseMove);
- document.removeEventListener('click', handleClick, true);
- document.removeEventListener('keydown', handleEscape);
- };
- document.addEventListener('mousemove', handleMouseMove);
- document.addEventListener('click', handleClick, true);
- document.addEventListener('keydown', handleEscape);
- });
- }
- // ==================== CRIAR BOTÃO MAPEADO ====================
- createMappedButton(label, targetElement, position, size = {}) {
- const button = document.createElement('div');
- button.className = 'mapped-button';
- button.textContent = label;
- button.style.left = position.x + 'px';
- button.style.top = position.y + 'px';
- button.style.width = (size.width || this.settings.defaultWidth) + 'px';
- button.style.height = (size.height || this.settings.defaultHeight) + 'px';
- // Criar alça de redimensionamento
- const resizeHandle = document.createElement('div');
- resizeHandle.className = 'resize-handle';
- button.appendChild(resizeHandle);
- // Dados do botão
- const buttonData = {
- element: button,
- label: label,
- target: targetElement,
- targetSelector: this.getElementSelector(targetElement),
- position: position,
- size: size,
- clickCount: 0,
- lastClick: null
- };
- // Click para acionar
- button.addEventListener('click', (e) => {
- if (!this.isDragging && !this.isResizing && !this.editMode && this.enabled) {
- this.triggerTargetElement(buttonData);
- }
- });
- // Arrastar
- this.setupDragging(button, buttonData);
- // Redimensionar
- this.setupResizing(button, resizeHandle, buttonData);
- // Botão direito - Menu de contexto
- button.addEventListener('contextmenu', (e) => {
- e.preventDefault();
- if (this.editMode) {
- this.showButtonMenu(e, buttonData);
- }
- });
- document.body.appendChild(button);
- this.mappedButtons.push(buttonData);
- return button;
- }
- // ==================== ARRASTAR BOTÃO ====================
- setupDragging(button, buttonData) {
- let offsetX, offsetY;
- button.addEventListener('mousedown', (e) => {
- if (this.editMode && !e.target.classList.contains('resize-handle')) {
- this.isDragging = true;
- button.classList.add('dragging');
- offsetX = e.clientX - button.offsetLeft;
- offsetY = e.clientY - button.offsetTop;
- const handleMouseMove = (e) => {
- if (this.isDragging) {
- const newX = e.clientX - offsetX;
- const newY = e.clientY - offsetY;
- // Limitar ao viewport
- const maxX = window.innerWidth - button.offsetWidth;
- const maxY = window.innerHeight - button.offsetHeight;
- button.style.left = Math.max(0, Math.min(newX, maxX)) + 'px';
- button.style.top = Math.max(0, Math.min(newY, maxY)) + 'px';
- buttonData.position.x = parseInt(button.style.left);
- buttonData.position.y = parseInt(button.style.top);
- }
- };
- const handleMouseUp = () => {
- if (this.isDragging) {
- this.isDragging = false;
- button.classList.remove('dragging');
- this.saveSettings();
- document.removeEventListener('mousemove', handleMouseMove);
- document.removeEventListener('mouseup', handleMouseUp);
- }
- };
- document.addEventListener('mousemove', handleMouseMove);
- document.addEventListener('mouseup', handleMouseUp);
- }
- });
- }
- // ==================== REDIMENSIONAR BOTÃO ====================
- setupResizing(button, handle, buttonData) {
- handle.addEventListener('mousedown', (e) => {
- if (this.editMode) {
- e.stopPropagation();
- this.isResizing = true;
- button.classList.add('resizing');
- const startWidth = button.offsetWidth;
- const startHeight = button.offsetHeight;
- const startX = e.clientX;
- const startY = e.clientY;
- const handleMouseMove = (e) => {
- if (this.isResizing) {
- const deltaX = e.clientX - startX;
- const deltaY = e.clientY - startY;
- let newWidth = startWidth + deltaX;
- let newHeight = startHeight + deltaY;
- // Aplicar limites
- newWidth = Math.max(this.settings.minWidth, Math.min(newWidth, this.settings.maxWidth));
- newHeight = Math.max(this.settings.minHeight, Math.min(newHeight, this.settings.maxHeight));
- button.style.width = newWidth + 'px';
- button.style.height = newHeight + 'px';
- buttonData.size = { width: newWidth, height: newHeight };
- }
- };
- const handleMouseUp = () => {
- if (this.isResizing) {
- this.isResizing = false;
- button.classList.remove('resizing');
- this.saveSettings();
- document.removeEventListener('mousemove', handleMouseMove);
- document.removeEventListener('mouseup', handleMouseUp);
- }
- };
- document.addEventListener('mousemove', handleMouseMove);
- document.addEventListener('mouseup', handleMouseUp);
- }
- });
- }
- // ==================== MENU DE CONTEXTO ====================
- showButtonMenu(e, buttonData) {
- const menu = document.createElement('div');
- menu.style.cssText = `
- position: fixed;
- left: ${e.clientX}px;
- top: ${e.clientY}px;
- background: white;
- border-radius: 8px;
- box-shadow: 0 4px 16px rgba(0,0,0,0.3);
- z-index: 1000000;
- padding: 8px;
- min-width: 180px;
- `;
- menu.innerHTML = `
- <div style="padding: 8px 12px; cursor: pointer; border-radius: 4px;"
- onmouseover="this.style.background='#f0f0f0'"
- onmouseout="this.style.background='white'"
- onclick="buttonMapper.renameButton('${buttonData.label}')">
- ✏️ Renomear
- </div>
- <div style="padding: 8px 12px; cursor: pointer; border-radius: 4px;"
- onmouseover="this.style.background='#f0f0f0'"
- onmouseout="this.style.background='white'"
- onclick="buttonMapper.resetSize('${buttonData.label}')">
- ↔️ Resetar Tamanho
- </div>
- <div style="padding: 8px 12px; cursor: pointer; border-radius: 4px;"
- onmouseover="this.style.background='#f0f0f0'"
- onmouseout="this.style.background='white'"
- onclick="buttonMapper.duplicateButton('${buttonData.label}')">
- 📋 Duplicar
- </div>
- <hr style="margin: 4px 0; border: none; border-top: 1px solid #ddd;">
- <div style="padding: 8px 12px; cursor: pointer; border-radius: 4px; color: #f44336;"
- onmouseover="this.style.background='#ffebee'"
- onmouseout="this.style.background='white'"
- onclick="buttonMapper.deleteButton('${buttonData.label}')">
- 🗑️ Deletar
- </div>
- `;
- document.body.appendChild(menu);
- // Fechar ao clicar fora
- setTimeout(() => {
- const closeMenu = (e) => {
- if (!menu.contains(e.target)) {
- menu.remove();
- document.removeEventListener('click', closeMenu);
- }
- };
- document.addEventListener('click', closeMenu);
- }, 100);
- }
- // ==================== ACIONAR ELEMENTO ALVO ====================
- async triggerTargetElement(buttonData) {
- if (!buttonData.target || !document.contains(buttonData.target)) {
- // Tentar reconectar
- const newTarget = document.querySelector(buttonData.targetSelector);
- if (newTarget) {
- buttonData.target = newTarget;
- } else {
- this.showToast('⚠️ Elemento alvo não encontrado!', 'warning');
- return;
- }
- }
- const element = buttonData.target;
- // Feedback visual
- buttonData.element.classList.add('clicked');
- setTimeout(() => buttonData.element.classList.remove('clicked'), 300);
- // Delay humanizado (anti-detecção)
- if (this.settings.humanizedClicks) {
- const delay = this.settings.minDelay + Math.random() * (this.settings.maxDelay - this.settings.minDelay);
- await new Promise(resolve => setTimeout(resolve, delay));
- }
- // Simular clique humano
- try {
- const rect = element.getBoundingClientRect();
- // Posição aleatória dentro do elemento (mais humano)
- const randomX = rect.left + (rect.width * (0.3 + Math.random() * 0.4));
- const randomY = rect.top + (rect.height * (0.3 + Math.random() * 0.4));
- // Sequência completa de eventos (mais realista)
- const eventOptions = {
- view: window,
- bubbles: true,
- cancelable: true,
- clientX: randomX,
- clientY: randomY,
- button: 0
- };
- // Mousedown -> Mouseup -> Click
- element.dispatchEvent(new MouseEvent('mousedown', eventOptions));
- await new Promise(resolve => setTimeout(resolve, 30 + Math.random() * 50));
- element.dispatchEvent(new MouseEvent('mouseup', eventOptions));
- element.dispatchEvent(new MouseEvent('click', eventOptions));
- // Método nativo também
- if (element.click) {
- element.click();
- }
- // Estatísticas
- buttonData.clickCount++;
- buttonData.lastClick = new Date();
- console.log(`✅ Clique enviado para: ${buttonData.label}`);
- } catch (error) {
- console.error('❌ Erro ao acionar botão:', error);
- this.showToast('❌ Erro ao acionar botão!', 'error');
- }
- }
- // ==================== FUNÇÕES DO MENU ====================
- renameButton(label) {
- const buttonData = this.mappedButtons.find(b => b.label === label);
- if (!buttonData) return;
- const newLabel = prompt('Digite o novo nome:', label);
- if (newLabel && newLabel.trim()) {
- buttonData.label = newLabel;
- buttonData.element.textContent = newLabel;
- this.saveSettings();
- this.showToast('✅ Botão renomeado!', 'success');
- }
- }
- resetSize(label) {
- const buttonData = this.mappedButtons.find(b => b.label === label);
- if (!buttonData) return;
- buttonData.element.style.width = this.settings.defaultWidth + 'px';
- buttonData.element.style.height = this.settings.defaultHeight + 'px';
- buttonData.size = { width: this.settings.defaultWidth, height: this.settings.defaultHeight };
- this.saveSettings();
- this.showToast('✅ Tamanho resetado!', 'success');
- }
- duplicateButton(label) {
- const buttonData = this.mappedButtons.find(b => b.label === label);
- if (!buttonData) return;
- const newPosition = {
- x: buttonData.position.x + 20,
- y: buttonData.position.y + 20
- };
- this.createMappedButton(
- buttonData.label + ' (cópia)',
- buttonData.target,
- newPosition,
- buttonData.size
- );
- this.updateButtonCount();
- this.saveSettings();
- this.showToast('✅ Botão duplicado!', 'success');
- }
- deleteButton(label) {
- const buttonData = this.mappedButtons.find(b => b.label === label);
- if (!buttonData) return;
- if (confirm(`Deletar "${label}"?`)) {
- buttonData.element.remove();
- this.mappedButtons = this.mappedButtons.filter(b => b.label !== label);
- this.updateButtonCount();
- this.saveSettings();
- this.showToast('🗑️ Botão deletado!', 'success');
- }
- }
- // ==================== CONTROLES ====================
- toggleEditMode() {
- this.editMode = !this.editMode;
- document.getElementById('edit-mode-text').textContent = `Modo Edição: ${this.editMode ? 'ON' : 'OFF'}`;
- const editBtn = document.querySelector('.btn-edit');
- editBtn.style.background = this.editMode
- ? 'linear-gradient(135deg, #ff9800, #f57c00)'
- : 'linear-gradient(135deg, #2196F3, #1976D2)';
- this.mappedButtons.forEach(btn => {
- if (this.editMode) {
- btn.element.classList.add('edit-mode');
- } else {
- btn.element.classList.remove('edit-mode');
- }
- });
- this.showToast(this.editMode ? '✏️ Modo de edição ativado' : '✅ Modo de edição desativado', 'info');
- }
- toggleEnabled() {
- this.enabled = !this.enabled;
- document.getElementById('enabled-text').textContent = this.enabled ? '⚡ Mapeamento: ON' : '⏸️ Mapeamento: OFF';
- document.getElementById('mapper-status').textContent = this.enabled ? '✅ Ativo' : '⏸️ Pausado';
- const btn = document.querySelector('.btn-toggle-enabled');
- btn.style.background = this.enabled
- ? 'linear-gradient(135deg, #9C27B0, #7B1FA2)'
- : 'linear-gradient(135deg, #757575, #616161)';
- this.mappedButtons.forEach(btn => {
- if (this.enabled) {
- btn.element.classList.remove('disabled');
- } else {
- btn.element.classList.add('disabled');
- }
- });
- this.showToast(this.enabled ? '✅ Mapeamento ativado' : '⏸️ Mapeamento pausado', 'info');
- }
- updateButtonColor(color) {
- this.settings.buttonColor = color;
- this.mappedButtons.forEach(btn => {
- btn.element.style.background = color;
- });
- }
- updateOpacity(value) {
- this.settings.opacity = value / 100;
- document.getElementById('opacity-value').textContent = value + '%';
- this.mappedButtons.forEach(btn => {
- btn.element.style.opacity = this.settings.opacity;
- });
- }
- updateBorderRadius(value) {
- this.settings.borderRadius = value;
- document.getElementById('radius-value').textContent = value + 'px';
- this.mappedButtons.forEach(btn => {
- btn.element.style.borderRadius = value + 'px';
- });
- }
- toggleStealthMode(enabled) {
- this.settings.stealthMode = enabled;
- if (enabled) {
- document.body.classList.add('stealth-mode');
- this.showToast('🕶️ Modo Furtivo ativado', 'info');
- } else {
- document.body.classList.remove('stealth-mode');
- this.showToast('👁️ Modo Furtivo desativado', 'info');
- }
- }
- toggleHumanizedClicks(enabled) {
- this.settings.humanizedClicks = enabled;
- this.showToast(enabled ? '🤖 Cliques humanizados ativados' : '⚡ Cliques instantâneos', 'info');
- }
- // ==================== SALVAMENTO E CARREGAMENTO ====================
- saveSettings() {
- const data = {
- buttons: this.mappedButtons.map(btn => ({
- label: btn.label,
- targetSelector: btn.targetSelector,
- position: btn.position,
- size: btn.size || { width: this.settings.defaultWidth, height: this.settings.defaultHeight }
- })),
- settings: this.settings
- };
- const key = `buttonMapper_${this.currentGameId}`;
- localStorage.setItem(key, JSON.stringify(data));
- // Também salvar lista de jogos
- this.saveGamesList();
- console.log(`💾 Salvado para: ${this.currentGameId}`);
- }
- saveGamesList() {
- let gamesList = JSON.parse(localStorage.getItem('buttonMapper_games') || '[]');
- if (!gamesList.includes(this.currentGameId)) {
- gamesList.push(this.currentGameId);
- localStorage.setItem('buttonMapper_games', JSON.stringify(gamesList));
- }
- }
- loadSettings() {
- const key = `buttonMapper_${this.currentGameId}`;
- const data = localStorage.getItem(key);
- if (!data) {
- console.log('📂 Nenhum mapeamento salvo para este jogo');
- return;
- }
- try {
- const parsed = JSON.parse(data);
- // Carregar configurações
- if (parsed.settings) {
- this.settings = { ...this.settings, ...parsed.settings };
- }
- // Carregar botões
- if (parsed.buttons && Array.isArray(parsed.buttons)) {
- parsed.buttons.forEach(btnData => {
- const targetElement = document.querySelector(btnData.targetSelector);
- if (targetElement) {
- this.createMappedButton(
- btnData.label,
- targetElement,
- btnData.position,
- btnData.size
- );
- } else {
- console.warn(`⚠️ Elemento não encontrado para: ${btnData.label}`);
- }
- });
- }
- this.updateButtonCount();
- this.showToast(`✅ ${this.mappedButtons.length} botões carregados!`, 'success');
- } catch (error) {
- console.error('❌ Erro ao carregar configurações:', error);
- }
- }
- // ==================== EXPORTAR/IMPORTAR ====================
- exportSettings() {
- const key = `buttonMapper_${this.currentGameId}`;
- const data = localStorage.getItem(key);
- if (!data) {
- this.showToast('❌ Nenhum dado para exportar!', 'error');
- return;
- }
- const blob = new Blob([data], { type: 'application/json' });
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `mapeamento_${this.currentGameId}_${Date.now()}.json`;
- a.click();
- URL.revokeObjectURL(url);
- this.showToast('📤 Configurações exportadas!', 'success');
- }
- importSettings() {
- const input = document.createElement('input');
- input.type = 'file';
- input.accept = '.json';
- input.onchange = (e) => {
- const file = e.target.files[0];
- if (!file) return;
- const reader = new FileReader();
- reader.onload = (event) => {
- try {
- const data = event.target.result;
- const key = `buttonMapper_${this.currentGameId}`;
- localStorage.setItem(key, data);
- // Recarregar página
- location.reload();
- } catch (error) {
- this.showToast('❌ Erro ao importar arquivo!', 'error');
- }
- };
- reader.readAsText(file);
- };
- input.click();
- }
- // ==================== LIMPEZA ====================
- clearAll() {
- if (!confirm('⚠️ Deletar TODOS os botões deste jogo?\n\nEsta ação não pode ser desfeita!')) {
- return;
- }
- this.mappedButtons.forEach(btn => btn.element.remove());
- this.mappedButtons = [];
- const key = `buttonMapper_${this.currentGameId}`;
- localStorage.removeItem(key);
- this.updateButtonCount();
- this.showToast('🗑️ Todos os botões foram removidos!', 'success');
- }
- // ==================== UTILIDADES ====================
- getElementSelector(element) {
- // ID único
- if (element.id) return `#${element.id}`;
- // Tentar combinação de tags e classes
- let selector = element.tagName.toLowerCase();
- if (element.className && typeof element.className === 'string') {
- const classes = element.className.trim().split(/\s+/).slice(0, 3);
- if (classes.length) {
- selector += '.' + classes.join('.');
- }
- }
- // Adicionar atributos únicos
- const uniqueAttrs = ['data-id', 'data-testid', 'aria-label', 'name'];
- for (const attr of uniqueAttrs) {
- if (element.hasAttribute(attr)) {
- selector += `[${attr}="${element.getAttribute(attr)}"]`;
- break;
- }
- }
- // Se ainda não é único, adicionar path
- if (document.querySelectorAll(selector).length > 1) {
- let path = [selector];
- let current = element.parentElement;
- let depth = 0;
- while (current && depth < 3) {
- let parentSelector = current.tagName.toLowerCase();
- if (current.id) {
- path.unshift(`#${current.id}`);
- break;
- } else if (current.className && typeof current.className === 'string') {
- const classes = current.className.trim().split(/\s+/)[0];
- if (classes) parentSelector += '.' + classes;
- }
- path.unshift(parentSelector);
- current = current.parentElement;
- depth++;
- }
- selector = path.join(' > ');
- }
- return selector;
- }
- updateButtonCount() {
- document.getElementById('button-count').textContent = this.mappedButtons.length;
- }
- showToast(message, type = 'info') {
- const toast = document.createElement('div');
- toast.className = 'toast-notification';
- toast.textContent = message;
- const colors = {
- success: '#4CAF50',
- error: '#f44336',
- warning: '#ff9800',
- info: '#2196F3'
- };
- toast.style.background = colors[type] || colors.info;
- document.body.appendChild(toast);
- setTimeout(() => {
- toast.style.animation = 'slideIn 0.3s ease reverse';
- setTimeout(() => toast.remove(), 300);
- }, 3000);
- }
- // ==================== SISTEMA DE RECONEXÃO AUTOMÁTICA ====================
- setupAutoReconnect() {
- setInterval(() => {
- this.mappedButtons.forEach(buttonData => {
- if (!document.contains(buttonData.target)) {
- const newTarget = document.querySelector(buttonData.targetSelector);
- if (newTarget) {
- buttonData.target = newTarget;
- console.log(`🔄 Reconectado: ${buttonData.label}`);
- }
- }
- });
- }, this.settings.updateInterval);
- }
- // ==================== MONITOR DE PERFORMANCE ====================
- startPerformanceMonitor() {
- let lastUpdate = Date.now();
- setInterval(() => {
- const now = Date.now();
- const fps = 1000 / (now - lastUpdate);
- lastUpdate = now;
- let status = '⚡ Ótimo';
- if (fps < 30) status = '⚠️ Lento';
- else if (fps < 45) status = '🟡 Bom';
- const perfElement = document.getElementById('performance-status');
- if (perfElement) perfElement.textContent = status;
- }, 1000);
- }
- // ==================== MODO STEALTH (ANTI-DETECÇÃO) ====================
- injectStealthMode() {
- // Remover rastros de console
- const originalLog = console.log;
- console.log = function(...args) {
- if (!args[0]?.includes('buttonMapper') && !args[0]?.includes('🎮')) {
- originalLog.apply(console, args);
- }
- };
- // Ofuscar identificadores
- Object.defineProperty(this, 'constructor', {
- get: function() { return Object; }
- });
- // Prevenir detecção por timing
- if (this.settings.randomClickDelay) {
- this.settings.minDelay = 50 + Math.random() * 30;
- this.settings.maxDelay = 100 + Math.random() * 50;
- }
- }
- }
- // ==================== INICIALIZAÇÃO ====================
- // Aguardar carregamento completo
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', init);
- } else {
- init();
- }
- function init() {
- // Pequeno delay para garantir que o DOM está pronto
- setTimeout(() => {
- window.buttonMapper = new AdvancedButtonMapper();
- console.log('🎮 Button Mapper v2.0 - Pronto!');
- }, 1000);
- }
Add Comment
Please, Sign In to add comment