Powerline Spectator Mode

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://gf.qytechs.cn/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);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址