您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Powerline.io Spectator Mode
// ==UserScript== // @name Powerline Spectator Mode // @author Rumini - Discord: rumini // @description Powerline.io Spectator Mode // @version 1.0 // @match *://powerline.io/* // @icon https://i.imgur.com/9k4SFr0.png // @license MIT // @grant none // @namespace https://greasyfork.org/users/1356205 // ==/UserScript== if (window.location.href === 'https://powerline.io/') { window.location.href = 'https://powerline.io/maindev.html'; } (function () { 'use strict'; let currentSpectateIndex = 0; let switcherButton; let overlayToggleButton; let isSpectating = false; let infoDiv; let updateInterval; let lastKnownLocalPlayerID = 0; let overlayVisible = true; let forceOverlayVisible = false; function waitForGame(callback) { if (typeof network !== 'undefined' && typeof entities !== 'undefined' && typeof Snake !== 'undefined') { callback(); } else { setTimeout(() => waitForGame(callback), 100); } } function createSpectateSwitcherUI() { const container = document.createElement('div'); container.id = 'spectate-switcher-container'; container.style.cssText = ` position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 1000; opacity: 0; transition: opacity 0.3s ease-in-out; display: flex; align-items: center; gap: 10px; `; switcherButton = document.createElement('button'); switcherButton.id = 'spectate-switcher'; switcherButton.style.cssText = ` background-color: rgba(0, 58, 58, 0.4); color: #05ffff; border: 2px solid rgba(5, 255, 255, 0.5); border-radius: 10px; padding: 10px 20px; font-family: 'Arial Black', sans-serif; font-size: 16px; cursor: pointer; backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); transition: all 0.3s ease; `; switcherButton.textContent = 'Switch Spectate'; switcherButton.addEventListener('click', switchSpectatePlayer); switcherButton.addEventListener('mouseover', () => { switcherButton.style.backgroundColor = 'rgba(0, 88, 88, 0.5)'; switcherButton.style.transform = 'scale(1.05)'; switcherButton.style.boxShadow = '0 0 15px rgba(5, 255, 255, 0.2)'; }); switcherButton.addEventListener('mouseout', () => { switcherButton.style.backgroundColor = 'rgba(0, 58, 58, 0.3)'; switcherButton.style.transform = 'scale(1)'; switcherButton.style.boxShadow = 'none'; }); overlayToggleButton = document.createElement('div'); overlayToggleButton.id = 'overlay-toggle-button'; overlayToggleButton.style.cssText = ` width: 50px; height: 50px; border-radius: 50%; background-color: rgba(0, 58, 58, 0.4); border: 2px solid rgba(5, 255, 255, 0.5); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s ease; `; overlayToggleButton.innerHTML = ` <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="24" height="24"> <path fill="#00ffff" d="M15 15C24.4 5.7 39.6 5.7 49 15l63 63L112 40c0-13.3 10.7-24 24-24s24 10.7 24 24l0 96c0 13.3-10.7 24-24 24l-96 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l38.1 0L15 49C5.7 39.6 5.7 24.4 15 15zM133.5 243.9C158.6 193.6 222.7 112 320 112s161.4 81.6 186.5 131.9c3.8 7.6 3.8 16.5 0 24.2C481.4 318.4 417.3 400 320 400s-161.4-81.6-186.5-131.9c-3.8-7.6-3.8-16.5 0-24.2zM320 320a64 64 0 1 0 0-128 64 64 0 1 0 0 128zM591 15c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-63 63 38.1 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-96 0c-13.3 0-24-10.7-24-24l0-96c0-13.3 10.7-24 24-24s24 10.7 24 24l0 38.1 63-63zM15 497c-9.4-9.4-9.4-24.6 0-33.9l63-63L40 400c-13.3 0-24-10.7-24-24s10.7-24 24-24l96 0c13.3 0 24 10.7 24 24l0 96c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-38.1L49 497c-9.4 9.4-24.6 9.4-33.9 0zm576 0l-63-63 0 38.1c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-96c0-13.3 10.7-24 24-24l96 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-38.1 0 63 63c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0z"/> </svg> `; overlayToggleButton.addEventListener('click', toggleOverlay); overlayToggleButton.addEventListener('mouseover', () => { overlayToggleButton.style.backgroundColor = 'rgba(0, 88, 88, 0.5)'; overlayToggleButton.style.transform = 'scale(1.1)'; overlayToggleButton.style.boxShadow = '0 0 15px rgba(5, 255, 255, 0.2)'; }); overlayToggleButton.addEventListener('mouseout', () => { overlayToggleButton.style.backgroundColor = 'rgba(0, 58, 58, 0.3)'; overlayToggleButton.style.transform = 'scale(1)'; overlayToggleButton.style.boxShadow = 'none'; }); infoDiv = document.createElement('div'); infoDiv.id = 'spectate-info'; infoDiv.style.cssText = ` position: fixed; bottom: 200px; right: 20px; z-index: 1000; background-color: rgba(0, 58, 58, 0.3); border: 2px solid rgba(5, 255, 255, 0.8); border-radius: 10px; padding: 0 20px 20px 20px; font-family: 'Arial', sans-serif; font-size: 14px; color: #05ffff; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: 0 0 20px rgba(5, 255, 255, 0.5); transition: opacity 0.3s ease, box-shadow 1s ease; max-width: 400px; word-wrap: break-word; opacity: 0; `; container.appendChild(switcherButton); container.appendChild(overlayToggleButton); document.body.appendChild(container); document.body.appendChild(infoDiv); setInterval(updateButtonVisibility, 100); setInterval(updateInfoBoxGlow, 50); document.addEventListener('keydown', function (event) { if (event.code === 'Space') { if (isSpectating || localPlayerID === 0) { isSpectating = false; clearInterval(updateInterval); infoDiv.style.opacity = '0'; } updateButtonVisibility(); } }); setOverlayVisibility(true); } function updateButtonVisibility() { const container = document.getElementById('spectate-switcher-container'); if (localPlayerID !== 0 && lastKnownLocalPlayerID === 0) { isSpectating = false; clearInterval(updateInterval); infoDiv.style.opacity = '0'; forceOverlayVisible = false; } if (localPlayerID === 0 && lastKnownLocalPlayerID !== 0) { forceOverlayVisible = true; setOverlayVisibility(true); } lastKnownLocalPlayerID = localPlayerID; if (localPlayerID === 0 || isSpectating) { container.style.opacity = '1'; infoDiv.style.opacity = isSpectating ? '1' : '0'; } else { container.style.opacity = '0'; infoDiv.style.opacity = '0'; } } function setOverlayVisibility(visible) { const overlay = document.getElementById('overlay'); if (overlay) { overlayVisible = visible; overlay.style.opacity = visible ? '1' : '0'; } } function toggleOverlay() { if (forceOverlayVisible) { forceOverlayVisible = false; } setOverlayVisibility(!overlayVisible); } function updateInfoBoxGlow() { const glowIntensity = Math.sin(Date.now() * 0.0005) * 5 + 15; infoDiv.style.boxShadow = `0 0 ${glowIntensity}px rgba(5, 255, 255, 0.7)`; } function switchSpectatePlayer() { const keys = Object.keys(entities); if (keys.length === 0) return; let found = false; for (let i = 0; i < keys.length; i++) { currentSpectateIndex = (currentSpectateIndex + 1) % keys.length; const entity = entities[keys[currentSpectateIndex]]; if (entity instanceof Snake && entity !== localPlayer) { localPlayer = entity; camera.target = localPlayer; updateInfoDiv(entity); clearInterval(updateInterval); updateInterval = setInterval(() => updateInfoDiv(entity), 100); isSpectating = true; found = true; break; } } if (!found) { hud.addSpecialMessage("No other snakes are close enough to spectate."); } updateButtonVisibility(); } function updateInfoDiv(entity) { if (!entity || entity.id === 0) { infoDiv.style.opacity = '0'; return; } const entityInfo = ` <h3>Spectating: ${entity.nick || '<unnamed>'}</h3> <b>ID:</b> ${entity.id}<br> <b>Current Length:</b> ${entity.curLength.toFixed(2)}<br> <b>Total Length:</b> ${entity.curLengthDst.toFixed(2)}<br> <b>Last Speed:</b> ${entity.lastSpeed.toFixed(2)}<br> <b>Client X:</b> ${entity.x.toFixed(2)}<br> <b>Client Y:</b> ${entity.y.toFixed(2)}<br> <b>Server X:</b> ${entity.lastServerX.toFixed(2)}<br> <b>Server Y:</b> ${entity.lastServerY.toFixed(2)}<br> `; infoDiv.innerHTML = entityInfo; infoDiv.style.opacity = '1'; } waitForGame(createSpectateSwitcherUI); })();