Merge branch 'master' into phone_cloud

This commit is contained in:
LmeSzinc 2022-07-13 23:25:46 +08:00
commit 95f5404c66
34 changed files with 293 additions and 74 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -22,5 +22,4 @@ prettytable==2.2.1
pypresence==4.2.1
rich==11.0.0
zerorpc==0.6.3
pyzmq==22.3.0
atomicwrites
pyzmq==22.3.0

View File

@ -23,5 +23,4 @@ prettytable==2.2.1
pypresence==4.2.1
rich==11.0.0
zerorpc==0.6.3
pyzmq==22.3.0
atomicwrites
pyzmq==22.3.0

View File

@ -672,8 +672,12 @@ def image_left_strip(image, threshold, length):
"""
brightness = np.mean(image, axis=0)
match = np.where(brightness < threshold)[0]
if len(match):
image = image[:, match[0] + length:]
left = match[0] + length
total = image.shape[1]
if left < total:
image = image[:, left:]
return image

View File

@ -0,0 +1,236 @@
"""
Copy-pasted from
https://github.com/untitaker/python-atomicwrites
"""
import contextlib
import io
import os
import sys
import tempfile
try:
import fcntl
except ImportError:
fcntl = None
# `fspath` was added in Python 3.6
try:
from os import fspath
except ImportError:
fspath = None
__version__ = '1.4.1'
PY2 = sys.version_info[0] == 2
text_type = unicode if PY2 else str # noqa
def _path_to_unicode(x):
if not isinstance(x, text_type):
return x.decode(sys.getfilesystemencoding())
return x
DEFAULT_MODE = "wb" if PY2 else "w"
_proper_fsync = os.fsync
if sys.platform != 'win32':
if hasattr(fcntl, 'F_FULLFSYNC'):
def _proper_fsync(fd):
# https://lists.apple.com/archives/darwin-dev/2005/Feb/msg00072.html
# https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fsync.2.html
# https://github.com/untitaker/python-atomicwrites/issues/6
fcntl.fcntl(fd, fcntl.F_FULLFSYNC)
def _sync_directory(directory):
# Ensure that filenames are written to disk
fd = os.open(directory, 0)
try:
_proper_fsync(fd)
finally:
os.close(fd)
def _replace_atomic(src, dst):
os.rename(src, dst)
_sync_directory(os.path.normpath(os.path.dirname(dst)))
def _move_atomic(src, dst):
os.link(src, dst)
os.unlink(src)
src_dir = os.path.normpath(os.path.dirname(src))
dst_dir = os.path.normpath(os.path.dirname(dst))
_sync_directory(dst_dir)
if src_dir != dst_dir:
_sync_directory(src_dir)
else:
from ctypes import windll, WinError
_MOVEFILE_REPLACE_EXISTING = 0x1
_MOVEFILE_WRITE_THROUGH = 0x8
_windows_default_flags = _MOVEFILE_WRITE_THROUGH
def _handle_errors(rv):
if not rv:
raise WinError()
def _replace_atomic(src, dst):
_handle_errors(windll.kernel32.MoveFileExW(
_path_to_unicode(src), _path_to_unicode(dst),
_windows_default_flags | _MOVEFILE_REPLACE_EXISTING
))
def _move_atomic(src, dst):
_handle_errors(windll.kernel32.MoveFileExW(
_path_to_unicode(src), _path_to_unicode(dst),
_windows_default_flags
))
def replace_atomic(src, dst):
'''
Move ``src`` to ``dst``. If ``dst`` exists, it will be silently
overwritten.
Both paths must reside on the same filesystem for the operation to be
atomic.
'''
return _replace_atomic(src, dst)
def move_atomic(src, dst):
'''
Move ``src`` to ``dst``. There might a timewindow where both filesystem
entries exist. If ``dst`` already exists, :py:exc:`FileExistsError` will be
raised.
Both paths must reside on the same filesystem for the operation to be
atomic.
'''
return _move_atomic(src, dst)
class AtomicWriter(object):
'''
A helper class for performing atomic writes. Usage::
with AtomicWriter(path).open() as f:
f.write(...)
:param path: The destination filepath. May or may not exist.
:param mode: The filemode for the temporary file. This defaults to `wb` in
Python 2 and `w` in Python 3.
:param overwrite: If set to false, an error is raised if ``path`` exists.
Errors are only raised after the file has been written to. Either way,
the operation is atomic.
:param open_kwargs: Keyword-arguments to pass to the underlying
:py:func:`open` call. This can be used to set the encoding when opening
files in text-mode.
If you need further control over the exact behavior, you are encouraged to
subclass.
'''
def __init__(self, path, mode=DEFAULT_MODE, overwrite=False,
**open_kwargs):
if 'a' in mode:
raise ValueError(
'Appending to an existing file is not supported, because that '
'would involve an expensive `copy`-operation to a temporary '
'file. Open the file in normal `w`-mode and copy explicitly '
'if that\'s what you\'re after.'
)
if 'x' in mode:
raise ValueError('Use the `overwrite`-parameter instead.')
if 'w' not in mode:
raise ValueError('AtomicWriters can only be written to.')
# Attempt to convert `path` to `str` or `bytes`
if fspath is not None:
path = fspath(path)
self._path = path
self._mode = mode
self._overwrite = overwrite
self._open_kwargs = open_kwargs
def open(self):
'''
Open the temporary file.
'''
return self._open(self.get_fileobject)
@contextlib.contextmanager
def _open(self, get_fileobject):
f = None # make sure f exists even if get_fileobject() fails
try:
success = False
with get_fileobject(**self._open_kwargs) as f:
yield f
self.sync(f)
self.commit(f)
success = True
finally:
if not success:
try:
self.rollback(f)
except Exception:
pass
def get_fileobject(self, suffix="", prefix=tempfile.gettempprefix(),
dir=None, **kwargs):
'''Return the temporary file to use.'''
if dir is None:
dir = os.path.normpath(os.path.dirname(self._path))
descriptor, name = tempfile.mkstemp(suffix=suffix, prefix=prefix,
dir=dir)
# io.open() will take either the descriptor or the name, but we need
# the name later for commit()/replace_atomic() and couldn't find a way
# to get the filename from the descriptor.
os.close(descriptor)
kwargs['mode'] = self._mode
kwargs['file'] = name
return io.open(**kwargs)
def sync(self, f):
'''responsible for clearing as many file caches as possible before
commit'''
f.flush()
_proper_fsync(f.fileno())
def commit(self, f):
'''Move the temporary file to the target location.'''
if self._overwrite:
replace_atomic(f.name, self._path)
else:
move_atomic(f.name, self._path)
def rollback(self, f):
'''Clean up all temporary resources.'''
os.unlink(f.name)
def atomic_write(path, writer_cls=AtomicWriter, **cls_kwargs):
'''
Simple atomic writes. This wraps :py:class:`AtomicWriter`::
with atomic_write(path) as f:
f.write(...)
:param path: The target path to write to.
:param writer_cls: The writer class to use. This parameter is useful if you
subclassed :py:class:`AtomicWriter` to change some behavior and want to
use that new subclass.
Additional keyword arguments are passed to the writer class. See
:py:class:`AtomicWriter`.
'''
return writer_cls(path, **cls_kwargs).open()

View File

@ -5,10 +5,10 @@ import string
from datetime import datetime, timedelta, timezone
import yaml
from atomicwrites import atomic_write
from filelock import FileLock
import module.config.server as server_
from module.config.atomicwrites import atomic_write
LANGUAGES = ['zh-CN', 'en-US', 'ja-JP', 'zh-TW']
SERVER_TO_LANG = {

View File

@ -5,7 +5,7 @@ from module.base.template import Template
# Don't modify it manually.
BATTLE_STATUS_CF = Button(area={'cn': (315, 217, 329, 303), 'en': (367, 238, 373, 274), 'jp': (340, 217, 350, 291), 'tw': (263, 216, 276, 305)}, color={'cn': (255, 242, 133), 'en': (252, 232, 164), 'jp': (255, 247, 143), 'tw': (240, 214, 143)}, button={'cn': (1000, 631, 1055, 689), 'en': (1000, 631, 1055, 689), 'jp': (1000, 631, 1055, 689), 'tw': (1000, 631, 1055, 689)}, file={'cn': './assets/cn/guild/BATTLE_STATUS_CF.png', 'en': './assets/en/guild/BATTLE_STATUS_CF.png', 'jp': './assets/jp/guild/BATTLE_STATUS_CF.png', 'tw': './assets/tw/guild/BATTLE_STATUS_CF.png'})
EXP_INFO_CF = Button(area={'cn': (179, 67, 189, 126), 'en': (215, 82, 219, 106), 'jp': (196, 67, 204, 119), 'tw': (144, 66, 153, 127)}, color={'cn': (255, 242, 133), 'en': (252, 231, 160), 'jp': (255, 246, 140), 'tw': (241, 219, 150)}, button={'cn': (1000, 631, 1055, 689), 'en': (1000, 631, 1055, 689), 'jp': (1000, 631, 1055, 689), 'tw': (1000, 631, 1055, 689)}, file={'cn': './assets/cn/guild/EXP_INFO_CF.png', 'en': './assets/en/guild/EXP_INFO_CF.png', 'jp': './assets/jp/guild/EXP_INFO_CF.png', 'tw': './assets/tw/guild/EXP_INFO_CF.png'})
EXP_INFO_CF = Button(area={'cn': (179, 67, 189, 126), 'en': (215, 82, 219, 106), 'jp': (196, 67, 204, 119), 'tw': (321, 93, 328, 114)}, color={'cn': (255, 242, 133), 'en': (252, 231, 160), 'jp': (255, 246, 140), 'tw': (255, 255, 159)}, button={'cn': (1000, 631, 1055, 689), 'en': (1000, 631, 1055, 689), 'jp': (1000, 631, 1055, 689), 'tw': (1000, 631, 1055, 689)}, file={'cn': './assets/cn/guild/EXP_INFO_CF.png', 'en': './assets/en/guild/EXP_INFO_CF.png', 'jp': './assets/jp/guild/EXP_INFO_CF.png', 'tw': './assets/tw/guild/EXP_INFO_CF.png'})
GUILD_BOSS_AVAILABLE = Button(area={'cn': (1229, 614, 1242, 632), 'en': (1229, 614, 1242, 632), 'jp': (1229, 614, 1242, 632), 'tw': (1229, 614, 1242, 632)}, color={'cn': (58, 100, 61), 'en': (58, 100, 61), 'jp': (40, 70, 53), 'tw': (58, 100, 61)}, button={'cn': (1229, 614, 1242, 632), 'en': (1229, 614, 1242, 632), 'jp': (1229, 614, 1242, 632), 'tw': (1229, 614, 1242, 632)}, file={'cn': './assets/cn/guild/GUILD_BOSS_AVAILABLE.png', 'en': './assets/en/guild/GUILD_BOSS_AVAILABLE.png', 'jp': './assets/jp/guild/GUILD_BOSS_AVAILABLE.png', 'tw': './assets/tw/guild/GUILD_BOSS_AVAILABLE.png'})
GUILD_BOSS_ENTER = Button(area={'cn': (1132, 642, 1261, 687), 'en': (1115, 646, 1257, 683), 'jp': (1140, 643, 1261, 687), 'tw': (1144, 642, 1261, 687)}, color={'cn': (71, 156, 246), 'en': (77, 158, 249), 'jp': (80, 161, 242), 'tw': (75, 162, 246)}, button={'cn': (1132, 642, 1261, 687), 'en': (1115, 646, 1257, 683), 'jp': (1140, 643, 1261, 687), 'tw': (1144, 642, 1261, 687)}, file={'cn': './assets/cn/guild/GUILD_BOSS_ENTER.png', 'en': './assets/en/guild/GUILD_BOSS_ENTER.png', 'jp': './assets/jp/guild/GUILD_BOSS_ENTER.png', 'tw': './assets/tw/guild/GUILD_BOSS_ENTER.png'})
GUILD_DISPATCH_CLOSE = Button(area={'cn': (1236, 102, 1266, 133), 'en': (1236, 102, 1266, 133), 'jp': (1236, 102, 1266, 133), 'tw': (1236, 102, 1266, 133)}, color={'cn': (88, 39, 38), 'en': (88, 39, 38), 'jp': (88, 39, 38), 'tw': (88, 39, 38)}, button={'cn': (1236, 102, 1266, 133), 'en': (1236, 102, 1266, 133), 'jp': (1236, 102, 1266, 133), 'tw': (1236, 102, 1266, 133)}, file={'cn': './assets/cn/guild/GUILD_DISPATCH_CLOSE.png', 'en': './assets/en/guild/GUILD_DISPATCH_CLOSE.png', 'jp': './assets/jp/guild/GUILD_DISPATCH_CLOSE.png', 'tw': './assets/tw/guild/GUILD_DISPATCH_CLOSE.png'})

View File

@ -40,6 +40,18 @@ class LoginHandler(Combat):
self.device.get_orientation()
orientation_timer.reset()
if self.appear_then_click(LOGIN_CHECK, interval=5):
if not login_success:
logger.info('Login success')
login_success = True
if self.appear(MAIN_CHECK):
if confirm_timer.reached():
logger.info('Login to main confirm')
break
else:
confirm_timer.reset()
if self.handle_get_items():
continue
if self.handle_get_ship():
@ -69,18 +81,6 @@ class LoginHandler(Combat):
if self.appear_then_click(GOTO_MAIN, offset=(30, 30), interval=5):
continue
if self.appear_then_click(LOGIN_CHECK, interval=5):
if not login_success:
logger.info('Login success')
login_success = True
if self.appear(MAIN_CHECK):
if confirm_timer.reached():
logger.info('Login to main confirm')
break
else:
confirm_timer.reset()
self.config.start_time = datetime.now()
return True

View File

@ -34,7 +34,7 @@ MEOWFFICER_TRAIN_ENTER = Button(area={'cn': (1142, 581, 1258, 651), 'en': (1178,
MEOWFFICER_TRAIN_FILL_QUEUE = Button(area={'cn': (780, 548, 859, 567), 'en': (772, 544, 866, 568), 'jp': (779, 547, 859, 569), 'tw': (778, 545, 863, 571)}, color={'cn': (205, 179, 89), 'en': (222, 198, 100), 'jp': (204, 176, 82), 'tw': (213, 187, 95)}, button={'cn': (780, 548, 859, 567), 'en': (772, 544, 866, 568), 'jp': (779, 547, 859, 569), 'tw': (778, 545, 863, 571)}, file={'cn': './assets/cn/meowfficer/MEOWFFICER_TRAIN_FILL_QUEUE.png', 'en': './assets/en/meowfficer/MEOWFFICER_TRAIN_FILL_QUEUE.png', 'jp': './assets/jp/meowfficer/MEOWFFICER_TRAIN_FILL_QUEUE.png', 'tw': './assets/tw/meowfficer/MEOWFFICER_TRAIN_FILL_QUEUE.png'})
MEOWFFICER_TRAIN_FINISH_ALL = Button(area={'cn': (784, 551, 870, 576), 'en': (787, 552, 866, 574), 'jp': (777, 547, 860, 569), 'tw': (780, 550, 870, 576)}, color={'cn': (216, 191, 97), 'en': (218, 192, 96), 'jp': (217, 191, 94), 'tw': (213, 188, 99)}, button={'cn': (784, 551, 870, 576), 'en': (787, 552, 866, 574), 'jp': (777, 547, 860, 569), 'tw': (780, 550, 870, 576)}, file={'cn': './assets/cn/meowfficer/MEOWFFICER_TRAIN_FINISH_ALL.png', 'en': './assets/en/meowfficer/MEOWFFICER_TRAIN_FINISH_ALL.png', 'jp': './assets/jp/meowfficer/MEOWFFICER_TRAIN_FINISH_ALL.png', 'tw': './assets/tw/meowfficer/MEOWFFICER_TRAIN_FINISH_ALL.png'})
MEOWFFICER_TRAIN_START = Button(area={'cn': (937, 553, 1024, 575), 'en': (921, 552, 1039, 577), 'jp': (930, 551, 1027, 578), 'tw': (930, 551, 1026, 576)}, color={'cn': (209, 183, 91), 'en': (220, 194, 90), 'jp': (210, 184, 87), 'tw': (211, 185, 96)}, button={'cn': (937, 553, 1024, 575), 'en': (921, 552, 1039, 577), 'jp': (930, 551, 1027, 578), 'tw': (930, 551, 1026, 576)}, file={'cn': './assets/cn/meowfficer/MEOWFFICER_TRAIN_START.png', 'en': './assets/en/meowfficer/MEOWFFICER_TRAIN_START.png', 'jp': './assets/jp/meowfficer/MEOWFFICER_TRAIN_START.png', 'tw': './assets/tw/meowfficer/MEOWFFICER_TRAIN_START.png'})
OCR_MEOWFFICER = Button(area={'cn': (1046, 672, 1092, 693), 'en': (1054, 673, 1097, 692), 'jp': (1052, 674, 1094, 690), 'tw': (1048, 674, 1091, 692)}, color={'cn': (217, 203, 192), 'en': (210, 194, 182), 'jp': (201, 183, 171), 'tw': (201, 185, 172)}, button={'cn': (1046, 672, 1092, 693), 'en': (1054, 673, 1097, 692), 'jp': (1052, 674, 1094, 690), 'tw': (1048, 674, 1091, 692)}, file={'cn': './assets/cn/meowfficer/OCR_MEOWFFICER.png', 'en': './assets/en/meowfficer/OCR_MEOWFFICER.png', 'jp': './assets/jp/meowfficer/OCR_MEOWFFICER.png', 'tw': './assets/tw/meowfficer/OCR_MEOWFFICER.png'})
OCR_MEOWFFICER = Button(area={'cn': (1046, 672, 1092, 693), 'en': (1054, 673, 1097, 692), 'jp': (1046, 672, 1092, 692), 'tw': (1048, 674, 1091, 692)}, color={'cn': (217, 203, 192), 'en': (210, 194, 182), 'jp': (215, 201, 189), 'tw': (201, 185, 172)}, button={'cn': (1046, 672, 1092, 693), 'en': (1054, 673, 1097, 692), 'jp': (1046, 672, 1092, 692), 'tw': (1048, 674, 1091, 692)}, file={'cn': './assets/cn/meowfficer/OCR_MEOWFFICER.png', 'en': './assets/en/meowfficer/OCR_MEOWFFICER.png', 'jp': './assets/jp/meowfficer/OCR_MEOWFFICER.png', 'tw': './assets/tw/meowfficer/OCR_MEOWFFICER.png'})
OCR_MEOWFFICER_CAPACITY = Button(area={'cn': (739, 563, 849, 597), 'en': (739, 563, 849, 597), 'jp': (739, 563, 849, 597), 'tw': (739, 563, 849, 597)}, color={'cn': (227, 225, 225), 'en': (227, 225, 225), 'jp': (227, 225, 225), 'tw': (227, 225, 225)}, button={'cn': (739, 563, 849, 597), 'en': (739, 563, 849, 597), 'jp': (739, 563, 849, 597), 'tw': (739, 563, 849, 597)}, file={'cn': './assets/cn/meowfficer/OCR_MEOWFFICER_CAPACITY.png', 'en': './assets/en/meowfficer/OCR_MEOWFFICER_CAPACITY.png', 'jp': './assets/jp/meowfficer/OCR_MEOWFFICER_CAPACITY.png', 'tw': './assets/tw/meowfficer/OCR_MEOWFFICER_CAPACITY.png'})
OCR_MEOWFFICER_CHOOSE = Button(area={'cn': (800, 279, 862, 305), 'en': (802, 277, 882, 307), 'jp': (800, 279, 862, 305), 'tw': (800, 279, 862, 305)}, color={'cn': (244, 241, 239), 'en': (247, 245, 243), 'jp': (244, 241, 239), 'tw': (244, 241, 239)}, button={'cn': (800, 279, 862, 305), 'en': (802, 277, 882, 307), 'jp': (800, 279, 862, 305), 'tw': (800, 279, 862, 305)}, file={'cn': './assets/cn/meowfficer/OCR_MEOWFFICER_CHOOSE.png', 'en': './assets/en/meowfficer/OCR_MEOWFFICER_CHOOSE.png', 'jp': './assets/jp/meowfficer/OCR_MEOWFFICER_CHOOSE.png', 'tw': './assets/tw/meowfficer/OCR_MEOWFFICER_CHOOSE.png'})
OCR_MEOWFFICER_COINS = Button(area={'cn': (1161, 20, 1261, 48), 'en': (1161, 20, 1261, 48), 'jp': (1161, 20, 1261, 48), 'tw': (1160, 20, 1256, 49)}, color={'cn': (200, 198, 192), 'en': (200, 198, 192), 'jp': (200, 198, 192), 'tw': (200, 198, 192)}, button={'cn': (1161, 20, 1261, 48), 'en': (1161, 20, 1261, 48), 'jp': (1161, 20, 1261, 48), 'tw': (1160, 20, 1256, 49)}, file={'cn': './assets/cn/meowfficer/OCR_MEOWFFICER_COINS.png', 'en': './assets/en/meowfficer/OCR_MEOWFFICER_COINS.png', 'jp': './assets/jp/meowfficer/OCR_MEOWFFICER_COINS.png', 'tw': './assets/tw/meowfficer/OCR_MEOWFFICER_COINS.png'})

View File

@ -87,6 +87,7 @@ class OSMap(OSFleet, Map, GlobeCamera):
self.zone = self.get_globe_pinned_zone()
self.zone_config_set()
self.os_globe_goto_map()
self.zone_init(fallback_init=False)
return self.zone
def globe_goto(self, zone, types=('SAFE', 'DANGEROUS'), refresh=False, stop_if_safe=False):

View File

@ -55,6 +55,10 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle
name = name.replace('é', 'e')
if 'nvcity' in name: # NY City Port read as 'V' rather than 'Y'
name = 'nycity'
if 'cibraltar' in name:
name = 'gibraltar'
if 'pasage' in name:
name = 'passage'
# `-` is missing
name = name.replace('safe', '')
name = name.replace('zone', '')
@ -133,13 +137,14 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle
self.config.HOMO_EDGE_COLOR_RANGE = (0, 33)
self.config.MAP_ENSURE_EDGE_INSIGHT_CORNER = ''
def zone_init(self, skip_first_screenshot=True):
def zone_init(self, fallback_init=True, skip_first_screenshot=True):
"""
Wrap get_current_zone(), set self.zone to the current zone.
This method must be called after entering a new zone.
Handle map events and the animation that zone names appear from the top.
Args:
fallback_init (bool): Whether to get zone from globe map when unable to parse zone name.
skip_first_screenshot (bool):
Returns:
@ -180,14 +185,15 @@ class OSMapOperation(MapOrderHandler, MissionHandler, PortHandler, StorageHandle
timeout.reset()
continue
logger.warning('Unable to get zone name, get current zone from globe map instead')
if hasattr(self, 'get_current_zone_from_globe'):
return self.get_current_zone_from_globe()
else:
logger.warning('OperationSiren.get_current_zone_from_globe() not exists')
if not self.is_in_map():
logger.warning('Trying to get zone name, but not in OS map')
return self.get_current_zone()
if fallback_init:
logger.warning('Unable to get zone name, get current zone from globe map instead')
if hasattr(self, 'get_current_zone_from_globe'):
return self.get_current_zone_from_globe()
else:
logger.warning('OperationSiren.get_current_zone_from_globe() not exists')
if not self.is_in_map():
logger.warning('Trying to get zone name, but not in OS map')
return self.get_current_zone()
def is_in_special_zone(self):
"""

View File

@ -18,7 +18,6 @@ DETAIL_GENRE_T = Button(area={'cn': (323, 110, 418, 133), 'en': (323, 110, 418,
DETAIL_ITEMS_ODD = Button(area={'cn': (408, 447, 422, 525), 'en': (408, 447, 422, 525), 'jp': (408, 447, 422, 525), 'tw': (408, 447, 422, 525)}, color={'cn': (145, 169, 164), 'en': (145, 169, 164), 'jp': (145, 169, 164), 'tw': (145, 169, 164)}, button={'cn': (408, 447, 422, 525), 'en': (408, 447, 422, 525), 'jp': (408, 447, 422, 525), 'tw': (408, 447, 422, 525)}, file={'cn': './assets/cn/research/DETAIL_ITEMS_ODD.png', 'en': './assets/en/research/DETAIL_ITEMS_ODD.png', 'jp': './assets/jp/research/DETAIL_ITEMS_ODD.png', 'tw': './assets/tw/research/DETAIL_ITEMS_ODD.png'})
DETAIL_NEXT = Button(area={'cn': (1236, 347, 1257, 374), 'en': (1236, 347, 1257, 374), 'jp': (1236, 347, 1257, 374), 'tw': (1236, 347, 1257, 374)}, color={'cn': (98, 148, 165), 'en': (98, 148, 165), 'jp': (98, 148, 165), 'tw': (98, 148, 165)}, button={'cn': (1236, 347, 1257, 374), 'en': (1236, 347, 1257, 374), 'jp': (1236, 347, 1257, 374), 'tw': (1236, 347, 1257, 374)}, file={'cn': './assets/cn/research/DETAIL_NEXT.png', 'en': './assets/en/research/DETAIL_NEXT.png', 'jp': './assets/jp/research/DETAIL_NEXT.png', 'tw': './assets/tw/research/DETAIL_NEXT.png'})
DURATION_DETAIL = Button(area={'cn': (788, 274, 913, 319), 'en': (788, 274, 913, 319), 'jp': (788, 274, 913, 319), 'tw': (788, 274, 913, 319)}, color={'cn': (102, 112, 132), 'en': (102, 112, 132), 'jp': (102, 112, 132), 'tw': (102, 112, 132)}, button={'cn': (788, 274, 913, 319), 'en': (788, 274, 913, 319), 'jp': (788, 274, 913, 319), 'tw': (788, 274, 913, 319)}, file={'cn': './assets/cn/research/DURATION_DETAIL.png', 'en': './assets/en/research/DURATION_DETAIL.png', 'jp': './assets/jp/research/DURATION_DETAIL.png', 'tw': './assets/tw/research/DURATION_DETAIL.png'})
DURATION_REMAIN = Button(area={'cn': (622, 579, 732, 613), 'en': (622, 579, 732, 613), 'jp': (622, 579, 732, 613), 'tw': (622, 579, 732, 613)}, color={'cn': (188, 211, 239), 'en': (188, 211, 239), 'jp': (188, 211, 239), 'tw': (188, 211, 239)}, button={'cn': (622, 579, 732, 613), 'en': (622, 579, 732, 613), 'jp': (622, 579, 732, 613), 'tw': (622, 579, 732, 613)}, file={'cn': './assets/cn/research/DURATION_REMAIN.png', 'en': './assets/en/research/DURATION_REMAIN.png', 'jp': './assets/jp/research/DURATION_REMAIN.png', 'tw': './assets/tw/research/DURATION_REMAIN.png'})
ENTRANCE_1 = Button(area={'cn': (52, 186, 198, 375), 'en': (52, 186, 198, 375), 'jp': (52, 186, 198, 375), 'tw': (52, 186, 198, 375)}, color={'cn': (110, 162, 216), 'en': (110, 162, 216), 'jp': (110, 162, 216), 'tw': (110, 162, 216)}, button={'cn': (52, 186, 198, 375), 'en': (52, 186, 198, 375), 'jp': (52, 186, 198, 375), 'tw': (52, 186, 198, 375)}, file={'cn': './assets/cn/research/ENTRANCE_1.png', 'en': './assets/en/research/ENTRANCE_1.png', 'jp': './assets/jp/research/ENTRANCE_1.png', 'tw': './assets/tw/research/ENTRANCE_1.png'})
ENTRANCE_2 = Button(area={'cn': (296, 157, 465, 376), 'en': (296, 157, 465, 376), 'jp': (296, 157, 465, 376), 'tw': (296, 157, 465, 376)}, color={'cn': (110, 162, 216), 'en': (110, 162, 216), 'jp': (110, 162, 216), 'tw': (110, 162, 216)}, button={'cn': (296, 157, 465, 376), 'en': (296, 157, 465, 376), 'jp': (296, 157, 465, 376), 'tw': (296, 157, 465, 376)}, file={'cn': './assets/cn/research/ENTRANCE_2.png', 'en': './assets/en/research/ENTRANCE_2.png', 'jp': './assets/jp/research/ENTRANCE_2.png', 'tw': './assets/tw/research/ENTRANCE_2.png'})
ENTRANCE_3 = Button(area={'cn': (542, 130, 730, 378), 'en': (542, 130, 730, 378), 'jp': (542, 130, 730, 378), 'tw': (542, 130, 730, 378)}, color={'cn': (224, 190, 135), 'en': (224, 190, 135), 'jp': (224, 190, 135), 'tw': (224, 190, 135)}, button={'cn': (542, 130, 730, 378), 'en': (542, 130, 730, 378), 'jp': (542, 130, 730, 378), 'tw': (542, 130, 730, 378)}, file={'cn': './assets/cn/research/ENTRANCE_3.png', 'en': './assets/en/research/ENTRANCE_3.png', 'jp': './assets/jp/research/ENTRANCE_3.png', 'tw': './assets/tw/research/ENTRANCE_3.png'})

View File

@ -1,6 +1,5 @@
import numpy as np
from module.base.decorator import Config
from module.base.timer import Timer
from module.base.utils import rgb2gray
from module.combat.assets import GET_ITEMS_1, GET_ITEMS_2, GET_ITEMS_3
@ -326,38 +325,6 @@ class RewardResearch(ResearchSelector):
return True
@Config.when(SERVER='jp')
def research_get_remain(self):
"""
Get remain duration of current project (the one in the middle).
Returns:
float: research project remain time if success
None: if failed
Pages:
in: page_research, stable.
out: page_research, stable.
"""
ocr = Duration(DURATION_REMAIN, letter=(255, 255, 255), threshold=64, name='DURATION_REMAIN')
logger.hr('Research get remain')
self.interval_clear(MAIN_GOTO_CAMPAIGN)
self.ui_ensure_research()
remain = ocr.ocr(self.device.image)
logger.info(f'Research project remain: {remain}')
seconds = remain.total_seconds()
if seconds >= 0:
research_duration_remain = seconds / 3600
return research_duration_remain
else:
logger.warning(f'Invalid research duration: {seconds} ')
return None
@Config.when(SERVER=None)
def research_get_remain(self):
"""
Get remain duration of current project from page_reward.

View File

@ -19,6 +19,7 @@ SHIPYARD_PROGRESS_DEV = Button(area={'cn': (1184, 145, 1273, 175), 'en': (1184,
SHIPYARD_PROGRESS_FATE = Button(area={'cn': (1141, 153, 1278, 190), 'en': (1141, 153, 1278, 190), 'jp': (1189, 151, 1267, 188), 'tw': (1141, 153, 1278, 190)}, color={'cn': (82, 85, 89), 'en': (82, 85, 89), 'jp': (120, 121, 125), 'tw': (82, 85, 89)}, button={'cn': (1141, 153, 1278, 190), 'en': (1141, 153, 1278, 190), 'jp': (1189, 151, 1267, 188), 'tw': (1141, 153, 1278, 190)}, file={'cn': './assets/cn/shipyard/SHIPYARD_PROGRESS_FATE.png', 'en': './assets/en/shipyard/SHIPYARD_PROGRESS_FATE.png', 'jp': './assets/jp/shipyard/SHIPYARD_PROGRESS_FATE.png', 'tw': './assets/tw/shipyard/SHIPYARD_PROGRESS_FATE.png'})
SHIPYARD_RESEARCH_COMPLETE = Button(area={'cn': (548, 498, 740, 531), 'en': (548, 498, 740, 531), 'jp': (536, 494, 731, 538), 'tw': (548, 498, 740, 531)}, color={'cn': (214, 142, 124), 'en': (214, 142, 124), 'jp': (208, 120, 95), 'tw': (214, 142, 124)}, button={'cn': (548, 498, 740, 531), 'en': (548, 498, 740, 531), 'jp': (536, 494, 731, 538), 'tw': (548, 498, 740, 531)}, file={'cn': './assets/cn/shipyard/SHIPYARD_RESEARCH_COMPLETE.png', 'en': './assets/en/shipyard/SHIPYARD_RESEARCH_COMPLETE.png', 'jp': './assets/jp/shipyard/SHIPYARD_RESEARCH_COMPLETE.png', 'tw': './assets/tw/shipyard/SHIPYARD_RESEARCH_COMPLETE.png'})
SHIPYARD_RESEARCH_INCOMPLETE = Button(area={'cn': (616, 490, 740, 531), 'en': (616, 490, 740, 531), 'jp': (614, 493, 735, 521), 'tw': (616, 490, 740, 531)}, color={'cn': (229, 192, 121), 'en': (229, 192, 121), 'jp': (244, 219, 164), 'tw': (229, 192, 121)}, button={'cn': (616, 490, 740, 531), 'en': (616, 490, 740, 531), 'jp': (614, 493, 735, 521), 'tw': (616, 490, 740, 531)}, file={'cn': './assets/cn/shipyard/SHIPYARD_RESEARCH_INCOMPLETE.png', 'en': './assets/en/shipyard/SHIPYARD_RESEARCH_INCOMPLETE.png', 'jp': './assets/jp/shipyard/SHIPYARD_RESEARCH_INCOMPLETE.png', 'tw': './assets/tw/shipyard/SHIPYARD_RESEARCH_INCOMPLETE.png'})
SHIPYARD_RESEARCH_IN_PROGRESS = Button(area={'cn': (465, 479, 482, 501), 'en': (465, 479, 482, 501), 'jp': (465, 479, 482, 501), 'tw': (465, 479, 482, 501)}, color={'cn': (105, 135, 173), 'en': (105, 135, 173), 'jp': (105, 135, 173), 'tw': (105, 135, 173)}, button={'cn': (465, 479, 482, 501), 'en': (465, 479, 482, 501), 'jp': (465, 479, 482, 501), 'tw': (465, 479, 482, 501)}, file={'cn': './assets/cn/shipyard/SHIPYARD_RESEARCH_IN_PROGRESS.png', 'en': './assets/en/shipyard/SHIPYARD_RESEARCH_IN_PROGRESS.png', 'jp': './assets/jp/shipyard/SHIPYARD_RESEARCH_IN_PROGRESS.png', 'tw': './assets/tw/shipyard/SHIPYARD_RESEARCH_IN_PROGRESS.png'})
SHIPYARD_SERIES_SELECT_CHECK = Button(area={'cn': (567, 209, 717, 228), 'en': (567, 209, 717, 228), 'jp': (566, 210, 718, 228), 'tw': (567, 209, 717, 228)}, color={'cn': (21, 30, 58), 'en': (21, 30, 58), 'jp': (21, 30, 58), 'tw': (21, 30, 58)}, button={'cn': (567, 209, 717, 228), 'en': (567, 209, 717, 228), 'jp': (566, 210, 718, 228), 'tw': (567, 209, 717, 228)}, file={'cn': './assets/cn/shipyard/SHIPYARD_SERIES_SELECT_CHECK.png', 'en': './assets/en/shipyard/SHIPYARD_SERIES_SELECT_CHECK.png', 'jp': './assets/jp/shipyard/SHIPYARD_SERIES_SELECT_CHECK.png', 'tw': './assets/tw/shipyard/SHIPYARD_SERIES_SELECT_CHECK.png'})
SHIPYARD_SERIES_SELECT_ENTER = Button(area={'cn': (33, 659, 161, 701), 'en': (34, 659, 160, 700), 'jp': (36, 674, 154, 696), 'tw': (33, 657, 157, 697)}, color={'cn': (91, 110, 155), 'en': (66, 87, 138), 'jp': (112, 126, 161), 'tw': (98, 117, 164)}, button={'cn': (33, 659, 161, 701), 'en': (34, 659, 160, 700), 'jp': (36, 674, 154, 696), 'tw': (33, 657, 157, 697)}, file={'cn': './assets/cn/shipyard/SHIPYARD_SERIES_SELECT_ENTER.png', 'en': './assets/en/shipyard/SHIPYARD_SERIES_SELECT_ENTER.png', 'jp': './assets/jp/shipyard/SHIPYARD_SERIES_SELECT_ENTER.png', 'tw': './assets/tw/shipyard/SHIPYARD_SERIES_SELECT_ENTER.png'})
SHIPYARD_TOTAL_DEV = Button(area={'cn': (1086, 429, 1147, 463), 'en': (1091, 426, 1142, 466), 'jp': (1086, 429, 1147, 463), 'tw': (1086, 429, 1147, 463)}, color={'cn': (39, 46, 55), 'en': (45, 48, 55), 'jp': (39, 46, 55), 'tw': (39, 46, 55)}, button={'cn': (1086, 429, 1147, 463), 'en': (1091, 426, 1142, 466), 'jp': (1086, 429, 1147, 463), 'tw': (1086, 429, 1147, 463)}, file={'cn': './assets/cn/shipyard/SHIPYARD_TOTAL_DEV.png', 'en': './assets/en/shipyard/SHIPYARD_TOTAL_DEV.png', 'jp': './assets/jp/shipyard/SHIPYARD_TOTAL_DEV.png', 'tw': './assets/tw/shipyard/SHIPYARD_TOTAL_DEV.png'})

View File

@ -4,6 +4,7 @@ from module.logger import logger
from module.shipyard.assets import *
from module.shipyard.ui_globals import *
from module.ui.navbar import Navbar
from module.ui.assets import SHIPYARD_CHECK
from module.ui.ui import UI
@ -126,6 +127,8 @@ class ShipyardUI(UI):
Returns:
bool whether in appropriate shipyard ui area
"""
if self.appear(SHIPYARD_CHECK, offset=(20, 20)):
return True
if self.appear(SHIPYARD_IN_DEV, offset=(20, 20)):
return True
if self.appear(SHIPYARD_IN_FATE, offset=(20, 20)):
@ -336,7 +339,8 @@ class ShipyardUI(UI):
Returns:
bool whether entered
"""
if self.appear(SHIPYARD_RESEARCH_INCOMPLETE, offset=(20, 20)):
if self.appear(SHIPYARD_RESEARCH_INCOMPLETE, offset=(20, 20)) or \
self.appear(SHIPYARD_RESEARCH_IN_PROGRESS, offset=(20, 20)):
logger.warning('Cannot enter buy interface, focused '
'ship has not yet been fully researched')
return False

View File

@ -78,6 +78,7 @@ class CampaignSos(CampaignRun, CampaignBase):
def _sos_signal_select(self, chapter):
"""
select a SOS signal
EN has no scroll bar, so the swipe signal list.
Args:
chapter (int): 3 to 10.
@ -139,7 +140,7 @@ class CampaignSos(CampaignRun, CampaignBase):
for scroll_position in positions:
if self._sos_scroll.appear(main=self):
self._sos_scroll.set(scroll_position, main=self)
self._sos_scroll.set(scroll_position, main=self, distance_check=False)
else:
logger.info('SOS signal scroll not appear, skip setting scroll position')
target_button = self._find_target_chapter(chapter)

View File

@ -57,7 +57,7 @@ BOOK_FILTER = Filter(
'(same)?'
'(red|blue|yellow)?'
'-?'
'(t[123])?'
'(t[1234])?'
),
attr=('same_str', 'genre_str', 'tier_str'),
preset=('first',)

View File

@ -106,7 +106,7 @@ class Scroll:
def at_bottom(self, main):
return self.cal_position(main) > 0.95
def set(self, position, main, random_range=(-0.05, 0.05), skip_first_screenshot=True):
def set(self, position, main, random_range=(-0.05, 0.05), distance_check=True, skip_first_screenshot=True):
"""
Set scroll to a specific position.
@ -114,6 +114,7 @@ class Scroll:
position (float, int): 0 to 1.
main (ModuleBase):
random_range (tuple(int, float)):
distance_check (bool): Whether to drop short swipes
skip_first_screenshot:
"""
logger.info(f'{self.name} set to {position}')
@ -139,7 +140,7 @@ class Scroll:
if self.drag_interval.reached():
p1 = random_rectangle_point(self.position_to_screen(current), n=1)
p2 = random_rectangle_point(self.position_to_screen(position, random_range=random_range), n=1)
main.device.swipe(p1, p2, name=self.name)
main.device.swipe(p1, p2, name=self.name, distance_check=distance_check)
main.device.sleep(0.3)
self.drag_interval.reset()

View File

@ -17,7 +17,8 @@ from module.os_handler.assets import (EXCHANGE_CHECK, RESET_FLEET_PREPARATION,
from module.raid.assets import RAID_FLEET_PREPARATION
from module.ui.assets import (BACK_ARROW, DORM_FEED_CANCEL, DORM_INFO,
DORM_TROPHY_CONFIRM, EVENT_LIST_CHECK, GOTO_MAIN,
MEOWFFICER_INFO, MEOWFFICER_GOTO_DORMMENU, META_CHECK,
MAIN_GOTO_CAMPAIGN, MEOWFFICER_INFO,
MEOWFFICER_GOTO_DORMMENU, META_CHECK,
PLAYER_CHECK, SHIPYARD_CHECK, SHOP_GOTO_SUPPLY_PACK)
from module.ui.page import (Page, page_academy, page_archives,
page_battle_pass, page_build, page_campaign,
@ -532,5 +533,7 @@ class UI(InfoHandler):
"""
if button == MEOWFFICER_GOTO_DORMMENU:
self.interval_reset(GET_SHIP)
if button == MAIN_GOTO_CAMPAIGN:
self.interval_reset(GET_SHIP)
if button == SHOP_GOTO_SUPPLY_PACK:
self.interval_reset(EXCHANGE_CHECK)

View File

@ -24,5 +24,4 @@ pypresence==4.2.1
alas-webapp==0.3.7
rich==11.0.0
zerorpc==0.6.3
pyzmq==22.3.0
atomicwrites
pyzmq==22.3.0

View File

@ -4,14 +4,13 @@
#
# pip-compile --annotation-style=line --output-file=requirements.txt requirements-in.txt
#
adbutils==0.11.0 # via uiautomator2
adbutils==0.11.0 # via -r requirements-in.txt, uiautomator2
aiofiles==0.7.0 # via -r requirements-in.txt
alas-webapp==0.3.7 # via -r requirements-in.txt
anyio==1.3.1 # via -r requirements-in.txt
apkutils2==1.0.0 # via adbutils
asgiref==3.4.1 # via uvicorn
async-generator==1.10 # via anyio
atomicwrites==1.4.0 # via -r requirements-in.txt
cached-property==1.5.2 # via uiautomator2
certifi==2021.5.30 # via requests
cffi==1.15.0 # via gevent
@ -63,7 +62,7 @@ python-dotenv==0.19.0 # via uvicorn
pywebio==1.5.2 # via -r requirements-in.txt
pywin32==301 # via portalocker
pyyaml==5.4.1 # via -r requirements-in.txt, uvicorn
pyzmq==22.3.0 # via zerorpc
pyzmq==22.3.0 # via -r requirements-in.txt, zerorpc
requests==2.18.4 # via adbutils, gluoncv, mxnet, uiautomator2
retry==0.9.2 # via adbutils, uiautomator2
retrying==1.3.3 # via -r requirements-in.txt