Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // --- PREVENT DUPLICATE LISTENERS ---
- if (window.handleCanvasHUDKeys) {
- window.removeEventListener("keydown", window.handleCanvasHUDKeys);
- }
- // --- CONFIGURATION & INITIAL STATE ---
- let lastDraw = []; // Stores [{char, color}] lines for diff-rendering
- let spawnX = cursor.x;
- let spawnY = cursor.y;
- let typeIndex = 0; // Controls character reveal count
- let typeSpeed = 2.0; // Characters revealed per animation frame
- let typingDone = false;
- let lastRevealedCount = -1;
- let running = true; // Master control loop flag
- // Map to track cursor activity: Map<id, {x, y, lastMoveTime}>
- const cursorActivity = new Map();
- // --- TOGGLES & CONFIGURATION ---
- let showStatus = true; // Displays Active / Idle status bar indicator
- let showCoords = false; // Toggle to show/hide coordinates column
- let showColors = true;
- let showNicknames = true;
- let sortAlphabetical = true;
- let sortByID = false; // Toggle to sort cursors by ID
- let sortByAFK = false; // Toggle to sort cursors by AFK status
- let tickerPaused = true; // Toggle to start/stop the ticker animation
- // --- COLOR CONFIGURATION ---
- const ACTIVE_STATUS_COLOR = 0; // Green for active users
- const AFK_STATUS_COLOR = 0; // Red/Orange for AFK users
- const LOGIN_COLOR = 3; // Green for logged in notifications
- const LOGOUT_COLOR = 4; // Red for logged out notifications
- const CLOCK_COLOR = 0; // <--- Add your preferred color code here
- const NEARBY_COLOR = 0; // <--- Color for the Nearby count (e.g., 2 for Green)
- const ONLINE_COLOR = 0; // <--- Color for the Online count (e.g., 3 for Cyan)
- // --- LOGIN / LOGOUT TRACKING ---
- let trackedCursors = new Map();
- let initializedCursors = false;
- let currentNotification = "";
- let notificationExpireTime = 0;
- const NOTIFICATION_DURATION = 3000; // 3 seconds
- function triggerNotification(msg) {
- currentNotification = msg;
- notificationExpireTime = Date.now() + NOTIFICATION_DURATION;
- }
- // --- SCROLLING / REVEAL TICKER CONFIGURATION ---
- const tickerMessages = [
- "Welcome to tw.2s4.me and stay safe",
- "Please read tw.2s4.me/rules",
- "Join our discord! *",
- " 67 ",
- ];
- let currentMessageIndex = 0;
- let currentFrame = 0;
- let lastTickerStepTime = Date.now();
- const TICKER_STEP_INTERVAL = 470; // Frame animation speed in ms
- const TICKER_PAUSE_DURATION = 5000; // Pause duration between messages in ms
- let isPaused = false;
- let pauseStartTime = 0;
- // HUD & Progress Bar overlay options
- const HUD_CONFIG = {
- enabled: true,
- showDate: false,
- showClock: true,
- showProgress: true,
- showTicker: true,
- tickerMode: "typewriter", // Options: "scroll" or "typewriter"
- barLength: 12,
- barFill: "▓",
- barEmpty: "▒",
- barLeft: " ",
- barRight: " ",
- percentPrecision: 5,
- fixedWidth: 70 // Interior box width precisely sized for aligned columns
- };
- /**
- * Calculates the current ticker text frame based on tickerMode and manages pauses
- */
- function getTickerFrameText() {
- const message = tickerMessages[currentMessageIndex];
- const fullLength = message.length;
- let displayedText = "";
- let totalFrames = 0;
- if (HUD_CONFIG.tickerMode === "typewriter") {
- // --- MODE 1: TYPEWRITER ---
- totalFrames = fullLength;
- if (currentFrame <= fullLength) {
- displayedText = message.substring(0, currentFrame);
- } else {
- displayedText = message;
- }
- } else {
- // --- MODE 2: SCROLLING TICKER ---
- totalFrames = fullLength * 2 + 1;
- if (currentFrame < fullLength) {
- // Phase 1: Text scrolls off to the left
- displayedText = message.substring(currentFrame) + " ".repeat(currentFrame);
- } else {
- // Phase 2: Text scrolls in from the right
- const charsToShow = currentFrame - fullLength;
- displayedText = " ".repeat(fullLength - charsToShow) + message.substring(0, charsToShow);
- }
- }
- // --- MANUAL TICKER PAUSE CONTROL ---
- if (tickerPaused) {
- return displayedText.padEnd(fullLength, " ");
- }
- const now = Date.now();
- // Handle Pause Phase between messages
- if (isPaused) {
- if (now - pauseStartTime >= TICKER_PAUSE_DURATION) {
- isPaused = false;
- currentFrame = 0;
- currentMessageIndex = (currentMessageIndex + 1) % tickerMessages.length;
- lastTickerStepTime = now;
- }
- return displayedText.padEnd(fullLength, " ");
- }
- // Handle Animation Step Clock
- if (now - lastTickerStepTime >= TICKER_STEP_INTERVAL) {
- lastTickerStepTime = now;
- currentFrame++;
- // Check if current message sequence finished -> trigger pause
- if (currentFrame >= totalFrames) {
- isPaused = true;
- pauseStartTime = now;
- }
- }
- return displayedText.padEnd(fullLength, " ");
- }
- /**
- * UTILITY: Extract first number from a string
- */
- function extractNumber(str) {
- const m = str.match(/\d+/);
- return m ? parseInt(m[0], 10) : 0;
- }
- /**
- * UTILITY: Get current (x, y) coordinates for a cursor cleanly
- */
- function getCursorPos(cur) {
- const x = cur?.rawx ?? cur?.l?.[0] ?? 0;
- const y = cur?.rawy ?? cur?.l?.[1] ?? 0;
- return { x, y };
- }
- // --- SERVER TIME SYNC STATE ---
- let serverTimeOffset = 0; // Difference in ms between local time and server time
- let lastSyncTime = 0;
- /**
- * Synchronizes client time with the server using HTTP response headers
- */
- async function syncServerTime() {
- try {
- const t0 = performance.now();
- const response = await fetch(window.location.origin, { method: "HEAD", cache: "no-store" });
- const t1 = performance.now();
- const serverDateHeader = response.headers.get("date");
- if (serverDateHeader) {
- const serverMs = new Date(serverDateHeader).getTime();
- const roundTripTime = t1 - t0;
- // Estimate server time at the moment the response returned
- const estimatedServerTime = serverMs + (roundTripTime / 2);
- serverTimeOffset = estimatedServerTime - Date.now();
- lastSyncTime = Date.now();
- }
- } catch (err) {
- console.warn("Server time sync failed, falling back to client time.", err);
- }
- }
- /**
- * Returns current Date object synchronized with server time
- */
- function getServerTime() {
- return new Date(Date.now() + serverTimeOffset);
- }
- /**
- * Formats synchronized server time as HH:MM:SS AM/PM
- */
- function getServerTimeStr() {
- const d = getServerTime();
- let hrs = d.getHours();
- const mins = d.getMinutes().toString().padStart(2, "0");
- const secs = d.getSeconds().toString().padStart(2, "0");
- const ampm = hrs >= 12 ? "PM" : "AM";
- hrs = hrs % 12;
- hrs = hrs ? hrs : 12; // Convert hour '0' to '12'
- const hrsStr = hrs.toString().padStart(2, "0");
- return `| ${hrsStr}:${mins}:${secs} ${ampm}`;
- }
- // Initial sync on script startup + periodic re-sync every 5 minutes
- syncServerTime();
- setInterval(syncServerTime, 5 * 60 * 1000);
- /**
- * DATE FORMATTER: Formats current date
- */
- function getDateStr() {
- const d = new Date();
- const weekdays = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
- const months = ["", "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
- const w = weekdays[(d.getDay() + 6) % 7];
- const day = d.getDate().toString().padStart(2, "0");
- const month = months[d.getMonth() + 1];
- const year = d.getFullYear();
- return w + day + month + year;
- }
- /**
- * YEAR PROGRESS CALCULATOR: Returns float between 0.0 and 1.0
- */
- function getYearProgress() {
- const now = new Date();
- const start = new Date(now.getFullYear(), 0, 1);
- const end = new Date(now.getFullYear() + 1, 0, 1);
- return Math.min(1, Math.max(0, (now - start) / (end - start)));
- }
- /**
- * Helper text builders for styled/colored cells
- */
- function makeColoredText(text, color) {
- const finalColor = showColors ? color : 0;
- return [...text].map(ch => ({ char: ch, color: finalColor }));
- }
- function makeText(text) {
- return [...text].map(ch => ({ char: ch, color: 0 }));
- }
- /**
- * FIXED-WIDTH BOX ROW CREATOR
- */
- function createBoxRow(cellSegments, targetWidth) {
- let processed = cellSegments;
- if (cellSegments.length > targetWidth) {
- processed = cellSegments.slice(0, targetWidth - 3);
- processed.push({ char: ".", color: 0 }, { char: ".", color: 0 }, { char: ".", color: 0 });
- }
- const row = [{ char: "║", color: 0 }, { char: " ", color: 0 }];
- row.push(...processed);
- const paddingNeeded = Math.max(0, targetWidth - processed.length);
- for (let i = 0; i < paddingNeeded; i++) {
- row.push({ char: " ", color: 0 });
- }
- row.push({ char: " ", color: 0 }, { char: "║", color: 0 });
- return row;
- }
- /**
- * Calculates typewriter animation overlay bounding limits.
- */
- function applyTypewriterMask(rows) {
- let totalChars = 0;
- for (let y = 0; y < rows.length; y++) {
- totalChars += rows[y].length;
- }
- if (typingDone) {
- typeIndex = totalChars;
- }
- let count = 0;
- const masked = [];
- const visibleChars = Math.floor(typeIndex);
- for (let y = 0; y < rows.length; y++) {
- const row = [];
- for (let x = 0; x < rows[y].length; x++) {
- if (count < visibleChars) {
- row.push(rows[y][x]);
- } else {
- row.push({ char: " ", color: 0 });
- }
- count++;
- }
- masked.push(row);
- }
- if (!typingDone) {
- typeIndex += typeSpeed;
- if (typeIndex >= count) {
- typeIndex = count;
- typingDone = true;
- }
- }
- return { masked, count };
- }
- /**
- * Performs frame-by-frame diff comparison to eliminate flickering.
- */
- function drawDiffLines(lines, x0, y0) {
- const maxLines = Math.max(lines.length, lastDraw.length);
- for (let y = 0; y < maxLines; y++) {
- const newLine = lines[y] || [];
- const oldLine = lastDraw[y] || [];
- const maxLen = Math.max(newLine.length, oldLine.length);
- for (let x = 0; x < maxLen; x++) {
- const n = newLine[x] || { char: " ", color: 0 };
- const o = oldLine[x] || { char: " ", color: 0 };
- if (n.char !== o.char || n.color !== o.color) {
- writeCharAt(n.char, n.color, x0 + x, y0 + y);
- }
- }
- }
- lastDraw = lines.map(row => row.map(cell => ({ ...cell })));
- }
- // Reference to observer for cleanup
- let chatObserver = null;
- /**
- * Tears down listeners, observers, and clears text cleanly.
- */
- function stopScript() {
- running = false;
- if (chatObserver) {
- chatObserver.disconnect();
- window._chatAFKObserverActive = false;
- }
- const emptyLines = lastDraw.map(row => row.map(() => ({ char: " ", color: 0 })));
- drawDiffLines(emptyLines, spawnX, spawnY);
- window.removeEventListener("keydown", window.handleCanvasHUDKeys);
- console.log("Script stopped and overlay cleared.");
- }
- /**
- * Handles toggles and script exit.
- */
- window.handleCanvasHUDKeys = function(e) {
- const key = e.key.toLowerCase();
- if (e.key === "`") {
- stopScript();
- }
- if (key === "!") {
- sortAlphabetical = !sortAlphabetical;
- sortByID = false;
- sortByAFK = false;
- typeIndex = 0;
- typingDone = true;
- }
- if (key === "@") {
- sortByID = !sortByID;
- sortAlphabetical = false;
- sortByAFK = false;
- typeIndex = 0;
- typingDone = true;
- }
- if (key === "#") {
- showCoords = !showCoords;
- }
- if (key === "$") {
- showStatus = !showStatus;
- }
- if (key === "%") {
- sortByAFK = !sortByAFK;
- sortAlphabetical = false;
- sortByID = false;
- typeIndex = 0;
- typingDone = false;
- }
- if (key === "^") { // Toggle Ticker Mode between "scroll" and "typewriter"
- HUD_CONFIG.tickerMode = (HUD_CONFIG.tickerMode === "scroll") ? "typewriter" : "scroll";
- currentFrame = 0;
- isPaused = false;
- }
- if (key === "&") { // Toggle start/stop (pause/play) for ticker animation
- tickerPaused = !tickerPaused;
- lastTickerStepTime = Date.now();
- }
- };
- window.addEventListener("keydown", window.handleCanvasHUDKeys);
- function getCursorName(cur) {
- if (!cur) return "Anon";
- if (cur.dn && cur.n && cur.dn !== cur.n) {
- return `${cur.n} (${cur.dn})`;
- }
- return cur.n || cur.dn || "Anon";
- }
- /**
- * Resets the AFK timer for a specific user ID or username
- */
- function resetUserAFK(identifier) {
- if (!identifier) return;
- const cleanId = String(identifier).trim();
- const now = Date.now();
- for (const [id, cur] of w.cursors.entries()) {
- const name = getCursorName(cur);
- if (String(id) === cleanId || name === cleanId || cur.n === cleanId) {
- const { x, y } = getCursorPos(cur);
- cursorActivity.set(id, { x, y, lastMoveTime: now });
- break;
- }
- }
- }
- /**
- * Returns raw idle time in seconds (0 = active)
- */
- function getCursorIdleSeconds(curId, cur) {
- const now = Date.now();
- const { x, y } = getCursorPos(cur);
- const previous = cursorActivity.get(curId);
- if (!previous || previous.x !== x || previous.y !== y) {
- cursorActivity.set(curId, { x, y, lastMoveTime: now });
- return 0;
- }
- return Math.floor((now - previous.lastMoveTime) / 500);
- }
- /**
- * Returns true if the cursor was active in the last 2 seconds.
- */
- function isCursorActive(curId, cur) {
- return getCursorIdleSeconds(curId, cur) < 2;
- }
- (function setupChatAFKReset() {
- if (window._chatAFKObserverActive) return;
- window._chatAFKObserverActive = true;
- function handleNewMessage(msgEl) {
- const userLink = msgEl.querySelector('a[title*="Username:"]');
- if (userLink) {
- const titleAttr = userLink.getAttribute("title");
- const match = titleAttr.match(/Username:\s*([^\n\r]+)/);
- if (match && match[1]) {
- resetUserAFK(match[1].trim());
- }
- }
- }
- chatObserver = new MutationObserver((mutations) => {
- for (const mutation of mutations) {
- for (const node of mutation.addedNodes) {
- if (node.nodeType === 1) {
- if (node.id === "_msg" || node.classList?.contains("fade-in")) {
- handleNewMessage(node);
- } else {
- const msgs = node.querySelectorAll?.('#_msg, .fade-in');
- msgs?.forEach(handleNewMessage);
- }
- }
- }
- }
- });
- chatObserver.observe(document.body, { childList: true, subtree: true });
- })();
- /**
- * Main application loop executing calculations per frame.
- */
- function ut() {
- if (!running) return;
- // Skip computation while the tab is minimized/hidden
- if (document.hidden) {
- requestAnimationFrame(ut);
- return;
- }
- // ============================================================
- // LOGIN / LOGOUT DETECTION
- // ============================================================
- const currentCursors = new Map();
- for (const [id, cur] of w.cursors.entries()) {
- currentCursors.set(String(id), getCursorName(cur));
- }
- if (initializedCursors) {
- for (const [id, name] of currentCursors.entries()) {
- if (!trackedCursors.has(id)) {
- triggerNotification(`${name} joined`);
- }
- }
- for (const [id, name] of trackedCursors.entries()) {
- if (!currentCursors.has(id)) {
- triggerNotification(`${name} left`);
- }
- }
- } else {
- initializedCursors = true;
- }
- trackedCursors = currentCursors;
- const contentSections = [];
- // --- SECTION 1: HUD METRICS, YEAR PROGRESS & TICKER ---
- if (HUD_CONFIG.enabled) {
- const sec1 = [];
- const el = document.getElementById("nearby");
- const nearbyText = el?.textContent?.trim() || "0 nearby";
- const nearbyCount = extractNumber(nearbyText);
- const onlineCount = extractNumber(el?.title || "");
- const dateStr = HUD_CONFIG.showDate ? getDateStr() : "";
- const clockStr = HUD_CONFIG.showClock ? getServerTimeStr() : "";
- // Base status text
- const baseText = `Near: ${nearbyText} | Online: ${onlineCount}`;
- const dateText = dateStr ? ` | ${dateStr}` : "";
- const activeNotice = (Date.now() < notificationExpireTime) ? currentNotification : "";
- const boxInteriorWidth = HUD_CONFIG.fixedWidth || 70;
- // Calculate total text length to handle space padding
- const leftTextLen = baseText.length + (clockStr ? 3 + clockStr.length : 0) + dateText.length;
- const availableSpace = boxInteriorWidth - leftTextLen - activeNotice.length;
- const paddingCount = Math.max(1, availableSpace);
- // Build the character cell array with custom segment colors
- const hudCells = [];
- // 1. Base status text with custom label & counter colors
- const nearLabel = "Near: ";
- const nearNum = `${nearbyText}`;
- const onlineLabel = " ║ Online: ";
- const onlineNum = `${onlineCount}`;
- // "Near: "
- for (const c of nearLabel) {
- hudCells.push({ char: c, color: 0 });
- }
- // Nearby Number
- for (const c of nearNum) {
- hudCells.push({ char: c, color: showColors ? NEARBY_COLOR : 0 });
- }
- // " | Online: "
- for (const c of onlineLabel) {
- hudCells.push({ char: c, color: 0 });
- }
- // Online Number
- for (const c of onlineNum) {
- hudCells.push({ char: c, color: showColors ? ONLINE_COLOR : 0 });
- }
- // 2. Clock segment (Colored using CLOCK_COLOR)
- if (clockStr) {
- hudCells.push(...makeText(" | "));
- for (const c of clockStr) {
- hudCells.push({
- char: c,
- color: showColors ? CLOCK_COLOR : 0
- });
- }
- }
- // 3. Date segment
- if (dateText) {
- hudCells.push(...makeText(dateText));
- }
- // 4. Space Padding
- hudCells.push(...makeText(" ".repeat(paddingCount)));
- // 5. Active Notice (Join / Leave notifications)
- if (activeNotice) {
- const isLogin = activeNotice.includes("joined");
- const noticeColor = showColors ? (isLogin ? LOGIN_COLOR : LOGOUT_COLOR) : 0;
- for (const c of activeNotice) {
- hudCells.push({ char: c, color: noticeColor });
- }
- }
- sec1.push(hudCells);
- if (HUD_CONFIG.showProgress) {
- const progress = getYearProgress();
- const filledUnits = Math.floor(progress * HUD_CONFIG.barLength);
- const fillStr = HUD_CONFIG.barFill || "=";
- const emptyStr = HUD_CONFIG.barEmpty || "-";
- const leftStr = HUD_CONFIG.barLeft || "[";
- const rightStr = HUD_CONFIG.barRight || "]";
- const filled = Array(filledUnits).fill(fillStr).join("");
- const empty = Array(HUD_CONFIG.barLength - filledUnits).fill(emptyStr).join("");
- const percent = (progress * 100).toFixed(HUD_CONFIG.percentPrecision) + "%";
- const barStr = `${leftStr}${filled}${empty}${rightStr} ${percent}`;
- sec1.push(makeText(barStr));
- }
- if (HUD_CONFIG.showTicker) {
- const tickerText = getTickerFrameText();
- sec1.push(makeText(tickerText));
- }
- contentSections.push(sec1);
- }
- // ============================================================
- // SECTION 2: CURSOR LIST ([STATUS SYMBOL] [NAME] [ID] [COORDS])
- // ============================================================
- const sec2 = [];
- let cursorList = Array.from(w.cursors.entries());
- const NAME_WIDTH = 43;
- const ID_WIDTH = 10;
- const COORD_WIDTH = 16;
- const GAP = " ";
- const hasNoneUser = cursorList.some(([_, cur]) => {
- const name = getCursorName(cur).toLowerCase();
- return name === "^" || cur?.n?.toLowerCase() === "^" || cur?.dn?.toLowerCase() === "^";
- });
- if (!hasNoneUser) {
- if (sortByAFK) {
- cursorList.sort((a, b) => {
- const idleA = getCursorIdleSeconds(a[0], a[1]);
- const idleB = getCursorIdleSeconds(b[0], b[1]);
- return idleA - idleB;
- });
- } else if (sortByID) {
- cursorList.sort((a, b) => {
- const idA = extractNumber(String(a[0] || 0));
- const idB = extractNumber(String(b[0] || 0));
- return idA - idB;
- });
- } else if (sortAlphabetical) {
- cursorList.sort((a, b) => {
- const nameA = getCursorName(a[1]).toLowerCase();
- const nameB = getCursorName(b[1]).toLowerCase();
- return nameA.localeCompare(nameB);
- });
- }
- }
- const hName = "USER LIST".padEnd(NAME_WIDTH + 2, " ");
- const hID = "ID".padEnd(ID_WIDTH, " ");
- const hCoords = showCoords ? "COORDS".padEnd(COORD_WIDTH, " ") : "";
- let headerLine = hName + GAP + hID;
- if (showCoords) headerLine += GAP + hCoords;
- sec2.push(makeText(headerLine.trimEnd()));
- for (const [id, cur] of cursorList) {
- if (!cur) continue;
- const unameColor = cur.c || 0;
- let rowSegments = [];
- // --- 1. AFK STATUS INDICATOR ---
- const active = isCursorActive(id, cur);
- const indicatorChar = active ? "▰" : "▱";
- const indicatorColor = active ? ACTIVE_STATUS_COLOR : AFK_STATUS_COLOR;
- if (showStatus) {
- rowSegments.push(...makeColoredText(indicatorChar, indicatorColor));
- rowSegments.push(...makeText(" "));
- } else {
- rowSegments.push(...makeText(" "));
- }
- // --- 2. USERNAME ---
- let rawName = showNicknames ? getCursorName(cur) : "Anon";
- if (rawName.length > NAME_WIDTH) {
- rawName = rawName.slice(0, NAME_WIDTH - 3) + "...";
- }
- const paddedName = rawName.padEnd(NAME_WIDTH, " ");
- rowSegments.push(...makeColoredText(paddedName, unameColor));
- // --- 3. ID ---
- const rawID = String(cur.id ?? id ?? "?");
- const paddedID = rawID.padEnd(ID_WIDTH, " ");
- rowSegments.push(...makeText(GAP + paddedID));
- // --- 4. COORDINATES ---
- if (showCoords) {
- const { x, y } = getCursorPos(cur);
- const rawCoord = `(${x},${y})`;
- const paddedCoord = rawCoord.padEnd(COORD_WIDTH, " ");
- rowSegments.push(...makeText(GAP + paddedCoord));
- }
- sec2.push(rowSegments);
- }
- if (sec2.length === 1) {
- sec2.push(makeText("No active cursors"));
- }
- contentSections.push(sec2);
- // ============================================================
- // SECTION 3: FOOTER METRICS
- // ============================================================
- const sec3 = [];
- const sortLabel = hasNoneUser
- ? "Disabled (^)"
- : (sortByAFK ? "AFK" : (sortByID ? "ID" : (sortAlphabetical ? "A-Z" : "Default")));
- sec3.push(makeText("Sorted: " + sortLabel));
- contentSections.push(sec3);
- // ============================================================
- // RENDER BOX STRUCTURE
- // ============================================================
- const targetWidth = HUD_CONFIG.fixedWidth || 70;
- const borderChar = "═".repeat(targetWidth + 2);
- const rows = [];
- rows.push(makeText(`╔${borderChar}╗`));
- contentSections.forEach((sec, idx) => {
- for (const rowCells of sec) {
- rows.push(createBoxRow(rowCells, targetWidth));
- }
- if (idx < contentSections.length - 1) {
- rows.push(makeText(`╟${borderChar}╢`));
- } else {
- rows.push(makeText(`╚${borderChar}╝`));
- }
- });
- const { masked } = applyTypewriterMask(rows);
- const currentRevealed = Math.floor(typeIndex);
- if (currentRevealed !== lastRevealedCount || typingDone) {
- drawDiffLines(masked, spawnX, spawnY);
- lastRevealedCount = currentRevealed;
- }
- requestAnimationFrame(ut);
- }
- ut();
Advertisement
Comments
-
Comment was deleted
-
- Press 1 to sort A to Z
- Press 2 to sort by ID
- Press 3 to show coords
-
- Hotkeys:
- --------------------
- b = sort by AFK Time
- z = sort by A-Z
- x = sort by ID
- c = toggle coords on/of
- v = toggle afk time on/off
Add Comment
Please, Sign In to add comment