吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3|回复: 0
收起左侧

[Python 原创] LOL 大乱斗换人助手 - 没有手速,全是科技!

[复制链接]
PJlay 发表于 2026-9-18 23:21

大乱斗换人别拼手速!一个小工具,看中谁,点一下就换!

兄弟们,大乱斗最痛苦的瞬间是什么?

不是被分到亚索,而是替补席明明躺着一个“救世主”,刚准备点击——没了。

只能默默感慨一句:卧槽,哥们手速真快!

所以我做了个小工具:ARAM Picker(大乱斗换人助手)

1

1

2

2

功能介绍

  • 自动检测英雄联盟客户端
  • 自动接受对局(可关闭)
  • 自动识别大乱斗选人阶段
  • 显示当前英雄、替补席英雄和倒计时
  • 点击替补英雄即可发起交换
  • 遇到交换冷却时自动等待并重试
  • 目标英雄被队友换走后自动取消等待
  • 支持可选的自动接受对局
  • 进入选人阶段自动置顶窗口
  • 英雄名称优先读取客户端中文数据

使用方法

  1. 启动英雄联盟客户端和本工具
  2. 进入大乱斗选人阶段
  3. 在左侧列表点击想交换的英雄
  4. 等待交换完成,开始快乐游戏

注意事项

本代码没有明显的注入型外挂行为,只通过本机英雄联盟客户端的 LCU 接口读取选人状态,调用替补交换和自动接受对局接口。
理论上不会封号,但凡事没有绝对,所以大家使用前请自行评估封号风险(我个人测试了挺久,都是没问题的)

如果你也经历过“想换的英雄永远在队友手里”,欢迎试试。
愿大家每局都能换到心仪英雄,少玩折磨阵容,多玩快乐大乱斗



完整源码https://github.com/lay-codes/aram-picker
赠人玫瑰,手有余香。方便的话,感谢各位大佬,帮忙点个星,万分感谢!

exe下载链接:https://wwalt.lanzouw.com/ifEi248znouf 密码:52pj

关键代码:
[Python] 纯文本查看 复制代码
import json
import os
import threading
from pathlib import Path
import psutil
import requests
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


class LCUConnector:
    """连接本机英雄联盟客户端接口。"""

    def __init__(self):
        self.port = None
        self.auth_token = None
        self.base_url = None
        self.session = None
        self._http_lock = threading.Lock()

    @property
    def connected(self):
        return self.session is not None

    def connect(self):
        return self._try_lockfile() or self._try_process_args()

    def _try_lockfile(self):
        paths = []
        for process in psutil.process_iter(["name", "exe"]):
            try:
                name = process.info.get("name") or ""
                executable = process.info.get("exe")
                if name.startswith("LeagueClient") and executable:
                    paths.append(Path(executable).parent / "lockfile")
            except (psutil.Error, OSError):
                continue

        for env_name in ("LOCALAPPDATA", "PROGRAMFILES", "PROGRAMFILES(X86)"):
            base = os.environ.get(env_name)
            if base:
                paths.append(Path(base) / "Riot Games" / "LeagueClient" / "lockfile")

        for path in dict.fromkeys(paths):
            try:
                # 锁文件的端口和令牌分别在第三、第四段
                parts = path.read_text(encoding="utf-8").strip().split(":")
                if len(parts) < 5:
                    continue
                self.port, self.auth_token = parts[2], parts[3]
                self._setup_session()
                return True
            except (OSError, UnicodeError):
                continue
        return False

    def _try_process_args(self):
        for process in psutil.process_iter(["name", "cmdline"]):
            try:
                if process.info.get("name") != "LeagueClientUx.exe":
                    continue
                port = self._argument_value(process.info.get("cmdline") or [], "--app-port")
                token = self._argument_value(
                    process.info.get("cmdline") or [], "--remoting-auth-token"
                )
                if port and token:
                    self.port, self.auth_token = port, token
                    self._setup_session()
                    return True
            except (psutil.Error, OSError):
                continue
        return False

    @staticmethod
    def _argument_value(arguments, option):
        for index, argument in enumerate(arguments):
            if argument == option and index + 1 < len(arguments):
                return arguments[index + 1]
            if argument.startswith(f"{option}="):
                return argument.split("=", 1)[1]
        return None

    def _setup_session(self):
        self.base_url = f"https://127.0.0.1:{self.port}"
        self.session = requests.Session()
        self.session.auth = ("riot", self.auth_token)
        self.session.verify = False
        self.session.headers.update(
            {"Accept": "application/json", "Content-Type": "application/json"}
        )

    def reset(self):
        with self._http_lock:
            if self.session:
                self.session.close()
            self.session = None
            self.base_url = None
            self.port = None
            self.auth_token = None

    def get(self, endpoint):
        try:
            with self._http_lock:
                if not self.session:
                    return None, 0
                response = self.session.get(f"{self.base_url}{endpoint}", timeout=5)
            if response.status_code != 200:
                return None, response.status_code
            try:
                return response.json(), 200
            except requests.JSONDecodeError:
                return None, 200
        except requests.RequestException:
            return None, 0

    def post(self, endpoint):
        try:
            with self._http_lock:
                if not self.session:
                    return False, 0, {"error": "客户端未连接"}
                response = self.session.post(f"{self.base_url}{endpoint}", timeout=5)
            try:
                body = response.json()
            except requests.JSONDecodeError:
                body = {}
            return response.status_code in (200, 201, 204), response.status_code, body
        except requests.RequestException as error:
            return False, 0, {"error": str(error)}


class ChampionNameMapper:
    """加载并缓存英雄中文名。"""

    def __init__(self, cache_file=None):
        self.name_map = {}
        self.cache_file = cache_file or self._default_cache_file()

    @staticmethod
    def _default_cache_file():
        if local_app_data := os.environ.get("LOCALAPPDATA"):
            return Path(local_app_data) / "ARAM Picker" / "champion_names.json"
        return Path.home() / ".aram_picker" / "champion_names.json"

    def load(self, lcu=None):
        if lcu and lcu.connected and self._fetch_local(lcu):
            self._save_cache()
            return True
        if self._load_cache():
            return True
        if self._fetch_datadragon():
            self._save_cache()
            return True
        return False

    def _load_cache(self):
        try:
            data = json.loads(self.cache_file.read_text(encoding="utf-8"))
            self.name_map = {int(key): value for key, value in data.items()}
            return bool(self.name_map)
        except (OSError, ValueError, TypeError, AttributeError):
            return False

    def _save_cache(self):
        try:
            self.cache_file.parent.mkdir(parents=True, exist_ok=True)
            content = json.dumps(self.name_map, ensure_ascii=False, indent=2)
            self.cache_file.write_text(content, encoding="utf-8")
        except OSError:
            pass

    def _fetch_local(self, lcu):
        data, _ = lcu.get("/lol-game-data/assets/v1/champion-summary.json")
        if not isinstance(data, list):
            return False

        names = {}
        for champion in data:
            if not isinstance(champion, dict):
                continue
            champion_id = champion.get("id", -1)
            name = champion.get("name") or champion.get("alias")
            if isinstance(champion_id, int) and champion_id > 0 and name:
                names[champion_id] = str(name)
        if names:
            self.name_map = names
        return bool(names)

    def _fetch_datadragon(self):
        try:
            versions_response = requests.get(
                "https://ddragon.leagueoflegends.com/api/versions.json", timeout=10
            )
            versions_response.raise_for_status()
            versions = versions_response.json()
            if not versions:
                return False

            champions_response = requests.get(
                "https://ddragon.leagueoflegends.com/cdn/"
                f"{versions[0]}/data/zh_CN/champion.json",
                timeout=10,
            )
            champions_response.raise_for_status()
            champions = champions_response.json()["data"].values()
            self.name_map = {
                int(champion["key"]): champion["name"] for champion in champions
            }
            return bool(self.name_map)
        except (requests.RequestException, KeyError, TypeError, ValueError):
            return False

    def get_name(self, champion_id):
        return self.name_map.get(champion_id, f"英雄#{champion_id}")

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-9-18 23:22

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表