mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-25 10:01:10 +00:00
Refactor: More compact route files
This commit is contained in:
parent
6eb9317ac4
commit
3fa28fba24
89
dev_tools/route_extract.py
Normal file
89
dev_tools/route_extract.py
Normal file
@ -0,0 +1,89 @@
|
||||
import os
|
||||
import re
|
||||
from dataclasses import dataclass, fields
|
||||
|
||||
from module.base.code_generator import CodeGenerator
|
||||
|
||||
|
||||
@dataclass
|
||||
class RouteData:
|
||||
name: str
|
||||
route: str
|
||||
plane: str
|
||||
floor: str = 'F1'
|
||||
position: tuple = None
|
||||
|
||||
|
||||
class RouteExtract:
|
||||
def __init__(self, folder):
|
||||
self.folder = folder
|
||||
|
||||
def iter_files(self):
|
||||
for path, folders, files in os.walk(self.folder):
|
||||
path = path.replace('\\', '/')
|
||||
for file in files:
|
||||
if file.endswith('.py'):
|
||||
yield f'{path}/{file}'
|
||||
|
||||
def extract_route(self, file):
|
||||
print(f'Extract {file}')
|
||||
with open(file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
"""
|
||||
def route_item_enemy(self):
|
||||
self.enter_himeko_trial()
|
||||
self.map_init(plane=Jarilo_BackwaterPass, position=(519.9, 361.5))
|
||||
"""
|
||||
regex = re.compile(
|
||||
r'def (?P<func>[a-zA-Z0-9_]*?)\(self\):.*?'
|
||||
r'self\.map_init\((.*?)\)'
|
||||
, re.DOTALL)
|
||||
file = file.replace(self.folder, '').replace('.py', '').replace('/', '_').strip('_')
|
||||
module = f"{self.folder.strip('./').replace('/', '.')}.{file.replace('_', '.')}"
|
||||
|
||||
for result in regex.findall(content):
|
||||
func, data = result
|
||||
|
||||
res = re.search(r'plane=([a-zA-Z_]*)', data)
|
||||
if res:
|
||||
plane = res.group(1)
|
||||
else:
|
||||
# Must contain plane
|
||||
continue
|
||||
res = re.search(r'floor=([\'"a-zA-Z0-9_]*)', data)
|
||||
if res:
|
||||
floor = res.group(1).strip('"\'')
|
||||
else:
|
||||
floor = 'F1'
|
||||
res = re.search(r'position=\(([0-9.]*)[, ]+([0-9.]*)', data)
|
||||
if res:
|
||||
position = (float(res.group(1)), float(res.group(2)))
|
||||
else:
|
||||
position = None
|
||||
|
||||
yield RouteData(
|
||||
name=f'{file}__{func}',
|
||||
route=f'{module}:{func}',
|
||||
plane=plane,
|
||||
floor=floor,
|
||||
position=position,
|
||||
)
|
||||
|
||||
def write(self, file):
|
||||
gen = CodeGenerator()
|
||||
gen.Import("""
|
||||
from tasks.map.route.base import RouteData
|
||||
""")
|
||||
for f in self.iter_files():
|
||||
for row in self.extract_route(f):
|
||||
with gen.Object(key=row.name, object_class='RouteData'):
|
||||
for key in fields(row):
|
||||
value = getattr(row, key.name)
|
||||
gen.ObjectAttr(key.name, value)
|
||||
gen.write(file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.chdir(os.path.join(os.path.dirname(__file__), '../'))
|
||||
RouteExtract('./route/daily').write('./tasks/map/route/route/daily.py')
|
@ -23,6 +23,7 @@ from tasks.dungeon.ui import DungeonUI
|
||||
from tasks.item.consumable_usage import ConsumableUsageUI
|
||||
from tasks.item.relics import RelicsUI
|
||||
from tasks.map.route.loader import RouteLoader
|
||||
from tasks.map.route.route import ROUTE_DAILY
|
||||
|
||||
|
||||
class DailyQuestOcr(Ocr):
|
||||
@ -260,7 +261,7 @@ class DailyQuestUI(DungeonUI, RouteLoader):
|
||||
if RelicsUI(self.config, self.device).salvage_relic():
|
||||
done += 1
|
||||
if KEYWORDS_DAILY_QUEST.Complete_Forgotten_Hall_1_time in quests:
|
||||
self.route_run('daily.forgotten_hall.stage_1')
|
||||
self.route_run(ROUTE_DAILY.ForgottenHallStage1__route)
|
||||
done += 1
|
||||
|
||||
return done
|
||||
|
@ -1,8 +1,19 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from tasks.map.control.control import MapControl
|
||||
from tasks.map.control.waypoint import Waypoint
|
||||
from tasks.map.keywords import MapPlane
|
||||
|
||||
|
||||
@dataclass
|
||||
class RouteData:
|
||||
name: str
|
||||
route: str
|
||||
plane: str
|
||||
floor: str = 'F1'
|
||||
position: tuple = None
|
||||
|
||||
|
||||
class RouteBase(MapControl):
|
||||
"""
|
||||
Base class of `Route`
|
||||
|
@ -1,38 +1,71 @@
|
||||
import importlib
|
||||
import os
|
||||
|
||||
from module.exception import RequestHumanTakeover
|
||||
from module.base.decorator import del_cached_property
|
||||
from module.exception import ScriptError
|
||||
from module.logger import logger
|
||||
from tasks.base.ui import UI
|
||||
from tasks.map.route.base import RouteBase
|
||||
from tasks.map.route.base import RouteBase, RouteData
|
||||
|
||||
|
||||
class RouteLoader(UI):
|
||||
route: RouteBase
|
||||
route_module: str = ''
|
||||
route_func: str = ''
|
||||
route_obj: RouteBase
|
||||
|
||||
def route_run(self, route: str):
|
||||
def route_delete(self):
|
||||
del_cached_property(self, 'route_obj')
|
||||
self.route_module = ''
|
||||
self.route_func = ''
|
||||
|
||||
def route_run(self, route: RouteData | str):
|
||||
"""
|
||||
Args:
|
||||
route: .py module path such as `daily.forgotten_hall.stage1`
|
||||
which will load `./route/daily/forgotten_hall/stage1.py`
|
||||
route: .py module path such as `route.daily.ForgottenHallStage1:route`
|
||||
which will load `./route/daily/ForgottenHallStage1.py` and run `Route.route()`
|
||||
"""
|
||||
folder, name = route.rsplit('.', maxsplit=1)
|
||||
path = f'./route/{route.replace(".", "/")}.py'
|
||||
logger.hr('Route run', level=1)
|
||||
if isinstance(route, RouteData):
|
||||
route = route.route
|
||||
logger.attr('Route', route)
|
||||
try:
|
||||
module = importlib.import_module(f'route.{folder}.{name}')
|
||||
module, func = route.split(':')
|
||||
except ValueError:
|
||||
logger.critical(f'Route invalid: {route}')
|
||||
raise ScriptError
|
||||
path = f'./{module.replace(".", "/")}.py'
|
||||
|
||||
# Import route file
|
||||
try:
|
||||
module_obj = importlib.import_module(f'{module}')
|
||||
except ModuleNotFoundError:
|
||||
logger.critical(f'Route file not found: {route} ({path})')
|
||||
logger.critical(f'Route file not found: {module} ({path})')
|
||||
if not os.path.exists(path):
|
||||
logger.critical(f'Route file not exists: {path}')
|
||||
raise RequestHumanTakeover
|
||||
raise ScriptError
|
||||
|
||||
# Create route object
|
||||
# Reuse the previous one
|
||||
if self.route_module != module:
|
||||
# config = copy.deepcopy(self.config).merge(module.Config())
|
||||
config = self.config
|
||||
device = self.device
|
||||
try:
|
||||
self.route = module.Route(config=config, device=device)
|
||||
return self.route.route()
|
||||
self.route_obj = module_obj.Route(config=config, device=device)
|
||||
except AttributeError as e:
|
||||
logger.critical(e)
|
||||
logger.critical(f'Route file {route} ({path}) must define Route.route()')
|
||||
raise RequestHumanTakeover
|
||||
logger.critical(f'Route file {route} ({path}) must define class Route')
|
||||
raise ScriptError
|
||||
self.route_module = module
|
||||
|
||||
# Get route func
|
||||
try:
|
||||
func_obj = self.route_obj.__getattribute__(func)
|
||||
except AttributeError as e:
|
||||
logger.critical(e)
|
||||
logger.critical(f'Route class in {route} ({path}) does not have method {func}')
|
||||
raise ScriptError
|
||||
self.route_func = func
|
||||
|
||||
# Run
|
||||
func_obj()
|
||||
|
1
tasks/map/route/route/__init__.py
Normal file
1
tasks/map/route/route/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
import tasks.map.route.route.daily as ROUTE_DAILY
|
38
tasks/map/route/route/daily.py
Normal file
38
tasks/map/route/route/daily.py
Normal file
@ -0,0 +1,38 @@
|
||||
from tasks.map.route.base import RouteData
|
||||
|
||||
|
||||
ForgottenHallStage1__route = RouteData(
|
||||
name='ForgottenHallStage1__route',
|
||||
route='route.daily.ForgottenHallStage1:route',
|
||||
plane='Jarilo_BackwaterPass',
|
||||
floor='F1',
|
||||
position=(369.4, 643.4),
|
||||
)
|
||||
HimekoTrial__route_item_enemy = RouteData(
|
||||
name='HimekoTrial__route_item_enemy',
|
||||
route='route.daily.HimekoTrial:route_item_enemy',
|
||||
plane='Jarilo_BackwaterPass',
|
||||
floor='F1',
|
||||
position=(519.9, 361.5),
|
||||
)
|
||||
HimekoTrial__route_item = RouteData(
|
||||
name='HimekoTrial__route_item',
|
||||
route='route.daily.HimekoTrial:route_item',
|
||||
plane='Jarilo_BackwaterPass',
|
||||
floor='F1',
|
||||
position=(519.9, 361.5),
|
||||
)
|
||||
HimekoTrial__route_enemy = RouteData(
|
||||
name='HimekoTrial__route_enemy',
|
||||
route='route.daily.HimekoTrial:route_enemy',
|
||||
plane='Jarilo_BackwaterPass',
|
||||
floor='F1',
|
||||
position=(519.9, 361.5),
|
||||
)
|
||||
HimekoTrial__exit = RouteData(
|
||||
name='HimekoTrial__exit',
|
||||
route='route.daily.HimekoTrial:exit',
|
||||
plane='Jarilo_BackwaterPass',
|
||||
floor='F1',
|
||||
position=(519.9, 361.5),
|
||||
)
|
Loading…
Reference in New Issue
Block a user