mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-05-04 14:23:29 -07:00
Android: initial working version
This commit is contained in:
@@ -650,7 +650,7 @@ if __name__ == '__main__':
|
||||
import atexit
|
||||
confirmation = atexit.register(input, "Press enter to close.")
|
||||
erargs, seed = main()
|
||||
from Main import main as ERmain
|
||||
from generate_lib import main as ERmain
|
||||
multiworld = ERmain(erargs, seed)
|
||||
if __debug__:
|
||||
import gc
|
||||
|
||||
24
Launcher.py
24
Launcher.py
@@ -30,7 +30,7 @@ if __name__ == "__main__":
|
||||
import settings
|
||||
import Utils
|
||||
from Utils import (init_logging, is_frozen, is_linux, is_macos, is_windows, local_path, messagebox, open_filename,
|
||||
user_path)
|
||||
user_path, is_mobile)
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_logging('Launcher')
|
||||
@@ -495,8 +495,7 @@ def main(args: argparse.Namespace | dict | None = None):
|
||||
elif not args["update_settings"]:
|
||||
run_gui(args.get("launch_components", None), args.get("args", ()))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def run():
|
||||
multiprocessing.freeze_support()
|
||||
multiprocessing.set_start_method("spawn") # if launched process uses kivy, fork won't work
|
||||
parser = argparse.ArgumentParser(
|
||||
@@ -519,3 +518,22 @@ if __name__ == '__main__':
|
||||
# we await all child processes to close before we tear down the process host
|
||||
# this makes it feel like each one is its own program, as the Launcher is closed now
|
||||
process.join()
|
||||
|
||||
|
||||
if is_mobile:
|
||||
allowed_names = {
|
||||
"Launcher",
|
||||
"Text Client",
|
||||
"APQuest Client",
|
||||
"Archipelago Website",
|
||||
"Discord Server",
|
||||
"Unrated/18+ Discord Server",
|
||||
}
|
||||
components[:] = [c for c in components if c.display_name in allowed_names]
|
||||
|
||||
|
||||
logging.info(f"Loaded {len(components)} components.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
|
||||
@@ -20,7 +20,8 @@ elif not (3, 11, 0) <= sys.version_info < (3, 14, 0):
|
||||
_skip_update = bool(
|
||||
getattr(sys, "frozen", False) or
|
||||
multiprocessing.parent_process() or
|
||||
os.environ.get("SKIP_REQUIREMENTS_UPDATE", "").lower() in ("1", "true", "yes")
|
||||
os.environ.get("SKIP_REQUIREMENTS_UPDATE", "").lower() in ("1", "true", "yes") or
|
||||
sys.platform in ("ios", "android")
|
||||
)
|
||||
update_ran = _skip_update
|
||||
|
||||
|
||||
@@ -1168,8 +1168,8 @@ class ConnectionsMeta(AssembleOptions):
|
||||
attrs["entrances"] = frozenset((connection.lower() for connection in attrs["entrances"]))
|
||||
assert "exits" in attrs, f"Please define valid exits for {name}"
|
||||
attrs["exits"] = frozenset((connection.lower() for connection in attrs["exits"]))
|
||||
if "__doc__" not in attrs:
|
||||
attrs["__doc__"] = PlandoConnections.__doc__
|
||||
if "__doc__" not in attrs:
|
||||
attrs["__doc__"] = PlandoConnections.__doc__
|
||||
cls = super().__new__(mcs, name, bases, attrs)
|
||||
return cls
|
||||
|
||||
|
||||
20
Utils.py
20
Utils.py
@@ -58,6 +58,9 @@ version_tuple = tuplize_version(__version__)
|
||||
is_linux = sys.platform.startswith("linux")
|
||||
is_macos = sys.platform == "darwin"
|
||||
is_windows = sys.platform in ("win32", "cygwin", "msys")
|
||||
is_android = sys.platform == "android"
|
||||
is_ios = sys.platform == "ios"
|
||||
is_mobile = is_android or is_ios
|
||||
|
||||
|
||||
def int16_as_bytes(value: int) -> typing.List[int]:
|
||||
@@ -684,13 +687,18 @@ def format_SI_prefix(value, power=1000, power_labels=("", "k", "M", "G", "T", "P
|
||||
|
||||
def get_fuzzy_results(input_word: str, word_list: typing.Collection[str], limit: typing.Optional[int] = None) \
|
||||
-> typing.List[typing.Tuple[str, int]]:
|
||||
import jellyfish
|
||||
if is_mobile:
|
||||
def get_fuzzy_ratio(word1: str, word2: str) -> float:
|
||||
length = min(len(word1), len(word2))
|
||||
return sum(word1[i] == word2[i] for i in range(length)) / min(1, length)
|
||||
|
||||
def get_fuzzy_ratio(word1: str, word2: str) -> float:
|
||||
if word1 == word2:
|
||||
return 1.01
|
||||
return (1 - jellyfish.damerau_levenshtein_distance(word1.lower(), word2.lower())
|
||||
/ max(len(word1), len(word2)))
|
||||
else:
|
||||
import jellyfish
|
||||
def get_fuzzy_ratio(word1: str, word2: str) -> float:
|
||||
if word1 == word2:
|
||||
return 1.01
|
||||
return (1 - jellyfish.damerau_levenshtein_distance(word1.lower(), word2.lower())
|
||||
/ max(len(word1), len(word2)))
|
||||
|
||||
limit = limit if limit else len(word_list)
|
||||
return list(
|
||||
|
||||
@@ -13,7 +13,7 @@ from pony.orm import commit, db_session
|
||||
|
||||
from BaseClasses import get_seed, seeddigits
|
||||
from Generate import PlandoOptions, handle_name, mystery_argparse
|
||||
from Main import main as ERmain
|
||||
from generate_lib import main as ERmain
|
||||
from Utils import __version__, restricted_dumps, DaemonThreadPoolExecutor
|
||||
from WebHostLib import app
|
||||
from settings import ServerOptions, GeneratorOptions
|
||||
|
||||
32
buildozer.spec
Normal file
32
buildozer.spec
Normal file
@@ -0,0 +1,32 @@
|
||||
[app]
|
||||
title = Archipelago
|
||||
package.name = archipelago
|
||||
package.domain = gg.archipelago
|
||||
source.dir = .
|
||||
source.include_exts = py,png,jpg,kv,atlas,json,yml,txt,lua
|
||||
source.include_patterns = data/*, *.kv, *.py
|
||||
source.exclude_dirs = factorio,test,docs,.github,.git, deploy, bin, build, __pycache__
|
||||
source.exclude_patterns = test,*.pyc,*.pyo,__pycache__,*.egg-info,*.dist-info,docs,examples,build,dist,.git,.github
|
||||
version = 0.6.7
|
||||
|
||||
# Requirements/Python
|
||||
p4a.branch = develop
|
||||
p4a.setup_py = false
|
||||
python_flags = -O
|
||||
requirements = python3==3.11.14, hostpython3==3.11.14,pip==24.3.1, kivy==2.3.1,kivymd@git+https://github.com/kivymd/KivyMD@365aa9b,materialyoucolor>=3.0.2,asynckivy>=0.10.0.dev1,asyncgui>=0.10.0.dev0,colorama==0.4.6,websockets==13.0.1,PyYAML>=6.0.3,jinja2>=3.1.6,schema>=0.7.8,bsdiff4>=1.2.6,platformdirs>=4.5.0,certifi>=2025.11.12,cython>=3.2.1,cymem>=2.0.13,orjson>=3.11.4,typing_extensions>=4.15.0,pyshortcuts>=1.9.6,pathspec>=0.12.1
|
||||
|
||||
|
||||
# Android settings
|
||||
orientation = portrait, landscape, portrait-reverse, landscape-reverse
|
||||
fullscreen = 0
|
||||
android.gradle_properties = org.gradle.jvmargs=-Xmx8192m -XX:MaxMetaspaceSize=512m
|
||||
android.permissions = INTERNET,ACCESS_NETWORK_STATE,WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE
|
||||
android.api = 34
|
||||
android.minapi = 24
|
||||
android.ndk = 25b
|
||||
android.archs = arm64-v8a
|
||||
android.copy_libs = 1
|
||||
|
||||
# Icons/presplash
|
||||
icon.filename = data/icon.png
|
||||
presplash.filename = data/icon.png
|
||||
4
kvui.py
4
kvui.py
@@ -57,7 +57,7 @@ for classobj in SoundLoader._classes:
|
||||
# .extensions(), which e.g. in audio_sdl2.pyx then calls a function called "mix_init()"
|
||||
classobj.extensions()
|
||||
|
||||
from kivymd.uix.divider import MDDivider
|
||||
|
||||
from kivy.core.window import Window
|
||||
from kivy.core.clipboard import Clipboard
|
||||
from kivy.core.text.markup import MarkupLabel
|
||||
@@ -86,7 +86,7 @@ from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.navigationbar import MDNavigationBar, MDNavigationItem
|
||||
from kivymd.uix.screen import MDScreen
|
||||
from kivymd.uix.screenmanager import MDScreenManager
|
||||
|
||||
from kivymd.uix.divider import MDDivider
|
||||
from kivymd.uix.menu import MDDropdownMenu
|
||||
from kivymd.uix.menu.menu import MDDropdownTextItem
|
||||
from kivymd.uix.dropdownitem import MDDropDownItem, MDDropDownItemText
|
||||
|
||||
4
main.py
Normal file
4
main.py
Normal file
@@ -0,0 +1,4 @@
|
||||
import Launcher
|
||||
|
||||
if __name__ == "__main__":
|
||||
Launcher.run()
|
||||
@@ -14,7 +14,7 @@ orjson>=3.11.4
|
||||
typing_extensions>=4.15.0
|
||||
pyshortcuts>=1.9.6
|
||||
pathspec>=0.12.1
|
||||
kivymd @ git+https://github.com/kivymd/KivyMD@5ff9d0d
|
||||
kivymd @ git+https://github.com/kivymd/KivyMD@365aa9b
|
||||
kivymd>=2.0.1.dev0
|
||||
|
||||
# Legacy world dependencies that custom worlds rely on
|
||||
|
||||
@@ -26,7 +26,7 @@ def _generate_local_inner(games: Iterable[str],
|
||||
with TemporaryDirectory() as players_dir:
|
||||
with TemporaryDirectory() as output_dir:
|
||||
import Generate
|
||||
import Main
|
||||
import generate_lib
|
||||
|
||||
for n, game in enumerate(games, 1):
|
||||
player_path = Path(players_dir) / f"{n}.yaml"
|
||||
|
||||
@@ -9,7 +9,7 @@ from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
import Generate
|
||||
import Main
|
||||
import generate_lib
|
||||
|
||||
|
||||
class TestGenerateMain(unittest.TestCase):
|
||||
@@ -59,7 +59,7 @@ class TestGenerateMain(unittest.TestCase):
|
||||
'--player_files_path', str(self.abs_input_dir),
|
||||
'--outputpath', self.output_tempdir.name]
|
||||
print(f'Testing Generate.py {sys.argv} in {os.getcwd()}')
|
||||
Main.main(*Generate.main())
|
||||
generate_lib.main(*Generate.main())
|
||||
|
||||
self.assertOutput(self.output_tempdir.name)
|
||||
|
||||
@@ -68,7 +68,7 @@ class TestGenerateMain(unittest.TestCase):
|
||||
'--player_files_path', str(self.rel_input_dir),
|
||||
'--outputpath', self.output_tempdir.name]
|
||||
print(f'Testing Generate.py {sys.argv} in {os.getcwd()}')
|
||||
Main.main(*Generate.main())
|
||||
generate_lib.main(*Generate.main())
|
||||
|
||||
self.assertOutput(self.output_tempdir.name)
|
||||
|
||||
@@ -87,7 +87,7 @@ class TestGenerateMain(unittest.TestCase):
|
||||
sys.argv = [sys.argv[0], '--seed', '0',
|
||||
'--outputpath', self.output_tempdir.name]
|
||||
print(f'Testing Generate.py {sys.argv} in {os.getcwd()}, player_files_path={self.yaml_input_dir}')
|
||||
Main.main(*Generate.main())
|
||||
generate_lib.main(*Generate.main())
|
||||
finally:
|
||||
user_path.cached_path = user_path_backup
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import weakref
|
||||
from enum import Enum, auto
|
||||
from typing import Optional, Callable, List, Iterable, Tuple
|
||||
|
||||
from Utils import local_path, open_filename, is_frozen, is_kivy_running, open_file, user_path, read_apignore
|
||||
from Utils import local_path, open_filename, is_frozen, is_kivy_running, open_file, user_path, read_apignore, is_mobile
|
||||
|
||||
|
||||
class Type(Enum):
|
||||
|
||||
@@ -1191,7 +1191,7 @@ def patch_rom(world: "YoshisIslandWorld", rom: LocalRom, player: int) -> None:
|
||||
rom.write_bytes(0x1153F6, bytearray([0x16, 0x28, 0x10, 0x0C, 0x10, 0x4E, 0x1E, 0x10, 0x08, 0x04, 0x08, 0x24, 0x36, 0x82, 0x83, 0x83, 0x34, 0x84, 0x85, 0x85])) # Luigi piece clear text
|
||||
rom.write_bytes(0x06FC86, bytearray([0xFF])) # Boss clear goal = 255, renders bowser inaccessible
|
||||
|
||||
from Main import __version__
|
||||
from generate_lib import __version__
|
||||
rom.name = bytearray(f'YOSHIAP{__version__.replace(".", "")[0:3]}_{player}_{world.multiworld.seed:11}\0', "utf8")[:21]
|
||||
rom.name.extend([0] * (21 - len(rom.name)))
|
||||
rom.write_bytes(0x007FC0, rom.name)
|
||||
|
||||
Reference in New Issue
Block a user