Waydroid Blue Archive Fix

TLDR

如果你是ARM平台的linux,不用修,直接能用。
x86_64平台:

  1. waydroid_script安装libndk或者libhoudini实现arm64
  2. libndk patch或者libhoudini patch

01 转译层

已经安装的可以跳过。

需要先安装lzipsudo apt install lzip或者nix-shell -p lzip,按你的发行版来
使用waydroid_script安装转译层:

git clone https://github.com/casualsnek/waydroid_script
cd waydroid_script
python3 -m venv venv
venv/bin/pip install -r requirements.txt

AMD用户安装libndk,intel用libhoudini

sudo venv/bin/python3 main.py install libndk   # AMD
sudo venv/bin/python3 main.py install libhoudini   # INTEL

02 修复转译层

修复NDK

scripton_ndk.txt,重命名成sh后缀然后执行
原始issue

修复Houdini

scripton.txt,重命名成sh后缀然后执行
原始issue

Troubleshooting

我用修复NDK的没成功,用以下脚本成功了

原始网页

import sys
from argparse import ArgumentParser
from dataclasses import dataclass
from pathlib import Path
from typing import BinaryIO, Sequence


class MismatchError(Exception):
    pass


@dataclass
class Patch:
    offset: int
    expected: bytes
    replacement: bytes

    def is_applied(self, io: BinaryIO) -> bool:
        io.seek(self.offset)
        actual = io.read(len(self.expected))

        if actual == self.expected:
            return False
        elif actual == self.replacement:
            return True
        else:
            raise MismatchError

    def apply(self, io: BinaryIO) -> bool:
        if self.is_applied(io):
            return False

        io.seek(self.offset)
        io.write(self.replacement)

        return True

    def reset(self, io: BinaryIO) -> bool:
        if not self.is_applied(io):
            return False

        io.seek(self.offset)
        io.write(self.expected)

        return True


class PatchManager:
    def __init__(self, filename: Path, patches: Sequence[Patch]) -> None:
        self.filename = filename
        self.patches = patches

    def check(self):
        with open(self.filename, "rb") as f:
            for patch in self.patches:
                if patch.is_applied(f):
                    print(f"Offset 0x{patch.offset:x}: patched")
                else:
                    print(f"Offset 0x{patch.offset:x}: not patched")

    def reset(self):
        with open(self.filename, "r+b") as f:
            for patch in self.patches:
                patch.is_applied(f)

            for patch in self.patches:
                if patch.reset(f):
                    print(
                        f"Offset 0x{patch.offset:x}: 0x{patch.replacement.hex()} -> 0x{patch.expected.hex()}"
                    )

    def apply(self):
        with open(self.filename, "r+b") as f:
            for patch in self.patches:
                patch.is_applied(f)

            for patch in self.patches:
                if patch.apply(f):
                    print(
                        f"Offset 0x{patch.offset:x}: 0x{patch.expected.hex()} -> 0x{patch.replacement.hex()}"
                    )


# Patches from https://github.com/waydroid/waydroid/issues/788
HOUDINI_PATCHES = [
    Patch(
        offset=0x3062A5,
        expected=b"\x48\xb8\xfb\xff\xff\xff",
        replacement=b"\x48\xb8\xff\xff\xff\xff",
    ),
    Patch(
        offset=0x3099D6,
        expected=b"\x83\xe0\xfb",
        replacement=b"\x83\xe0\xff",
    ),
    Patch(
        offset=0x309B42,
        expected=b"\xe8\x89\x2f\xee\xff",
        replacement=b"\x90\x90\x90\x90\x90",
    ),
]

NDK_PATCHES = [
    Patch(
        offset=0x206DD1,
        expected=b"\x83\xe2\xfa",
        replacement=b"\x83\xe2\xff",
    ),
    Patch(
        offset=0x206CD6,
        expected=b"\x83\xe2\xfa",
        replacement=b"\x83\xe2\xff",
    ),
]


HOUDINI_PATH = Path("/var/lib/waydroid/overlay/system/lib64/libhoudini.so")
NDK_PATH = Path("/var/lib/waydroid/overlay/system/lib64/libndk_translation.so")


HOUDINI_FILENAME = HOUDINI_PATH.name
NDK_FILENAME = NDK_PATH.name


if __name__ == "__main__":
    parser = ArgumentParser(
        prog="patch-waydroid-bluearchive",
        description="Patch libhoudini or libndk to play Blue Archive",
    )
    parser.add_argument("-t", "--type", choices=["houdini", "ndk"])
    parser.add_argument("-f", "--filename", type=Path)
    parser.add_argument("command", choices=["check", "patch", "reset"])

    args = parser.parse_args()

    if (not args.type) and args.filename:
        if args.filename.name == HOUDINI_FILENAME:
            type = "houdini"
        elif args.filename.name == NDK_FILENAME:
            type = "ndk"
        else:
            parser.error("Could not detect type from filename, please specify --type.")

        print(f"Detected type: {type}")

        filename = args.filename
    elif args.type and (not args.filename):
        type = args.type
        if args.type == "houdini":
            filename = HOUDINI_PATH
        elif args.type == "ndk":
            filename = NDK_PATH
        else:
            parser.error(f"Invalid type: {type}")

        print(f"Detected filename: {filename}")

    elif args.type and args.filename:
        type = args.type
        filename = args.filename
    else:
        parser.error("Please specify one of --filename or --type.")

    if type == "houdini":
        patches = HOUDINI_PATCHES
    elif type == "ndk":
        patches = NDK_PATCHES
    else:
        parser.error(f"Invalid type: {type}")

    manager = PatchManager(filename, patches)

    try:
        if args.command == "check":
            manager.check()
        elif args.command == "patch":
            manager.apply()
        elif args.command == "reset":
            manager.reset()
    except MismatchError:
        print(
            f"{filename} doesn't seem to be a valid {type} shared object, refusing to patch",
            file=sys.stderr,
        )
        sys.exit(1)
    except PermissionError:
        print(f"{filename} is not writable, please run with sudo", file=sys.stderr)
        sys.exit(1)
    except FileNotFoundError:
        print(f"{filename} not found", file=sys.stderr)
        sys.exit(1)
posted @ 2025-01-25 18:55  int16  阅读(151)  评论(0)    收藏  举报