您需要先安装一个扩展,例如 篡改猴、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);
- })();