Add: Semi-auto, Opsi semi-auto and benchmark
- Add: dependency prettytable - Fix: Running an Alas module directly - Del: Remove all assets in daemon module, because it's redundant
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.4 KiB |
@ -1212,5 +1212,21 @@
|
||||
"ActionPointPreserve": 500,
|
||||
"HazardLevel": 5
|
||||
}
|
||||
},
|
||||
"Daemon": {
|
||||
"Daemon": {
|
||||
"EnterMap": true
|
||||
}
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"OpsiDaemon": {
|
||||
"RepairShip": true
|
||||
}
|
||||
},
|
||||
"Benchmark": {
|
||||
"Benchmark": {
|
||||
"TestScreenshotMethod": true,
|
||||
"TestClickMethod": true
|
||||
}
|
||||
}
|
||||
}
|
@ -14,14 +14,15 @@ class ModuleBase:
|
||||
device: Device
|
||||
stat: AzurStats
|
||||
|
||||
def __init__(self, config, device=None):
|
||||
def __init__(self, config, device=None, task=None):
|
||||
"""
|
||||
Args:
|
||||
config (AzurLaneConfig, str):
|
||||
device (Device):
|
||||
config (AzurLaneConfig, str): Name of the user config under ./config
|
||||
device (Device): To reuse a device. If None, create a new Device object.
|
||||
task (str): Bind a task only for dev purpose. Usually to be None for auto task scheduling.
|
||||
"""
|
||||
if isinstance(config, str):
|
||||
self.config = AzurLaneConfig(config)
|
||||
self.config = AzurLaneConfig(config, task=task)
|
||||
else:
|
||||
self.config = config
|
||||
if device is not None:
|
||||
|
@ -5467,5 +5467,33 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Daemon": {
|
||||
"Daemon": {
|
||||
"EnterMap": {
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"OpsiDaemon": {
|
||||
"RepairShip": {
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"Benchmark": {
|
||||
"Benchmark": {
|
||||
"TestScreenshotMethod": {
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
},
|
||||
"TestClickMethod": {
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -403,3 +403,13 @@ OpsiMeowfficerFarming:
|
||||
HazardLevel:
|
||||
value: 5
|
||||
option: [1, 2, 3, 4, 5, 6]
|
||||
|
||||
# ==================== Tools ====================
|
||||
|
||||
Daemon:
|
||||
EnterMap: true
|
||||
OpsiDaemon:
|
||||
RepairShip: true
|
||||
Benchmark:
|
||||
TestScreenshotMethod: true
|
||||
TestClickMethod: true
|
||||
|
@ -45,6 +45,11 @@
|
||||
"OpsiDaily",
|
||||
"OpsiObscure",
|
||||
"OpsiMeowfficerFarming"
|
||||
],
|
||||
"Tool": [
|
||||
"Daemon",
|
||||
"OpsiDaemon",
|
||||
"Benchmark"
|
||||
]
|
||||
}
|
||||
}
|
@ -191,3 +191,12 @@ OpsiObscure:
|
||||
OpsiMeowfficerFarming:
|
||||
- Scheduler
|
||||
- OpsiMeowfficerFarming
|
||||
|
||||
# ==================== Tool ====================
|
||||
|
||||
Daemon:
|
||||
- Daemon
|
||||
OpsiDaemon:
|
||||
- OpsiDaemon
|
||||
Benchmark:
|
||||
- Benchmark
|
||||
|
@ -278,3 +278,13 @@ class GeneratedConfig:
|
||||
# Group `OpsiMeowfficerFarming`
|
||||
OpsiMeowfficerFarming_ActionPointPreserve = 500
|
||||
OpsiMeowfficerFarming_HazardLevel = 5 # 1, 2, 3, 4, 5, 6
|
||||
|
||||
# Group `Daemon`
|
||||
Daemon_EnterMap = True
|
||||
|
||||
# Group `OpsiDaemon`
|
||||
OpsiDaemon_RepairShip = True
|
||||
|
||||
# Group `Benchmark`
|
||||
Benchmark_TestScreenshotMethod = True
|
||||
Benchmark_TestClickMethod = True
|
||||
|
@ -23,6 +23,10 @@
|
||||
"Opsi": {
|
||||
"name": "OpSi",
|
||||
"help": ""
|
||||
},
|
||||
"Tool": {
|
||||
"name": "Tools",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Task": {
|
||||
@ -169,6 +173,18 @@
|
||||
"OpsiMeowfficerFarming": {
|
||||
"name": "OpSi Meowfficer Farming",
|
||||
"help": ""
|
||||
},
|
||||
"Daemon": {
|
||||
"name": "Semi-auto Clicking",
|
||||
"help": ""
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"name": "Opsi Semi-auto",
|
||||
"help": ""
|
||||
},
|
||||
"Benchmark": {
|
||||
"name": "Performance Test",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
@ -1450,6 +1466,40 @@
|
||||
"6": "6"
|
||||
}
|
||||
},
|
||||
"Daemon": {
|
||||
"_info": {
|
||||
"name": "Semi-auto Clicking",
|
||||
"help": "Useful when attacking a stage haven't adapted by Alas. Can save tons of manual clicks\nAlas will click combat preparation, click combat drop, skip story, auto-retire, close popups. You only need to choose enemies."
|
||||
},
|
||||
"EnterMap": {
|
||||
"name": "Auto Click Stage Preparation",
|
||||
"help": "Prepare your fleets before using this"
|
||||
}
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"_info": {
|
||||
"name": "Useful when attacking logger zones or Opsi story. Can save tons of manual clicks.\nAlas will click combat preparation, click combat drop, skip story, close popups. You only need to choose enemies and switch zones.",
|
||||
"help": "OpsiDaemon._info.help"
|
||||
},
|
||||
"RepairShip": {
|
||||
"name": "Repair Ships When Nearing Port",
|
||||
"help": "After you move fleet to port, Alas will repair your ships in port.\nWhen it's done, move your fleet outside of port in 30s to avoid repairing again"
|
||||
}
|
||||
},
|
||||
"Benchmark": {
|
||||
"_info": {
|
||||
"name": "Performance Test",
|
||||
"help": "Test which screenshot method and click method is the fastest. Speed is vary from emulators and PCs."
|
||||
},
|
||||
"TestScreenshotMethod": {
|
||||
"name": "Test Screenshots Methods",
|
||||
"help": ""
|
||||
},
|
||||
"TestClickMethod": {
|
||||
"name": "Test Click Methods",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
"Aside": {
|
||||
"Install": "Install",
|
||||
|
@ -23,6 +23,10 @@
|
||||
"Opsi": {
|
||||
"name": "Menu.Opsi.name",
|
||||
"help": "Menu.Opsi.help"
|
||||
},
|
||||
"Tool": {
|
||||
"name": "Menu.Tool.name",
|
||||
"help": "Menu.Tool.help"
|
||||
}
|
||||
},
|
||||
"Task": {
|
||||
@ -169,6 +173,18 @@
|
||||
"OpsiMeowfficerFarming": {
|
||||
"name": "Task.OpsiMeowfficerFarming.name",
|
||||
"help": "Task.OpsiMeowfficerFarming.help"
|
||||
},
|
||||
"Daemon": {
|
||||
"name": "Task.Daemon.name",
|
||||
"help": "Task.Daemon.help"
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"name": "Task.OpsiDaemon.name",
|
||||
"help": "Task.OpsiDaemon.help"
|
||||
},
|
||||
"Benchmark": {
|
||||
"name": "Task.Benchmark.name",
|
||||
"help": "Task.Benchmark.help"
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
@ -1450,6 +1466,40 @@
|
||||
"6": "6"
|
||||
}
|
||||
},
|
||||
"Daemon": {
|
||||
"_info": {
|
||||
"name": "Daemon._info.name",
|
||||
"help": "Daemon._info.help"
|
||||
},
|
||||
"EnterMap": {
|
||||
"name": "Daemon.EnterMap.name",
|
||||
"help": "Daemon.EnterMap.help"
|
||||
}
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"_info": {
|
||||
"name": "OpsiDaemon._info.name",
|
||||
"help": "OpsiDaemon._info.help"
|
||||
},
|
||||
"RepairShip": {
|
||||
"name": "OpsiDaemon.RepairShip.name",
|
||||
"help": "OpsiDaemon.RepairShip.help"
|
||||
}
|
||||
},
|
||||
"Benchmark": {
|
||||
"_info": {
|
||||
"name": "Benchmark._info.name",
|
||||
"help": "Benchmark._info.help"
|
||||
},
|
||||
"TestScreenshotMethod": {
|
||||
"name": "Benchmark.TestScreenshotMethod.name",
|
||||
"help": "Benchmark.TestScreenshotMethod.help"
|
||||
},
|
||||
"TestClickMethod": {
|
||||
"name": "Benchmark.TestClickMethod.name",
|
||||
"help": "Benchmark.TestClickMethod.help"
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
"Aside": {
|
||||
"Install": "Gui.Aside.Install",
|
||||
|
@ -23,6 +23,10 @@
|
||||
"Opsi": {
|
||||
"name": "大世界",
|
||||
"help": ""
|
||||
},
|
||||
"Tool": {
|
||||
"name": "工具",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Task": {
|
||||
@ -169,6 +173,18 @@
|
||||
"OpsiMeowfficerFarming": {
|
||||
"name": "短猫相接",
|
||||
"help": ""
|
||||
},
|
||||
"Daemon": {
|
||||
"name": "半自动点击",
|
||||
"help": ""
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"name": "大世界半自动",
|
||||
"help": ""
|
||||
},
|
||||
"Benchmark": {
|
||||
"name": "性能测试",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
@ -1450,6 +1466,40 @@
|
||||
"6": "6"
|
||||
}
|
||||
},
|
||||
"Daemon": {
|
||||
"_info": {
|
||||
"name": "半自动点击",
|
||||
"help": "在出击未适配的关卡时有用,能减少大量人工操作\nAlas 将帮助点击战斗准备,点击战斗结算,跳过剧情,自动退役,关闭各种弹窗。你只需要手动选择敌人。"
|
||||
},
|
||||
"EnterMap": {
|
||||
"name": "自动点击进图准备",
|
||||
"help": "使用之前,需要准备好出击队伍"
|
||||
}
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"_info": {
|
||||
"name": "大世界半自动",
|
||||
"help": "在出击大世界深渊海域(红宝箱图)或完成大世界主线时有用,能减少大量人工操作\nAlas 将帮助点击战斗准备,点击战斗结算,跳过剧情,关闭各种弹窗。你只需要手动选择敌人和手动切换海域。"
|
||||
},
|
||||
"RepairShip": {
|
||||
"name": "靠近港口时自动修船",
|
||||
"help": "手动把队伍移动至港口后,Alas将帮助修船\n修理完成后需要在30秒内将队伍移出港口,否则将再次修船"
|
||||
}
|
||||
},
|
||||
"Benchmark": {
|
||||
"_info": {
|
||||
"name": "性能测试",
|
||||
"help": "测试哪个截图方案和点击方案速度更快,速度因模拟器和电脑配置而异"
|
||||
},
|
||||
"TestScreenshotMethod": {
|
||||
"name": "测试截图方案",
|
||||
"help": ""
|
||||
},
|
||||
"TestClickMethod": {
|
||||
"name": "测试点击方案",
|
||||
"help": ""
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
"Aside": {
|
||||
"Install": "安装",
|
||||
|
@ -23,6 +23,10 @@
|
||||
"Opsi": {
|
||||
"name": "Menu.Opsi.name",
|
||||
"help": "Menu.Opsi.help"
|
||||
},
|
||||
"Tool": {
|
||||
"name": "Menu.Tool.name",
|
||||
"help": "Menu.Tool.help"
|
||||
}
|
||||
},
|
||||
"Task": {
|
||||
@ -169,6 +173,18 @@
|
||||
"OpsiMeowfficerFarming": {
|
||||
"name": "Task.OpsiMeowfficerFarming.name",
|
||||
"help": "Task.OpsiMeowfficerFarming.help"
|
||||
},
|
||||
"Daemon": {
|
||||
"name": "Task.Daemon.name",
|
||||
"help": "Task.Daemon.help"
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"name": "Task.OpsiDaemon.name",
|
||||
"help": "Task.OpsiDaemon.help"
|
||||
},
|
||||
"Benchmark": {
|
||||
"name": "Task.Benchmark.name",
|
||||
"help": "Task.Benchmark.help"
|
||||
}
|
||||
},
|
||||
"Scheduler": {
|
||||
@ -1450,6 +1466,40 @@
|
||||
"6": "6"
|
||||
}
|
||||
},
|
||||
"Daemon": {
|
||||
"_info": {
|
||||
"name": "Daemon._info.name",
|
||||
"help": "Daemon._info.help"
|
||||
},
|
||||
"EnterMap": {
|
||||
"name": "Daemon.EnterMap.name",
|
||||
"help": "Daemon.EnterMap.help"
|
||||
}
|
||||
},
|
||||
"OpsiDaemon": {
|
||||
"_info": {
|
||||
"name": "OpsiDaemon._info.name",
|
||||
"help": "OpsiDaemon._info.help"
|
||||
},
|
||||
"RepairShip": {
|
||||
"name": "OpsiDaemon.RepairShip.name",
|
||||
"help": "OpsiDaemon.RepairShip.help"
|
||||
}
|
||||
},
|
||||
"Benchmark": {
|
||||
"_info": {
|
||||
"name": "Benchmark._info.name",
|
||||
"help": "Benchmark._info.help"
|
||||
},
|
||||
"TestScreenshotMethod": {
|
||||
"name": "Benchmark.TestScreenshotMethod.name",
|
||||
"help": "Benchmark.TestScreenshotMethod.help"
|
||||
},
|
||||
"TestClickMethod": {
|
||||
"name": "Benchmark.TestClickMethod.name",
|
||||
"help": "Benchmark.TestClickMethod.help"
|
||||
}
|
||||
},
|
||||
"Gui": {
|
||||
"Aside": {
|
||||
"Install": "Gui.Aside.Install",
|
||||
|
@ -1,13 +0,0 @@
|
||||
from module.base.button import Button
|
||||
from module.base.template import Template
|
||||
|
||||
# This file was automatically generated by dev_tools.button_extract.
|
||||
# Don't modify it manually.
|
||||
|
||||
AMBUSH_AVOID = Button(area={'cn': (753, 444, 927, 502), 'en': (753, 443, 927, 503), 'jp': (753, 444, 927, 502), 'tw': (762, 443, 927, 499)}, color={'cn': (87, 129, 189), 'en': (94, 136, 195), 'jp': (87, 129, 189), 'tw': (92, 133, 192)}, button={'cn': (979, 444, 1152, 502), 'en': (978, 443, 1153, 503), 'jp': (979, 444, 1152, 502), 'tw': (979, 444, 1152, 502)}, file={'cn': './assets/cn/daemon/AMBUSH_AVOID.png', 'en': './assets/en/daemon/AMBUSH_AVOID.png', 'jp': './assets/jp/daemon/AMBUSH_AVOID.png', 'tw': './assets/tw/daemon/AMBUSH_AVOID.png'})
|
||||
AT_SEA = Button(area={'cn': (749, 654, 921, 707), 'en': (748, 652, 922, 702), 'jp': (748, 653, 921, 707), 'tw': (749, 654, 921, 707)}, color={'cn': (213, 124, 124), 'en': (211, 124, 124), 'jp': (210, 122, 122), 'tw': (213, 124, 124)}, button={'cn': (749, 654, 921, 707), 'en': (748, 652, 922, 702), 'jp': (748, 653, 921, 707), 'tw': (749, 654, 921, 707)}, file={'cn': './assets/cn/daemon/AT_SEA.png', 'en': './assets/en/daemon/AT_SEA.png', 'jp': './assets/jp/daemon/AT_SEA.png', 'tw': './assets/tw/daemon/AT_SEA.png'})
|
||||
FLEET_PREPARATION = Button(area={'cn': (981, 575, 1180, 636), 'en': (978, 572, 1179, 635), 'jp': (1040, 604, 1242, 670), 'tw': (981, 575, 1180, 636)}, color={'cn': (235, 185, 114), 'en': (234, 177, 90), 'jp': (233, 181, 99), 'tw': (235, 185, 114)}, button={'cn': (981, 575, 1180, 636), 'en': (978, 572, 1179, 635), 'jp': (1040, 604, 1242, 670), 'tw': (981, 575, 1180, 636)}, file={'cn': './assets/cn/daemon/FLEET_PREPARATION.png', 'en': './assets/en/daemon/FLEET_PREPARATION.png', 'jp': './assets/jp/daemon/FLEET_PREPARATION.png', 'tw': './assets/tw/daemon/FLEET_PREPARATION.png'})
|
||||
GET_EMERGENCY_REPAIR = Button(area={'cn': (645, 352, 666, 360), 'en': (645, 352, 666, 360), 'jp': (645, 352, 666, 360), 'tw': (645, 352, 666, 360)}, color={'cn': (255, 255, 255), 'en': (255, 255, 255), 'jp': (255, 255, 255), 'tw': (255, 255, 255)}, button={'cn': (645, 352, 666, 360), 'en': (645, 352, 666, 360), 'jp': (645, 352, 666, 360), 'tw': (645, 352, 666, 360)}, file={'cn': './assets/cn/daemon/GET_EMERGENCY_REPAIR.png', 'en': './assets/en/daemon/GET_EMERGENCY_REPAIR.png', 'jp': './assets/jp/daemon/GET_EMERGENCY_REPAIR.png', 'tw': './assets/tw/daemon/GET_EMERGENCY_REPAIR.png'})
|
||||
GET_ITEMS = Button(area={'cn': (538, 217, 741, 253), 'en': (550, 215, 739, 246), 'jp': (539, 220, 741, 252), 'tw': (538, 217, 741, 253)}, color={'cn': (160, 192, 248), 'en': (157, 187, 233), 'jp': (146, 184, 249), 'tw': (160, 192, 248)}, button={'cn': (1120, 643, 1146, 666), 'en': (1120, 643, 1146, 666), 'jp': (1120, 643, 1146, 666), 'tw': (1120, 643, 1146, 666)}, file={'cn': './assets/cn/daemon/GET_ITEMS.png', 'en': './assets/en/daemon/GET_ITEMS.png', 'jp': './assets/jp/daemon/GET_ITEMS.png', 'tw': './assets/tw/daemon/GET_ITEMS.png'})
|
||||
MAP_PREPARATION = Button(area={'cn': (853, 488, 1053, 549), 'en': (852, 489, 1054, 553), 'jp': (850, 485, 1051, 548), 'tw': (853, 488, 1053, 549)}, color={'cn': (235, 186, 114), 'en': (234, 179, 93), 'jp': (232, 181, 101), 'tw': (235, 186, 114)}, button={'cn': (853, 488, 1053, 549), 'en': (852, 489, 1054, 553), 'jp': (850, 485, 1051, 548), 'tw': (853, 488, 1053, 549)}, file={'cn': './assets/cn/daemon/MAP_PREPARATION.png', 'en': './assets/en/daemon/MAP_PREPARATION.png', 'jp': './assets/jp/daemon/MAP_PREPARATION.png', 'tw': './assets/tw/daemon/MAP_PREPARATION.png'})
|
||||
STRATEGY_OPEN = Button(area={'cn': (1102, 480, 1178, 482), 'en': (1102, 480, 1178, 482), 'jp': (1102, 480, 1178, 482), 'tw': (1102, 480, 1178, 482)}, color={'cn': (255, 223, 74), 'en': (255, 223, 74), 'jp': (255, 223, 74), 'tw': (255, 223, 74)}, button={'cn': (1064, 405, 1093, 483), 'en': (1064, 405, 1093, 483), 'jp': (1064, 405, 1093, 483), 'tw': (1064, 405, 1093, 483)}, file={'cn': './assets/cn/daemon/STRATEGY_OPEN.png', 'en': './assets/en/daemon/STRATEGY_OPEN.png', 'jp': './assets/jp/daemon/STRATEGY_OPEN.png', 'tw': './assets/tw/daemon/STRATEGY_OPEN.png'})
|
136
module/daemon/benchmark.py
Normal file
@ -0,0 +1,136 @@
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
from prettytable import PrettyTable
|
||||
|
||||
from module.base.utils import float2str as float2str_
|
||||
from module.base.utils import random_rectangle_point
|
||||
from module.daemon.daemon_base import DaemonBase
|
||||
from module.logger import logger
|
||||
from module.ui.ui import UI, page_campaign
|
||||
|
||||
|
||||
def float2str(n, decimal=3):
|
||||
if not isinstance(n, (float, int)):
|
||||
return str(n)
|
||||
else:
|
||||
return float2str_(n, decimal=decimal) + 's'
|
||||
|
||||
|
||||
class Benchmark(DaemonBase, UI):
|
||||
TEST_TOTAL = 15
|
||||
TEST_BEST = int(TEST_TOTAL * 0.8)
|
||||
|
||||
def benchmark_test(self, func, *args, **kwargs):
|
||||
"""
|
||||
Args:
|
||||
func: Function to test.
|
||||
*args: Passes to func.
|
||||
**kwargs: Passes to func.
|
||||
|
||||
Returns:
|
||||
float: Time cost on average.
|
||||
"""
|
||||
logger.hr(f'Benchmark test', level=2)
|
||||
logger.info(f'Testing function: {func.__name__}')
|
||||
record = []
|
||||
|
||||
for n in range(1, self.TEST_TOTAL + 1):
|
||||
start = time.time()
|
||||
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.warning(f'Benchmark tests failed on func: {func.__name__}')
|
||||
return 'Failed'
|
||||
|
||||
cost = time.time() - start
|
||||
logger.attr(
|
||||
f'{str(n).rjust(2, "0")}/{self.TEST_TOTAL}',
|
||||
f'{float2str(cost)}'
|
||||
)
|
||||
record.append(cost)
|
||||
|
||||
logger.info('Benchmark tests done')
|
||||
average = float(np.mean(np.sort(record)[:self.TEST_BEST]))
|
||||
logger.info(f'Time cost {float2str(average)} ({self.TEST_BEST} best results out of {self.TEST_TOTAL} tests)')
|
||||
return average
|
||||
|
||||
@staticmethod
|
||||
def evaluate_screenshot(cost):
|
||||
if not isinstance(cost, (float, int)):
|
||||
return str(cost)
|
||||
|
||||
if cost < 0.25:
|
||||
return 'Very Fast'
|
||||
if cost < 0.45:
|
||||
return 'Fast'
|
||||
if cost < 0.65:
|
||||
return 'Medium'
|
||||
if cost < 0.95:
|
||||
return 'Slow'
|
||||
return 'Very Slow'
|
||||
|
||||
@staticmethod
|
||||
def evaluate_click(cost):
|
||||
if not isinstance(cost, (float, int)):
|
||||
return str(cost)
|
||||
|
||||
if cost < 0.1:
|
||||
return 'Fast'
|
||||
if cost < 0.2:
|
||||
return 'Medium'
|
||||
return 'Slow'
|
||||
|
||||
@staticmethod
|
||||
def show(test, data, evaluate_func):
|
||||
"""
|
||||
+--------------+--------+--------+
|
||||
| Screenshot | time | Speed |
|
||||
+--------------+--------+--------+
|
||||
| ADB | 0.319s | Fast |
|
||||
| uiautomator2 | 0.476s | Medium |
|
||||
| aScreenCap | Failed | Failed |
|
||||
+--------------+--------+--------+
|
||||
"""
|
||||
table = PrettyTable()
|
||||
table.field_names = [test, 'Time', 'Speed']
|
||||
for row in data:
|
||||
table.add_row([row[0], f'{float2str(row[1])}', evaluate_func(row[1])])
|
||||
|
||||
for row in table.get_string().split('\n'):
|
||||
logger.info(row)
|
||||
|
||||
def run(self):
|
||||
logger.hr('Benchmark', level=1)
|
||||
self.ui_ensure(page_campaign)
|
||||
|
||||
data = []
|
||||
if self.config.Benchmark_TestScreenshotMethod:
|
||||
data.append(['ADB', self.benchmark_test(self.device._screenshot_adb)])
|
||||
data.append(['uiautomator2', self.benchmark_test(self.device._screenshot_uiautomator2)])
|
||||
data.append(['aScreenCap', self.benchmark_test(self.device._screenshot_ascreencap)])
|
||||
screenshot = data
|
||||
|
||||
data = []
|
||||
area = (124, 4, 649, 106) # Somewhere save to click.
|
||||
if self.config.Benchmark_TestClickMethod:
|
||||
x, y = random_rectangle_point(area)
|
||||
data.append(['ADB', self.benchmark_test(self.device._click_adb, x, y)])
|
||||
x, y = random_rectangle_point(area)
|
||||
data.append(['uiautomator2', self.benchmark_test(self.device._click_uiautomator2, x, y)])
|
||||
x, y = random_rectangle_point(area)
|
||||
data.append(['minitouch', self.benchmark_test(self.device._click_minitouch, x, y)])
|
||||
click = data
|
||||
|
||||
logger.hr('Benchmark Results', level=1)
|
||||
if screenshot:
|
||||
self.show(test='Screenshot', data=screenshot, evaluate_func=self.evaluate_screenshot)
|
||||
if click:
|
||||
self.show(test='Click', data=click, evaluate_func=self.evaluate_click)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
b = Benchmark('alas', task='Benchmark')
|
||||
b.run()
|
@ -1,13 +1,12 @@
|
||||
from module.campaign.campaign_base import CampaignBase
|
||||
from module.daemon.assets import *
|
||||
from module.exception import *
|
||||
from module.daemon.daemon_base import DaemonBase
|
||||
from module.exception import CampaignEnd
|
||||
from module.handler.ambush import MAP_AMBUSH_EVADE
|
||||
from module.map.map_operation import MAP_PREPARATION, FLEET_PREPARATION
|
||||
|
||||
|
||||
class AzurLaneDaemon(CampaignBase):
|
||||
def daemon(self):
|
||||
self.device.disable_stuck_detection()
|
||||
|
||||
class AzurLaneDaemon(DaemonBase, CampaignBase):
|
||||
def run(self):
|
||||
while 1:
|
||||
self.device.screenshot()
|
||||
|
||||
@ -17,26 +16,23 @@ class AzurLaneDaemon(CampaignBase):
|
||||
|
||||
# Combat
|
||||
if self.combat_appear():
|
||||
# if self.handle_combat_automation_set(auto=True):
|
||||
# continue
|
||||
# self.device.click(BATTLE_PREPARATION)
|
||||
self.combat_preparation()
|
||||
try:
|
||||
if self.handle_battle_status(save_get_items=False):
|
||||
self.combat_status(save_get_items=False, expected_end='no_searching')
|
||||
if self.handle_battle_status():
|
||||
self.combat_status(expected_end='no_searching')
|
||||
continue
|
||||
except CampaignEnd:
|
||||
continue
|
||||
|
||||
# Map operation
|
||||
if self.appear_then_click(MAP_AMBUSH_EVADE):
|
||||
if self.appear_then_click(MAP_AMBUSH_EVADE, offset=(20, 20)):
|
||||
self.device.sleep(1)
|
||||
continue
|
||||
if self.appear_then_click(STRATEGY_OPEN):
|
||||
if self.handle_mystery_items():
|
||||
continue
|
||||
|
||||
# Map preparation
|
||||
if self.config.ENABLE_SEMI_MAP_PREPARATION:
|
||||
if self.config.Daemon_EnterMap:
|
||||
if self.appear_then_click(MAP_PREPARATION, offset=(20, 20), interval=2):
|
||||
continue
|
||||
if self.appear_then_click(FLEET_PREPARATION, offset=(20, 20), interval=2):
|
||||
@ -50,14 +46,25 @@ class AzurLaneDaemon(CampaignBase):
|
||||
pass
|
||||
|
||||
# Urgent commission
|
||||
if self.handle_urgent_commission(save_get_items=False):
|
||||
if self.handle_urgent_commission():
|
||||
continue
|
||||
|
||||
# Popups
|
||||
if self.handle_guild_popup_cancel():
|
||||
return True
|
||||
if self.handle_vote_popup():
|
||||
continue
|
||||
|
||||
# Story
|
||||
if self.config.ENABLE_SEMI_STORY_SKIP:
|
||||
self.story_skip()
|
||||
if self.story_skip():
|
||||
continue
|
||||
|
||||
# End
|
||||
# No end condition, stop it manually.
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
b = AzurLaneDaemon('alas', task='Daemon')
|
||||
b.run()
|
||||
|
7
module/daemon/daemon_base.py
Normal file
@ -0,0 +1,7 @@
|
||||
from module.base.base import ModuleBase
|
||||
|
||||
|
||||
class DaemonBase(ModuleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.device.disable_stuck_detection()
|
@ -1,13 +1,12 @@
|
||||
from module.exception import *
|
||||
from module.daemon.daemon_base import DaemonBase
|
||||
from module.exception import CampaignEnd
|
||||
from module.logger import logger
|
||||
from module.os_combat.combat import Combat, ContinuousCombat
|
||||
from module.os_handler.port import PortHandler, PORT_ENTER
|
||||
|
||||
|
||||
class AzurLaneDaemon(Combat, PortHandler):
|
||||
def daemon(self):
|
||||
self.device.disable_stuck_detection()
|
||||
|
||||
class AzurLaneDaemon(DaemonBase, Combat, PortHandler):
|
||||
def run(self):
|
||||
while 1:
|
||||
self.device.screenshot()
|
||||
|
||||
@ -19,41 +18,32 @@ class AzurLaneDaemon(Combat, PortHandler):
|
||||
if self.combat_appear():
|
||||
self.combat_preparation()
|
||||
try:
|
||||
if self.handle_battle_status(save_get_items=False):
|
||||
self.combat_status(save_get_items=False, expected_end='no_searching')
|
||||
if self.handle_battle_status():
|
||||
self.combat_status(expected_end='no_searching')
|
||||
continue
|
||||
except (CampaignEnd, ContinuousCombat):
|
||||
continue
|
||||
|
||||
# Map operation
|
||||
|
||||
# Map preparation
|
||||
|
||||
# Retire
|
||||
pass
|
||||
|
||||
# Emotion
|
||||
pass
|
||||
|
||||
# Urgent commission
|
||||
if self.handle_urgent_commission(save_get_items=False):
|
||||
# Map events
|
||||
if self.handle_map_event():
|
||||
continue
|
||||
|
||||
# Story
|
||||
if self.config.ENABLE_OS_SEMI_STORY_SKIP:
|
||||
self.story_skip()
|
||||
|
||||
self.handle_map_event()
|
||||
|
||||
# Port repair
|
||||
if self.config.OpsiDaemon_RepairShip:
|
||||
if self.appear(PORT_ENTER, offset=(20, 20), interval=30):
|
||||
self.port_enter()
|
||||
self.port_dock_repair()
|
||||
self.port_quit()
|
||||
self.interval_reset(PORT_ENTER)
|
||||
logger.info('Port repair finished, move your fleet out of the port in 30s to avoid repairing again')
|
||||
logger.info('Port repair finished, '
|
||||
'please move your fleet out of the port in 30s to avoid repairing again')
|
||||
|
||||
# End
|
||||
# No end condition, stop it manually.
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
b = AzurLaneDaemon('alas', task='OpsiDaemon')
|
||||
b.run()
|
||||
|
@ -112,6 +112,8 @@ class Device(Screenshot, Control, AppControl):
|
||||
"""
|
||||
Disable stuck detection and its handler. Usually uses in semi auto and debugging.
|
||||
"""
|
||||
logger.info('Disable stuck detection')
|
||||
|
||||
def empty_function(*arg, **kwargs):
|
||||
return False
|
||||
|
||||
|
@ -77,7 +77,7 @@ class Combat(Combat_, MapEventHandler):
|
||||
# self.emotion.reduce(fleet_index)
|
||||
break
|
||||
|
||||
def handle_get_items(self, save_get_items=False):
|
||||
def handle_get_items(self, drop=None):
|
||||
if self.appear(GET_ITEMS_1, offset=5, interval=self.battle_status_click_interval):
|
||||
self.device.click(CLICK_SAFE_AREA)
|
||||
self.interval_reset(BATTLE_STATUS_S)
|
||||
@ -107,8 +107,8 @@ class Combat(Combat_, MapEventHandler):
|
||||
|
||||
return self.handle_os_in_map()
|
||||
|
||||
def combat_status(self, save_get_items=False, expected_end=None):
|
||||
super().combat_status(save_get_items=False, expected_end=self._os_combat_expected_end)
|
||||
def combat_status(self, drop=None, expected_end=None):
|
||||
super().combat_status(drop=drop, expected_end=self._os_combat_expected_end)
|
||||
|
||||
def combat(self, *args, **kwargs):
|
||||
"""
|
||||
|
@ -18,3 +18,4 @@ anyio==1.3.1
|
||||
uvicorn[standard]
|
||||
aiofiles
|
||||
wrapt==1.13.1
|
||||
prettytable==2.2.1
|
@ -28,7 +28,7 @@ h11==0.12.0 # via uvicorn
|
||||
httptools==0.2.0 # via uvicorn
|
||||
idna==2.6 # via requests
|
||||
imageio==2.9.0 # via scikit-image
|
||||
importlib-metadata==4.8.1 # via click
|
||||
importlib-metadata==4.8.1 # via click, prettytable
|
||||
inflection==0.5.1 # via -r requirements-in.txt
|
||||
jellyfish==0.8.8 # via -r requirements-in.txt
|
||||
kiwisolver==1.3.2 # via matplotlib
|
||||
@ -43,6 +43,7 @@ opencv-python==4.5.3.56 # via -r requirements-in.txt
|
||||
packaging==20.9 # via deprecation, uiautomator2
|
||||
pillow==8.3.2 # via -r requirements-in.txt, cnocr, gluoncv, imageio, matplotlib, scikit-image, uiautomator2
|
||||
portalocker==2.3.2 # via gluoncv
|
||||
prettytable==2.2.1 # via -r requirements-in.txt
|
||||
progress==1.6 # via uiautomator2
|
||||
py==1.10.0 # via retry
|
||||
pyelftools==0.27 # via apkutils2
|
||||
@ -70,6 +71,7 @@ urllib3==1.22 # via requests
|
||||
user-agents==2.2.0 # via pywebio
|
||||
uvicorn[standard]==0.15.0 # via -r requirements-in.txt
|
||||
watchgod==0.7 # via uvicorn
|
||||
wcwidth==0.2.5 # via prettytable
|
||||
websockets==10.0 # via uvicorn
|
||||
whichcraft==0.6.1 # via adbutils, uiautomator2
|
||||
wrapt==1.13.1 # via -r requirements-in.txt, deprecated
|
||||
|