From cacff68f34e6ec90eb734b7616220867949bab82 Mon Sep 17 00:00:00 2001 From: kyuketski Date: Fri, 29 Aug 2025 21:48:17 +0300 Subject: [PATCH] refactor: enhance configuration, coordinate generation, and pixel painting * Enabled PAINTING\_SPEED\_ENABLED by default to improve painting performance. * Disabled desktop notifications by default to reduce interruptions. * Lowered overlay opacity from 0.6 to 0.2 for better visibility. * Commented out theme variable assignments for future cleanup or removal. * Added new state properties for coordinate generation (coordinateMode, coordinateDirection, etc.) to support advanced painting strategies. * Introduced dynamicSleep utility for more efficient sleep handling during cooldowns. * Added msToTimeText utility to format time durations in a human-readable way. * Implemented migration logic to version 2.2 for backward compatibility with saved progress data. * Enhanced saveProgress and loadProgress methods to include new coordinate generation settings. * Improved error handling in getCharges to provide default values when API calls fail. * Refactored notification messages for better clarity and consistency. * Added multiple coordinate generation modes including rows, columns, circle-out, circle-in, blocks, and shuffle-blocks. * Implemented UI controls for selecting generation modes, setting block sizes, toggling snake patterns, and choosing directions. * Enhanced settings panel with collapsible sections and improved styling for better user experience. * Added dynamic visibility logic to show/hide relevant controls based on the selected generation mode. * Integrated state management to persist user preferences for generation modes, directions, snake pattern toggling, and block dimensions. * Improved logging and user feedback with success alerts when changing coordinate-related settings. * Implemented functionality to track full charge progress using a dynamic timer. * Displays remaining time until full charge in the UI, updating every second. * Ensures charges are calculated accurately based on elapsed time and cooldown intervals. * Added support for pausing and resuming charge updates when the user interacts with the system. * Improved UI feedback for charge-related information, including current charges and full charge status. * Refactored the pixel batch processing logic to improve readability and maintainability. * Introduced a generateCoordinates function to handle coordinate generation for various modes (rows, columns, circle-out, etc.). * Added support for configurable block-based painting modes (blocks and shuffle-blocks) with customizable block dimensions. * Improved logic for handling region transitions during batch painting. * Updated delay calculations for batch processing to better align with painting speed settings. * Enhanced transparency and white pixel skipping logic with customizable thresholds. * Added detailed logging for debugging and monitoring purposes. * Ensured proper cleanup of intervals and state updates when stopping or pausing painting. * Refactored pixel painting logic to include smarter batch processing. * Added checks to skip already painted pixels, reducing redundant operations. * Improved batch size calculation and handling, ensuring batches are sent optimally. * Enhanced error handling for failed batches, preventing infinite loops in case of persistent failures. * Introduced dynamic sleep functionality during cooldown periods to optimize resource usage. * Updated UI interactions to reflect batch progress and cooldown states more accurately. * Added new coordinate mode and direction settings for greater flexibility in pixel painting. These changes improve the bot's configurability, performance, maintainability, and user experience while ensuring backward compatibility with existing progress data, accurate charge tracking, and efficient pixel painting across multiple modes. --- Auto-Image.js | 1180 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 924 insertions(+), 256 deletions(-) diff --git a/Auto-Image.js b/Auto-Image.js index 66de554..83bd5b0 100644 --- a/Auto-Image.js +++ b/Auto-Image.js @@ -16,19 +16,19 @@ MIN: 3, // Random range minimum MAX: 20, // Random range maximum }, - PAINTING_SPEED_ENABLED: false, // Off by default + PAINTING_SPEED_ENABLED: true, // On by default AUTO_CAPTCHA_ENABLED: true, // Turnstile generator enabled by default TOKEN_SOURCE: 'generator', // "generator", "manual", or "hybrid" - default to generator COOLDOWN_CHARGE_THRESHOLD: 1, // Default wait threshold // Desktop Notifications (defaults) NOTIFICATIONS: { - ENABLED: true, + ENABLED: false, ON_CHARGES_REACHED: true, ONLY_WHEN_UNFOCUSED: true, REPEAT_MINUTES: 5, // repeat reminder while threshold condition holds }, OVERLAY: { - OPACITY_DEFAULT: 0.6, + OPACITY_DEFAULT: 0.2, BLUE_MARBLE_DEFAULT: false, ditheringEnabled: false, }, @@ -238,22 +238,22 @@ } catch {} }; - setVar('--wplace-primary', theme.primary); - setVar('--wplace-secondary', theme.secondary); - setVar('--wplace-accent', theme.accent); - setVar('--wplace-text', theme.text); - setVar('--wplace-highlight', theme.highlight); - setVar('--wplace-success', theme.success); - setVar('--wplace-error', theme.error); - setVar('--wplace-warning', theme.warning); - - // Typography + look - setVar('--wplace-font', theme.fontFamily || "'Segoe UI', Roboto, sans-serif"); - setVar('--wplace-radius', '' + (theme.borderRadius || '12px')); - setVar('--wplace-border-style', '' + (theme.borderStyle || 'solid')); - setVar('--wplace-border-width', '' + (theme.borderWidth || '1px')); - setVar('--wplace-backdrop', '' + (theme.backdropFilter || 'blur(10px)')); - setVar('--wplace-border-color', 'rgba(255,255,255,0.1)'); + // setVar('--wplace-primary', theme.primary); + // setVar('--wplace-secondary', theme.secondary); + // setVar('--wplace-accent', theme.accent); + // setVar('--wplace-text', theme.text); + // setVar('--wplace-highlight', theme.highlight); + // setVar('--wplace-success', theme.success); + // setVar('--wplace-error', theme.error); + // setVar('--wplace-warning', theme.warning); + // + // // Typography + look + // setVar('--wplace-font', theme.fontFamily || "'Segoe UI', Roboto, sans-serif"); + // setVar('--wplace-radius', '' + (theme.borderRadius || '12px')); + // setVar('--wplace-border-style', '' + (theme.borderStyle || 'solid')); + // setVar('--wplace-border-width', '' + (theme.borderWidth || '1px')); + // setVar('--wplace-backdrop', '' + (theme.backdropFilter || 'blur(10px)')); + // setVar('--wplace-border-color', 'rgba(255,255,255,0.1)'); } const saveThemePreference = () => { @@ -470,12 +470,11 @@ const FALLBACK_TEXT = { en: { title: 'WPlace Auto-Image', - settings: 'Settings', - close: 'Close', - language: 'Language', - loadingError: 'Loading translations failed, using fallback', + toggleOverlay: 'Toggle Overlay', scanColors: 'Scan Colors', uploadImage: 'Upload Image', + resizeImage: 'Resize Image', + selectPosition: 'Select Position', startPainting: 'Start Painting', stopPainting: 'Stop Painting', progress: 'Progress', @@ -522,6 +521,8 @@ availableColors: [], activeColorPalette: [], // User-selected colors for conversion paintWhitePixels: true, // Default to ON + fullChargeData: null, + fullChargeInterval: null, paintTransparentPixels: false, // Default to OFF currentCharges: 0, maxCharges: 1, // Default max charges @@ -541,6 +542,7 @@ randomBatchMin: CONFIG.RANDOM_BATCH_RANGE.MIN, // Random range minimum randomBatchMax: CONFIG.RANDOM_BATCH_RANGE.MAX, // Random range maximum cooldownChargeThreshold: CONFIG.COOLDOWN_CHARGE_THRESHOLD, + chargesThresholdInterval: null, tokenSource: CONFIG.TOKEN_SOURCE, // "generator" or "manual" initialSetupComplete: false, // Track if initial startup setup is complete (only happens once) overlayOpacity: CONFIG.OVERLAY.OPACITY_DEFAULT, @@ -555,6 +557,12 @@ resizeSettings: null, originalImage: null, resizeIgnoreMask: null, + // Coordinate generation settings + coordinateMode: 'rows', + coordinateDirection: 'bottom-left', + coordinateSnake: true, + blockWidth: 6, + blockHeight: 2, // Notification prefs and runtime bookkeeping notificationsEnabled: CONFIG.NOTIFICATIONS.ENABLED, notifyOnChargesReached: CONFIG.NOTIFICATIONS.ON_CHARGES_REACHED, @@ -1159,6 +1167,14 @@ const Utils = { sleep: (ms) => new Promise((r) => setTimeout(r, ms)), + dynamicSleep: async function (getRemainingMsFn, interval = 500) { + let remaining = getRemainingMsFn(); + while (remaining > 0) { + await this.sleep(Math.min(interval, remaining)); + remaining = getRemainingMsFn(); + } + }, + waitForSelector: async (selector, interval = 200, timeout = 5000) => { const start = Date.now(); while (Date.now() - start < timeout) { @@ -1169,6 +1185,16 @@ return null; }, + msToTimeText(ms) { + const totalSeconds = Math.ceil(ms / 1000); + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + + if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`; + if (minutes > 0) return `${minutes}m ${seconds}s`; + return `${seconds}s`; + }, // Turnstile Generator Integration - Optimized with widget reuse and proper cleanup turnstileLoaded: false, _turnstileContainer: null, @@ -2059,6 +2085,35 @@ } }, + migrateProgressToV22: (data) => { + try { + const migrated = { ...data }; + migrated.version = '2.2'; + + // Добавляем новые поля с значениями по умолчанию + if (!migrated.state.coordinateMode) { + migrated.state.coordinateMode = 'rows'; + } + if (!migrated.state.coordinateDirection) { + migrated.state.coordinateDirection = 'bottom-left'; + } + if (!migrated.state.coordinateSnake) { + migrated.state.coordinateSnake = true; + } + if (!migrated.state.blockWidth) { + migrated.state.blockWidth = 6; + } + if (!migrated.state.blockHeight) { + migrated.state.blockHeight = 2; + } + + return migrated; + } catch (e) { + console.warn('Migration to v2.2 failed, using original data:', e); + return data; + } + }, + saveProgress: () => { try { // Pack painted map if available @@ -2080,7 +2135,7 @@ const progressData = { timestamp: Date.now(), - version: '2.1', + version: '2.2', state: { totalPixels: state.totalPixels, paintedPixels: state.paintedPixels, @@ -2090,6 +2145,12 @@ imageLoaded: state.imageLoaded, colorsChecked: state.colorsChecked, availableColors: state.availableColors, + // Добавляем настройки генерации координат + coordinateMode: state.coordinateMode, + coordinateDirection: state.coordinateDirection, + coordinateSnake: state.coordinateSnake, + blockWidth: state.blockWidth, + blockHeight: state.blockHeight, }, imageData: state.imageData ? { @@ -2117,13 +2178,18 @@ let data = JSON.parse(saved); const ver = data.version; let migrated = data; - if (ver === '2.1') { + + // Миграция для новых версий + if (ver === '2.2') { // already latest + } else if (ver === '2.1') { + migrated = Utils.migrateProgressToV22(data); } else if (ver === '2' || ver === '2.0') { - migrated = Utils.migrateProgressToV21(data); + migrated = Utils.migrateProgressToV22(Utils.migrateProgressToV21(data)); } else { - migrated = Utils.migrateProgressToV21(data); + migrated = Utils.migrateProgressToV22(Utils.migrateProgressToV21(data)); } + if (migrated && migrated !== data) { try { localStorage.setItem('wplace-bot-progress', JSON.stringify(migrated)); @@ -2144,6 +2210,12 @@ state.paintedMap = null; state._lastSavePixelCount = 0; state._lastSaveTime = 0; + // Сбрасываем настройки генерации координат к значениям по умолчанию + state.coordinateMode = 'rows'; + state.coordinateDirection = 'bottom-left'; + state.coordinateSnake = true; + state.blockWidth = 6; + state.blockHeight = 2; console.log('📋 Progress and painted map cleared'); return true; } catch (error) { @@ -2156,6 +2228,23 @@ try { Object.assign(state, savedData.state); + // Восстанавливаем настройки генерации координат + if (savedData.state.coordinateMode) { + state.coordinateMode = savedData.state.coordinateMode; + } + if (savedData.state.coordinateDirection) { + state.coordinateDirection = savedData.state.coordinateDirection; + } + if (savedData.state.coordinateSnake !== undefined) { + state.coordinateSnake = savedData.state.coordinateSnake; + } + if (savedData.state.blockWidth) { + state.blockWidth = savedData.state.blockWidth; + } + if (savedData.state.blockHeight) { + state.blockHeight = savedData.state.blockHeight; + } + if (savedData.imageData) { state.imageData = { ...savedData.imageData, @@ -2241,7 +2330,10 @@ paintedMapPacked: paintedMapPacked, }; - const filename = `wplace-bot-progress-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`; + const filename = `wplace-bot-progress-${new Date() + .toISOString() + .slice(0, 19) + .replace(/:/g, '-')}.json`; Utils.createFileDownloader(JSON.stringify(progressData, null, 2), filename); return true; } catch (error) { @@ -2387,7 +2479,11 @@ try { await ensureToken(); if (!turnstileToken) return 'token_error'; - const payload = { coords: [pixelX, pixelY], colors: [color], t: turnstileToken }; + const payload = { + coords: [pixelX, pixelY], + colors: [color], + t: turnstileToken, + }; const res = await fetch(`https://backend.wplace.live/s0/pixel/${regionX}/${regionY}`, { method: 'POST', headers: { 'Content-Type': 'text/plain;charset=UTF-8' }, @@ -2411,23 +2507,32 @@ }, async getCharges() { + const defaultResult = { + charges: 0, + max: 1, + cooldown: CONFIG.COOLDOWN_DEFAULT, + }; + try { const res = await fetch('https://backend.wplace.live/me', { credentials: 'include', }); + + if (!res.ok) { + console.error(`Failed to get charges: HTTP ${res.status}`); + return defaultResult; + } + const data = await res.json(); + return { - charges: data.charges?.count || 0, - max: data.charges?.max || 1, - cooldown: data.charges?.next || CONFIG.COOLDOWN_DEFAULT, + charges: data.charges?.count ?? 0, + max: data.charges?.max ?? 1, + cooldown: data.charges?.cooldownMs ?? CONFIG.COOLDOWN_DEFAULT, }; } catch (e) { console.error('Failed to get charges:', e); - return { - charges: 0, - max: 1, - cooldown: CONFIG.COOLDOWN_DEFAULT, - }; + return defaultResult; } }, }; @@ -2539,7 +2644,9 @@ function findClosestColor(targetRgb, availableColors) { if (!availableColors || availableColors.length === 0) return 1; - const cacheKey = `${targetRgb[0]},${targetRgb[1]},${targetRgb[2]}|${state.colorMatchingAlgorithm}|${state.enableChromaPenalty ? 'c' : 'nc'}|${state.chromaPenaltyWeight}`; + const cacheKey = `${targetRgb[0]},${targetRgb[1]},${targetRgb[2]}|${ + state.colorMatchingAlgorithm + }|${state.enableChromaPenalty ? 'c' : 'nc'}|${state.chromaPenaltyWeight}`; if (colorCache.has(cacheKey)) return colorCache.get(cacheKey); const whiteThreshold = state.customWhiteThreshold || CONFIG.WHITE_THRESHOLD; @@ -2706,7 +2813,9 @@ if (isAvailable) availableCount++; - const colorItem = Utils.createElement('div', { className: 'wplace-color-item' }); + const colorItem = Utils.createElement('div', { + className: 'wplace-color-item', + }); const swatch = Utils.createElement('button', { className: `wplace-color-swatch ${!isAvailable ? 'unavailable' : ''}`, title: `${name} (ID: ${id})${!isAvailable ? ' (Unavailable)' : ''}`, @@ -2799,7 +2908,15 @@ const token = await Utils.generatePaintToken(sitekey); console.log( - `🔍 Token received - Type: ${typeof token}, Value: ${token ? (typeof token === 'string' ? (token.length > 50 ? token.substring(0, 50) + '...' : token) : JSON.stringify(token)) : 'null/undefined'}, Length: ${token?.length || 0}` + `🔍 Token received - Type: ${typeof token}, Value: ${ + token + ? typeof token === 'string' + ? token.length > 50 + ? token.substring(0, 50) + '...' + : token + : JSON.stringify(token) + : 'null/undefined' + }, Length: ${token?.length || 0}` ); if (typeof token === 'string' && token.length > 20) { @@ -2808,7 +2925,9 @@ return token; } else { throw new Error( - `Invalid or empty token received - Type: ${typeof token}, Value: ${JSON.stringify(token)}, Length: ${token?.length || 0}` + `Invalid or empty token received - Type: ${typeof token}, Value: ${JSON.stringify( + token + )}, Length: ${token?.length || 0}` ); } } catch (error) { @@ -2868,14 +2987,26 @@ const centerY = Math.round(rect.top + rect.height / 2); canvas.dispatchEvent( - new MouseEvent('mousemove', { clientX: centerX, clientY: centerY, bubbles: true }) + new MouseEvent('mousemove', { + clientX: centerX, + clientY: centerY, + bubbles: true, + }) ); canvas.dispatchEvent( - new KeyboardEvent('keydown', { key: ' ', code: 'Space', bubbles: true }) + new KeyboardEvent('keydown', { + key: ' ', + code: 'Space', + bubbles: true, + }) ); await Utils.sleep(50); canvas.dispatchEvent( - new KeyboardEvent('keyup', { key: ' ', code: 'Space', bubbles: true }) + new KeyboardEvent('keyup', { + key: ' ', + code: 'Space', + bubbles: true, + }) ); await Utils.sleep(500); @@ -2950,7 +3081,7 @@ // Link external CSS files const cssLink = document.createElement('link'); cssLink.rel = 'stylesheet'; - cssLink.href = 'https://staninna.github.io/WPlace-AutoBOT/decoupled-css/auto-image-styles.css'; // TODO: Before merge change to https://raw.githubusercontent.com/Wplace-AutoBot/WPlace-AutoBOT/refs/heads/main/auto-image-styles.css + cssLink.href = 'https://skalsech.github.io/WPlace-AutoBOT/my_main/auto-image-styles.css'; cssLink.setAttribute('data-wplace-theme', 'true'); document.head.appendChild(cssLink); @@ -3098,7 +3229,9 @@
-
${Utils.t('initMessage')}
+
${Utils.t( + 'initMessage' + )}
@@ -3187,6 +3320,7 @@
${Math.round(state.overlayOpacity * 100)}%
@@ -3305,6 +3441,121 @@ ${Utils.t('enablePaintingSpeedLimit')} + + +
+ + + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + +
@@ -3378,18 +3629,17 @@
+ - -