mirror of
https://github.com/tiennm99/WPlace-AutoBOT.git
synced 2026-10-13 14:15:48 +00:00
Biggest optimization yet
This commit is contained in:
1 parent
a4968a441c
commit
f4fdc1bbfe
1 file changed
+103
-79
+103
-79
@@ -134,7 +134,9 @@
|
||||
},
|
||||
"Neon Retro": {
|
||||
primary: "#1a1a2e",
|
||||
secondary: "#16213e",
|
||||
availableColors: [], // Default to empty array
|
||||
activeColorPalette: [], // User-selected colors for conversion
|
||||
paintWhitePixels: true, // Default to ON
|
||||
accent: "#0f3460",
|
||||
text: "#00ff41",
|
||||
highlight: "#ff6b35",
|
||||
@@ -1239,7 +1241,7 @@
|
||||
totalPixels: state.imageData.totalPixels,
|
||||
}
|
||||
: null,
|
||||
paintedMap: state.paintedMap ? state.paintedMap.map((row) => Array.from(row)) : null,
|
||||
paintedMap: state.paintedMap ? Array.from(state.paintedMap) : null,
|
||||
}
|
||||
|
||||
localStorage.setItem("wplace-bot-progress", JSON.stringify(progressData))
|
||||
@@ -1273,6 +1275,9 @@
|
||||
restoreProgress: (savedData) => {
|
||||
try {
|
||||
Object.assign(state, savedData.state)
|
||||
if (state.availableColors && state.availableColors.length) {
|
||||
primeColorHelpers();
|
||||
}
|
||||
|
||||
if (savedData.imageData) {
|
||||
state.imageData = {
|
||||
@@ -1282,7 +1287,7 @@
|
||||
}
|
||||
|
||||
if (savedData.paintedMap) {
|
||||
state.paintedMap = savedData.paintedMap.map((row) => Array.from(row))
|
||||
state.paintedMap = new Uint8Array(savedData.paintedMap);
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -1315,7 +1320,7 @@
|
||||
totalPixels: state.imageData.totalPixels,
|
||||
}
|
||||
: null,
|
||||
paintedMap: state.paintedMap ? state.paintedMap.map((row) => Array.from(row)) : null,
|
||||
paintedMap: state.paintedMap ? Array.from(state.paintedMap) : null,
|
||||
}
|
||||
|
||||
const filename = `wplace-bot-progress-${new Date().toISOString().slice(0, 19).replace(/:/g, "-")}.json`
|
||||
@@ -1502,45 +1507,59 @@
|
||||
}
|
||||
|
||||
// COLOR MATCHING FUNCTION - Optimized with caching
|
||||
const colorCache = new Map()
|
||||
// Improved color cache using integer keys & squared distance (avoid sqrt)
|
||||
const colorCache = new Map(); // key: 24-bit int -> color id
|
||||
let cachedWhiteId = null;
|
||||
|
||||
function primeColorHelpers() {
|
||||
cachedWhiteId = null;
|
||||
for (let i = 0; i < state.availableColors.length; i++) {
|
||||
const c = state.availableColors[i];
|
||||
if (c.rgb[0] >= 250 && c.rgb[1] >= 250 && c.rgb[2] >= 250) {
|
||||
cachedWhiteId = c.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findClosestColor(targetRgb, availableColors) {
|
||||
const cacheKey = `${targetRgb[0]},${targetRgb[1]},${targetRgb[2]}`
|
||||
const key = (targetRgb[0] << 16) | (targetRgb[1] << 8) | targetRgb[2];
|
||||
const cached = colorCache.get(key);
|
||||
if (cached !== undefined) return cached;
|
||||
|
||||
if (colorCache.has(cacheKey)) {
|
||||
return colorCache.get(cacheKey)
|
||||
// Fast path for white-ish
|
||||
if (cachedWhiteId !== null && targetRgb[0] >= 250 && targetRgb[1] >= 250 && targetRgb[2] >= 250) {
|
||||
colorCache.set(key, cachedWhiteId);
|
||||
return cachedWhiteId;
|
||||
}
|
||||
|
||||
const isNearWhite = targetRgb[0] >= 250 && targetRgb[1] >= 250 && targetRgb[2] >= 250
|
||||
if (isNearWhite) {
|
||||
const whiteEntry = availableColors.find(c => c.rgb[0] >= 250 && c.rgb[1] >= 250 && c.rgb[2] >= 250)
|
||||
if (whiteEntry) {
|
||||
colorCache.set(cacheKey, whiteEntry.id)
|
||||
return whiteEntry.id
|
||||
}
|
||||
}
|
||||
|
||||
let minDistance = Number.POSITIVE_INFINITY
|
||||
let closestColorId = availableColors[0]?.id || 1
|
||||
|
||||
let bestId = availableColors[0]?.id || 1;
|
||||
let bestDist = 1e12;
|
||||
const tr = targetRgb[0];
|
||||
const tg = targetRgb[1];
|
||||
const tb = targetRgb[2];
|
||||
for (let i = 0; i < availableColors.length; i++) {
|
||||
const color = availableColors[i]
|
||||
const distance = Utils.colorDistance(targetRgb, color.rgb)
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance
|
||||
closestColorId = color.id
|
||||
if (distance === 0) break
|
||||
const c = availableColors[i];
|
||||
const cr = c.rgb[0] - tr;
|
||||
const cg = c.rgb[1] - tg;
|
||||
const cb = c.rgb[2] - tb;
|
||||
const dist = cr * cr + cg * cg + cb * cb; // squared distance
|
||||
if (dist < bestDist) {
|
||||
bestDist = dist;
|
||||
bestId = c.id;
|
||||
if (dist === 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
colorCache.set(cacheKey, closestColorId)
|
||||
|
||||
if (colorCache.size > 10000) {
|
||||
const firstKey = colorCache.keys().next().value
|
||||
colorCache.delete(firstKey)
|
||||
colorCache.set(key, bestId);
|
||||
// Simple LRU trim
|
||||
if (colorCache.size > 20000) {
|
||||
let n = 0;
|
||||
for (const k of colorCache.keys()) { // trim first 1000 entries
|
||||
colorCache.delete(k);
|
||||
if (++n > 1000) break;
|
||||
}
|
||||
}
|
||||
|
||||
return closestColorId
|
||||
return bestId;
|
||||
}
|
||||
|
||||
// UI UPDATE FUNCTIONS (declared early to avoid reference errors)
|
||||
@@ -4084,6 +4103,7 @@
|
||||
|
||||
if (!state.colorsChecked) {
|
||||
state.availableColors = availableColors;
|
||||
primeColorHelpers();
|
||||
state.colorsChecked = true;
|
||||
updateUI("colorsFound", "success", { count: availableColors.length });
|
||||
updateStats();
|
||||
@@ -4339,27 +4359,28 @@
|
||||
const startRow = state.lastPosition.y || 0
|
||||
const startCol = state.lastPosition.x || 0
|
||||
|
||||
// Use a flat Uint8Array as bitset for painted map for memory & speed
|
||||
if (!state.paintedMap) {
|
||||
state.paintedMap = Array(height)
|
||||
.fill()
|
||||
.map(() => Array(width).fill(false))
|
||||
state.paintedMap = new Uint8Array(width * height);
|
||||
}
|
||||
|
||||
let pixelBatch = null;
|
||||
|
||||
try {
|
||||
let lastStatsUpdate = 0;
|
||||
const statsUpdateInterval = 1500; // ms
|
||||
outerLoop: for (let y = startRow; y < height; y++) {
|
||||
const rowOffset = y * width;
|
||||
for (let x = y === startRow ? startCol : 0; x < width; x++) {
|
||||
if (state.stopFlag) {
|
||||
if (pixelBatch > 0 && pixelBatch.pixels.length > 0) {
|
||||
if (pixelBatch && pixelBatch.pixels.length > 0) {
|
||||
await sendPixelBatch(pixelBatch.pixels, pixelBatch.regionX, pixelBatch.regionY);
|
||||
}
|
||||
state.lastPosition = { x, y }
|
||||
updateUI("paintingPaused", "warning", { x, y })
|
||||
break outerLoop
|
||||
}
|
||||
|
||||
if (state.paintedMap[y][x]) continue
|
||||
if (state.paintedMap[rowOffset + x]) continue
|
||||
|
||||
const idx = (y * width + x) * 4
|
||||
const r = pixels[idx]
|
||||
@@ -4388,19 +4409,22 @@
|
||||
let pixelX = absX % 1000;
|
||||
let pixelY = absY % 1000;
|
||||
|
||||
if (!pixelBatch ||
|
||||
pixelBatch.regionX !== regionX + adderX ||
|
||||
pixelBatch.regionY !== regionY + adderY) {
|
||||
if (!pixelBatch || pixelBatch.regionX !== regionX + adderX || pixelBatch.regionY !== regionY + adderY) {
|
||||
|
||||
if (pixelBatch && pixelBatch.pixels.length > 0) {
|
||||
let success = await sendPixelBatch(pixelBatch.pixels, pixelBatch.regionX, pixelBatch.regionY);
|
||||
if (success) {
|
||||
pixelBatch.pixels.forEach((p) => {
|
||||
state.paintedMap[p.localY][p.localX] = true;
|
||||
for (let i = 0; i < pixelBatch.pixels.length; i++) {
|
||||
const p = pixelBatch.pixels[i];
|
||||
state.paintedMap[p.localY * width + p.localX] = 1;
|
||||
state.paintedPixels++;
|
||||
});
|
||||
}
|
||||
state.currentCharges -= pixelBatch.pixels.length;
|
||||
updateStats();
|
||||
const now = performance.now();
|
||||
if (now - lastStatsUpdate > statsUpdateInterval) {
|
||||
updateStats();
|
||||
lastStatsUpdate = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4446,26 +4470,25 @@
|
||||
}
|
||||
|
||||
if (success) {
|
||||
pixelBatch.pixels.forEach((pixel) => {
|
||||
state.paintedMap[pixel.localY][pixel.localX] = true;
|
||||
for (let i = 0; i < pixelBatch.pixels.length; i++) {
|
||||
const pix = pixelBatch.pixels[i];
|
||||
state.paintedMap[pix.localY * width + pix.localX] = 1;
|
||||
state.paintedPixels++;
|
||||
})
|
||||
|
||||
state.currentCharges -= pixelBatch.pixels.length;
|
||||
updateStats()
|
||||
updateUI("paintingProgress", "default", {
|
||||
painted: state.paintedPixels,
|
||||
total: state.totalPixels,
|
||||
})
|
||||
|
||||
if (state.paintedPixels % 50 === 0) {
|
||||
Utils.saveProgress()
|
||||
}
|
||||
|
||||
if (CONFIG.PAINTING_SPEED_ENABLED && state.paintingSpeed > 0 && pixelBatch.length > 0) {
|
||||
const delayPerPixel = 1000 / state.paintingSpeed // ms per pixel
|
||||
const totalDelay = Math.max(100, delayPerPixel * pixelBatch.length) // minimum 100ms
|
||||
await Utils.sleep(totalDelay)
|
||||
state.currentCharges -= pixelBatch.pixels.length;
|
||||
const now = performance.now();
|
||||
if (now - lastStatsUpdate > statsUpdateInterval) {
|
||||
updateStats();
|
||||
updateUI("paintingProgress", "default", { painted: state.paintedPixels, total: state.totalPixels });
|
||||
lastStatsUpdate = now;
|
||||
}
|
||||
if ((state.paintedPixels & 0x3F) === 0) { // every 64
|
||||
Utils.saveProgress();
|
||||
}
|
||||
if (CONFIG.PAINTING_SPEED_ENABLED && state.paintingSpeed > 0) {
|
||||
const delayPerPixel = 1000 / state.paintingSpeed;
|
||||
const totalDelay = Math.max(50, delayPerPixel * pixelBatch.pixels.length);
|
||||
await Utils.sleep(totalDelay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4482,12 +4505,12 @@
|
||||
break;
|
||||
}
|
||||
|
||||
updateUI("noChargesThreshold", "warning", {
|
||||
time: Utils.formatTime(state.cooldown),
|
||||
threshold: state.cooldownChargeThreshold,
|
||||
current: state.currentCharges
|
||||
});
|
||||
await updateStats();
|
||||
const now = performance.now();
|
||||
if (now - lastStatsUpdate > statsUpdateInterval) {
|
||||
updateUI("noChargesThreshold", "warning", { time: Utils.formatTime(state.cooldown), threshold: state.cooldownChargeThreshold, current: state.currentCharges });
|
||||
updateStats();
|
||||
lastStatsUpdate = now;
|
||||
}
|
||||
await Utils.sleep(state.cooldown);
|
||||
}
|
||||
if (state.stopFlag) break outerLoop;
|
||||
@@ -4498,15 +4521,16 @@
|
||||
if (pixelBatch && pixelBatch.pixels.length > 0 && !state.stopFlag) {
|
||||
const success = await sendPixelBatch(pixelBatch.pixels, pixelBatch.regionX, pixelBatch.regionY);
|
||||
if (success) {
|
||||
pixelBatch.pixels.forEach((pixel) => {
|
||||
state.paintedMap[pixel.localY][pixel.localX] = true
|
||||
state.paintedPixels++
|
||||
})
|
||||
for (let i = 0; i < pixelBatch.pixels.length; i++) {
|
||||
const p = pixelBatch.pixels[i];
|
||||
state.paintedMap[p.localY * width + p.localX] = 1;
|
||||
state.paintedPixels++;
|
||||
}
|
||||
state.currentCharges -= pixelBatch.pixels.length;
|
||||
if (CONFIG.PAINTING_SPEED_ENABLED && state.paintingSpeed > 0 && pixelBatch.length > 0) {
|
||||
const delayPerPixel = 1000 / state.paintingSpeed // ms per pixel
|
||||
const totalDelay = Math.max(100, delayPerPixel * pixelBatch.length) // minimum 100ms
|
||||
await Utils.sleep(totalDelay)
|
||||
if (CONFIG.PAINTING_SPEED_ENABLED && state.paintingSpeed > 0) {
|
||||
const delayPerPixel = 1000 / state.paintingSpeed;
|
||||
const totalDelay = Math.max(50, delayPerPixel * pixelBatch.pixels.length);
|
||||
await Utils.sleep(totalDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user