1
0
mirror of https://github.com/TheFunny/ArisuAutoSweeper synced 2026-06-28 04:25:04 +00:00

20 Commits

Author SHA1 Message Date
YoursFunny a621299aea fix(cafe): update assets 2023-11-12 16:12:18 +08:00
YoursFunny 1f7ed7b08c fix(cafe): remove crop as not needed 2023-11-12 16:00:48 +08:00
YoursFunny 049499d986 fix(cafe): crop template from button image 2023-11-12 15:28:54 +08:00
YoursFunny 9c68ab01e6 fix(cafe): apply mask 2023-11-11 23:45:08 +08:00
YoursFunny e1f61dac14 feat(stage): add stage list recognition 2023-11-11 23:44:08 +08:00
YoursFunny 7bc3630083 refactor(cafe): adjust crop template button 2023-11-11 17:08:30 +08:00
YoursFunny 1b83b7077f doc: add en gui pic 2023-11-10 21:47:14 +08:00
YoursFunny f1e3cd9810 feat(login): add update download confirm 2023-11-10 21:17:20 +08:00
YoursFunny f91fc2c55d feat(popup): add ap exceed and item expire handler 2023-11-10 21:17:20 +08:00
YoursFunny d82e206463 fix(tc): stick at certain status 2023-11-10 21:17:18 +08:00
YoursFunny db813c9efb fix: adapt AAS webui 2023-11-07 19:46:24 +08:00
YoursFunny 9d3b5ceff8 feat: add English webui 2023-11-07 19:43:41 +08:00
YoursFunny b83db6bc35 fix(popup): adjust daily reward recognition 2023-11-07 19:14:42 +08:00
YoursFunny 2e4a1f144b fix(popup): support another type of network reconnection 2023-11-07 19:14:01 +08:00
YoursFunny f7444e29dc doc: add gui pic 2023-11-07 14:58:55 +08:00
YoursFunny 1113094cf5 doc: adjust readme icon style 2023-11-07 14:41:05 +08:00
YoursFunny 60e6710181 doc: add readme 2023-11-07 14:22:47 +08:00
YoursFunny 9708ec05d7 fix(cafe): use correct boarder method 2023-11-06 21:24:13 +08:00
YoursFunny 77f0ded95f feat(cafe): handle unexpected popups 2023-11-05 23:19:51 +08:00
YoursFunny 937a7c63e8 fix(cafe): use smaller default pinch area 2023-11-05 23:09:46 +08:00
30 changed files with 553 additions and 213 deletions
+33
View File
@@ -0,0 +1,33 @@
<img width="150" height="150" align="left" style="float: left; margin: 0 10px 0 0;" alt="AAS icon" src="docs/resources/aas_icon.svg"/>
# ArisuAutoScript
**Blue Archive Automation Script**
**| English | [简体中文](README.md) |**
![gui_en.png](docs/resources/gui_en.png)
## Features
The script is still under active development. The following features have been implemented:
- [x] **Cafe** Claim rewards / Interact / Second cafe
- [x] **Circle** Claim AP
- [x] **Mailbox** Claim rewards
- [x] **Tactical Challenge** Claim rewards / Auto battle
_Currently only supports JP server._
## Relative projects
- [AzurLaneAutoScript](https://github.com/LmeSzinc/AzurLaneAutoScript): Azur Lane auto script
- [StarRailCopilot](https://github.com/LmeSzinc/StarRailCopilot): A bot for Honkai: Star Rail, based on the next
generation of ALAS framework.
## Acknowledgements
Thanks to [6bir](https://github.com/6bir) for the icon design.
Thanks to [Alas](https://github.com/LmeSzinc/AzurLaneAutoScript) and [SRC](https://github.com/LmeSzinc/StarRailCopilot)
for the development framework.
+32
View File
@@ -0,0 +1,32 @@
<img width="150" height="150" align="left" style="float: left; margin: 0 10px 0 0;" alt="AAS icon" src="docs/resources/aas_icon.svg"/>
# ArisuAutoScript
**蔚蓝档案自动化脚本**
**| [English](README.en.md) | 简体中文 |**
![gui_cn.png](docs/resources/gui_cn.png)
## 功能
当前脚本还在活跃开发中,已经实现的功能有:
- [x] **咖啡厅** 领取奖励 / 互动 / 第二咖啡厅
- [x] **公会** 领取体力
- [x] **邮箱** 领取奖励
- [x] **战术对抗赛** 领取奖励 / 自动战斗
_目前仅支持日服。_
## 相关项目
- [AzurLaneAutoScript](https://github.com/LmeSzinc/AzurLaneAutoScript): 碧蓝航线自动化脚本
- [StarRailCopilot](https://github.com/LmeSzinc/StarRailCopilot): 崩坏:星穹铁道脚本,基于下一代Alas框架
## 鸣谢
感谢 [6bir](https://github.com/6bir) 为本项目设计的图标。
感谢 [Alas](https://github.com/LmeSzinc/AzurLaneAutoScript) 以及 [SRC](https://github.com/LmeSzinc/StarRailCopilot)
提供的开发框架。
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

+194 -194
View File
@@ -1,94 +1,94 @@
{ {
"Menu": { "Menu": {
"Alas": { "Alas": {
"name": "Menu.Alas.name", "name": "AAS",
"help": "Menu.Alas.help" "help": ""
}, },
"Daily": { "Daily": {
"name": "Menu.Daily.name", "name": "Daily",
"help": "Menu.Daily.help" "help": ""
} }
}, },
"Task": { "Task": {
"Alas": { "Alas": {
"name": "Task.Alas.name", "name": "AAS Settings",
"help": "Task.Alas.help" "help": ""
}, },
"Restart": { "Restart": {
"name": "Task.Restart.name", "name": "Error Handling",
"help": "Task.Restart.help" "help": ""
}, },
"Cafe": { "Cafe": {
"name": "Task.Cafe.name", "name": "Cafe",
"help": "Task.Cafe.help" "help": ""
}, },
"Mail": { "Mail": {
"name": "Task.Mail.name", "name": "Mailbox",
"help": "Task.Mail.help" "help": ""
}, },
"Circle": { "Circle": {
"name": "Task.Circle.name", "name": "Circle",
"help": "Task.Circle.help" "help": ""
}, },
"TacticalChallenge": { "TacticalChallenge": {
"name": "Task.TacticalChallenge.name", "name": "Tactical Challenge",
"help": "Task.TacticalChallenge.help" "help": ""
}, },
"DataUpdate": { "DataUpdate": {
"name": "Task.DataUpdate.name", "name": "Dashboard Upd",
"help": "Task.DataUpdate.help" "help": ""
} }
}, },
"Scheduler": { "Scheduler": {
"_info": { "_info": {
"name": "Scheduler._info.name", "name": "Scheduler",
"help": "Scheduler._info.help" "help": ""
}, },
"Enable": { "Enable": {
"name": "Scheduler.Enable.name", "name": "Enable Task",
"help": "Scheduler.Enable.help", "help": "Join this task to scheduler.",
"True": "True", "True": "Enabled",
"False": "False" "False": "False"
}, },
"NextRun": { "NextRun": {
"name": "Scheduler.NextRun.name", "name": "Next Run",
"help": "Scheduler.NextRun.help" "help": "Updated automatically after completing the task to set next scheduled run, typically not manually modified\nHowever you can force immediate scheduling if you clear this text field"
}, },
"Command": { "Command": {
"name": "Scheduler.Command.name", "name": "Command",
"help": "Scheduler.Command.help" "help": ""
}, },
"ServerUpdate": { "ServerUpdate": {
"name": "Scheduler.ServerUpdate.name", "name": "Server Update",
"help": "Scheduler.ServerUpdate.help" "help": "Series of server refresh time(s) as to when this task will next run, this is automatically converted to respective time zone, generally do not need to modify"
} }
}, },
"Emulator": { "Emulator": {
"_info": { "_info": {
"name": "Emulator._info.name", "name": "Emulator Settings",
"help": "Emulator._info.help" "help": ""
}, },
"Serial": { "Serial": {
"name": "Emulator.Serial.name", "name": "Serial",
"help": "Emulator.Serial.help" "help": "Common emulator Serial can be queried in the list below\nUse \"auto\" to auto-detect emulators, but if multiple emulators are running or use emulators that do not support auto-detect, \"auto\" cannot be used and serial must be filled in manually\nDefault serial for select emulators:\n- BlueStacks 127.0.0.1:5555\n- BlueStacks4 Hyper-V use \"bluestacks4-hyperv\", \"bluestacks4-hyperv-2\" for multi instance, and so on\n- BlueStacks5 Hyper-V use \"bluestacks5-hyperv\", \"bluestacks5-hyperv-1\" for multi instance, and so on\n- NoxPlayer 127.0.0.1:62001\n- NoxPlayer64bit 127.0.0.1:59865\n- MuMuPlayer/MuMuPlayer X 127.0.0.1:7555\n- MuMuPlayer12 127.0.0.1:16384\n- MemuPlayer 127.0.0.1:21503\n- LDPlayer emulator-5554 or 127.0.0.1:5555\n- WSA use \"wsa-0\" to make the game run in the background, which needs to be controlled or closed by third-party software\nIf there are multiple emulator instances running, the default is reserved for one of them and the others will use different serials to avoid conflicts\nOpen console.bat and run `adb devices` to find them or follow the emulator's official tutorial"
}, },
"PackageName": { "PackageName": {
"name": "Emulator.PackageName.name", "name": "Game Server",
"help": "Emulator.PackageName.help", "help": "Can't distinguish different regions of oversea servers, please select the server manually.",
"auto": "auto", "auto": "Auto-detect",
"JP-Official": "JP-Official" "JP-Official": "[JP]-Official"
}, },
"GameLanguage": { "GameLanguage": {
"name": "Emulator.GameLanguage.name", "name": "In-game Text Language",
"help": "Emulator.GameLanguage.help", "help": "Currently, only Simplified Chinese and English are supported. Please set the text language in game to one of them.",
"auto": "auto", "auto": "Auto-detect",
"jp": "jp" "jp": "Japanese"
}, },
"ScreenshotMethod": { "ScreenshotMethod": {
"name": "Emulator.ScreenshotMethod.name", "name": "Screenshot Method",
"help": "Emulator.ScreenshotMethod.help", "help": "When using auto-select, a benchmark will be performed and automatically changed to the fastest screenshot method.\nGeneral speed: DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB.\nRun Tools - Performance Test to find the fastest method.",
"auto": "auto", "auto": "Auto-select the fastest",
"ADB": "ADB", "ADB": "ADB ",
"ADB_nc": "ADB_nc", "ADB_nc": "ADB_nc",
"uiautomator2": "uiautomator2", "uiautomator2": "uiautomator2",
"aScreenCap": "aScreenCap", "aScreenCap": "aScreenCap",
@@ -98,127 +98,127 @@
"scrcpy": "scrcpy" "scrcpy": "scrcpy"
}, },
"ControlMethod": { "ControlMethod": {
"name": "Emulator.ControlMethod.name", "name": "Control Method",
"help": "Emulator.ControlMethod.help", "help": "Speed: MaaTouch = minitouch >>> uiautomator2 ~= ADB\nMaaTouch is recommended",
"minitouch": "minitouch", "minitouch": "minitouch",
"MaaTouch": "MaaTouch" "MaaTouch": "MaaTouch"
}, },
"AdbRestart": { "AdbRestart": {
"name": "Emulator.AdbRestart.name", "name": "Try to restart adb when no device found",
"help": "Emulator.AdbRestart.help" "help": ""
} }
}, },
"EmulatorInfo": { "EmulatorInfo": {
"_info": { "_info": {
"name": "EmulatorInfo._info.name", "name": "Emulator Settings",
"help": "EmulatorInfo._info.help" "help": "The following values are auto-filled according to \"Serial\", if you dont understand, please don't modify them"
}, },
"Emulator": { "Emulator": {
"name": "EmulatorInfo.Emulator.name", "name": "Emulator Type",
"help": "EmulatorInfo.Emulator.help", "help": "",
"auto": "auto", "auto": "Auto-detect",
"NoxPlayer": "NoxPlayer", "NoxPlayer": "Nox Player",
"NoxPlayer64": "NoxPlayer64", "NoxPlayer64": "Nox Player 64bit",
"BlueStacks4": "BlueStacks4", "BlueStacks4": "BlueStacks 4",
"BlueStacks5": "BlueStacks5", "BlueStacks5": "BlueStacks 5",
"BlueStacks4HyperV": "BlueStacks4HyperV", "BlueStacks4HyperV": "BlueStacks 4 Hyper-V",
"BlueStacks5HyperV": "BlueStacks5HyperV", "BlueStacks5HyperV": "BlueStacks 5 Hyper-V",
"LDPlayer3": "LDPlayer3", "LDPlayer3": "LD Player 3",
"LDPlayer4": "LDPlayer4", "LDPlayer4": "LD Player 4",
"LDPlayer9": "LDPlayer9", "LDPlayer9": "LD Player 9",
"MuMuPlayer": "MuMuPlayer", "MuMuPlayer": "MuMu Player",
"MuMuPlayerX": "MuMuPlayerX", "MuMuPlayerX": "MuMu Player X",
"MuMuPlayer12": "MuMuPlayer12", "MuMuPlayer12": "MuMu Player 12",
"MEmuPlayer": "MEmuPlayer" "MEmuPlayer": "MEmu Player"
}, },
"name": { "name": {
"name": "EmulatorInfo.name.name", "name": "Emulator Instance Name",
"help": "EmulatorInfo.name.help" "help": ""
}, },
"path": { "path": {
"name": "EmulatorInfo.path.name", "name": "Emulator Installation Path",
"help": "EmulatorInfo.path.help" "help": ""
} }
}, },
"Error": { "Error": {
"_info": { "_info": {
"name": "Error._info.name", "name": "Debug Settings",
"help": "Error._info.help" "help": ""
}, },
"Restart": { "Restart": {
"name": "Error.Restart.name", "name": "Restart Game on Error",
"help": "Error.Restart.help", "help": "",
"game": "game", "game": "Restart game",
"game_emulator": "game_emulator" "game_emulator": "Restart emulator and game"
}, },
"SaveError": { "SaveError": {
"name": "Error.SaveError.name", "name": "Record Exception",
"help": "Error.SaveError.help" "help": "Records exception and log into directory for review or sharing"
}, },
"ScreenshotLength": { "ScreenshotLength": {
"name": "Error.ScreenshotLength.name", "name": "Record Screenshot(s)",
"help": "Error.ScreenshotLength.help" "help": "Number of screenshots saved when exception occurs"
}, },
"OnePushConfig": { "OnePushConfig": {
"name": "Error.OnePushConfig.name", "name": "Error notify config",
"help": "Error.OnePushConfig.help" "help": "When AAS cannot handle exception, send a message through Onepush. Configuration document: \nhttps://github.com/LmeSzinc/AzurLaneAutoScript/wiki/Onepush-configuration-%5BEN%5D"
} }
}, },
"Optimization": { "Optimization": {
"_info": { "_info": {
"name": "Optimization._info.name", "name": "Optimization Settings",
"help": "Optimization._info.help" "help": ""
}, },
"ScreenshotInterval": { "ScreenshotInterval": {
"name": "Optimization.ScreenshotInterval.name", "name": "Take Screenshots Every X Second(s)",
"help": "Optimization.ScreenshotInterval.help" "help": "Minimum interval between 2 screenshots, limited in 0.1 ~ 0.3, can help reduce CPU on high-end PCs"
}, },
"CombatScreenshotInterval": { "CombatScreenshotInterval": {
"name": "Optimization.CombatScreenshotInterval.name", "name": "Take Screenshots Every X Second(s) In Combat",
"help": "Optimization.CombatScreenshotInterval.help" "help": "Minimum interval between 2 screenshots, limited in 0.1 ~ 1.0, can help reduce CPU during battle"
}, },
"WhenTaskQueueEmpty": { "WhenTaskQueueEmpty": {
"name": "Optimization.WhenTaskQueueEmpty.name", "name": "When Task Queue is Empty",
"help": "Optimization.WhenTaskQueueEmpty.help", "help": "Close AL when there are no pending tasks, can help reduce CPU",
"stay_there": "stay_there", "stay_there": "Stay There",
"goto_main": "goto_main", "goto_main": "Goto Main Page",
"close_game": "close_game" "close_game": "Close Game"
} }
}, },
"Cafe": { "Cafe": {
"_info": { "_info": {
"name": "Cafe._info.name", "name": "Cafe Settings",
"help": "Cafe._info.help" "help": ""
}, },
"Reward": { "Reward": {
"name": "Cafe.Reward.name", "name": "Claim Reward",
"help": "Cafe.Reward.help" "help": ""
}, },
"Touch": { "Touch": {
"name": "Cafe.Touch.name", "name": "Student Interaction",
"help": "Cafe.Touch.help" "help": "Auto detect intractable student and click"
}, },
"AutoAdjust": { "AutoAdjust": {
"name": "Cafe.AutoAdjust.name", "name": "Interface Auto Adjustment",
"help": "Cafe.AutoAdjust.help" "help": "Auto adjust cafe interface for better student interaction"
}, },
"SecondCafe": { "SecondCafe": {
"name": "Cafe.SecondCafe.name", "name": "Second Cafe",
"help": "Cafe.SecondCafe.help" "help": "Enable auto switch to second cafe and perform interaction"
} }
}, },
"TacticalChallenge": { "TacticalChallenge": {
"_info": { "_info": {
"name": "TacticalChallenge._info.name", "name": "Tactical Challenge Settings",
"help": "TacticalChallenge._info.help" "help": ""
}, },
"PlayerSelect": { "PlayerSelect": {
"name": "TacticalChallenge.PlayerSelect.name", "name": "Select Player",
"help": "TacticalChallenge.PlayerSelect.help", "help": "",
"0": "0", "0": "Random",
"1": "1", "1": "First",
"2": "2", "2": "Second",
"3": "3" "3": "Third"
} }
}, },
"ItemStorage": { "ItemStorage": {
@@ -227,118 +227,118 @@
"help": "ItemStorage._info.help" "help": "ItemStorage._info.help"
}, },
"AP": { "AP": {
"name": "ItemStorage.AP.name", "name": "AP",
"help": "ItemStorage.AP.help" "help": ""
}, },
"Credit": { "Credit": {
"name": "ItemStorage.Credit.name", "name": "Credit",
"help": "ItemStorage.Credit.help" "help": ""
}, },
"Pyroxene": { "Pyroxene": {
"name": "ItemStorage.Pyroxene.name", "name": "Pyroxene",
"help": "ItemStorage.Pyroxene.help" "help": ""
} }
}, },
"Gui": { "Gui": {
"Aside": { "Aside": {
"Install": "Gui.Aside.Install", "Install": "Install",
"Home": "Gui.Aside.Home", "Home": "Home",
"Develop": "Gui.Aside.Develop", "Develop": "Develop",
"Performance": "Gui.Aside.Performance", "Performance": "Perf.",
"Setting": "Gui.Aside.Setting", "Setting": "Settings",
"AddAlas": "Gui.Aside.AddAlas" "AddAlas": "Add"
}, },
"Button": { "Button": {
"Start": "Gui.Button.Start", "Start": "Start",
"Stop": "Gui.Button.Stop", "Stop": "Stop",
"ScrollON": "Gui.Button.ScrollON", "ScrollON": "Auto Scroll ON",
"ScrollOFF": "Gui.Button.ScrollOFF", "ScrollOFF": "Auto Scroll OFF",
"ClearLog": "Gui.Button.ClearLog", "ClearLog": "Clear Log",
"Setting": "Gui.Button.Setting", "Setting": "Setting",
"CheckUpdate": "Gui.Button.CheckUpdate", "CheckUpdate": "Check update",
"ClickToUpdate": "Gui.Button.ClickToUpdate", "ClickToUpdate": "Click to update",
"RetryUpdate": "Gui.Button.RetryUpdate", "RetryUpdate": "Retry update",
"CancelUpdate": "Gui.Button.CancelUpdate" "CancelUpdate": "Cancel update"
}, },
"Toast": { "Toast": {
"DisableTranslateMode": "Gui.Toast.DisableTranslateMode", "DisableTranslateMode": "Click here to disable translate mode",
"ConfigSaved": "Gui.Toast.ConfigSaved", "ConfigSaved": "Config saved",
"AlasIsRunning": "Gui.Toast.AlasIsRunning", "AlasIsRunning": "Scheduler is already running",
"ClickToUpdate": "Gui.Toast.ClickToUpdate" "ClickToUpdate": "New update available, click here to update"
}, },
"Status": { "Status": {
"Running": "Gui.Status.Running", "Running": "Running",
"Inactive": "Gui.Status.Inactive", "Inactive": "Inactive",
"Warning": "Gui.Status.Warning", "Warning": "Warning",
"Updating": "Gui.Status.Updating" "Updating": "Waiting Update"
}, },
"MenuAlas": { "MenuAlas": {
"Overview": "Gui.MenuAlas.Overview", "Overview": "Overview",
"Log": "Gui.MenuAlas.Log" "Log": "Logs"
}, },
"MenuDevelop": { "MenuDevelop": {
"HomePage": "Gui.MenuDevelop.HomePage", "HomePage": "Home",
"Translate": "Gui.MenuDevelop.Translate", "Translate": "Translate",
"Update": "Gui.MenuDevelop.Update", "Update": "Updater",
"Remote": "Gui.MenuDevelop.Remote", "Remote": "Remote access",
"Utils": "Gui.MenuDevelop.Utils" "Utils": "Utils"
}, },
"Overview": { "Overview": {
"Scheduler": "Gui.Overview.Scheduler", "Scheduler": "Scheduler",
"Log": "Gui.Overview.Log", "Log": "Log",
"Running": "Gui.Overview.Running", "Running": "Running",
"Pending": "Gui.Overview.Pending", "Pending": "Pending",
"Waiting": "Gui.Overview.Waiting", "Waiting": "Waiting",
"NoTask": "Gui.Overview.NoTask" "NoTask": "No Task"
}, },
"Dashboard": { "Dashboard": {
"NoData": "Gui.Dashboard.NoData", "NoData": "no data",
"TimeError": "Gui.Dashboard.TimeError", "TimeError": "time error",
"JustNow": "Gui.Dashboard.JustNow", "JustNow": "just now",
"MinutesAgo": "Gui.Dashboard.MinutesAgo", "MinutesAgo": "{time}min ago",
"HoursAgo": "Gui.Dashboard.HoursAgo", "HoursAgo": "{time}h ago",
"DaysAgo": "Gui.Dashboard.DaysAgo", "DaysAgo": "{time}d ago",
"LongTimeAgo": "Gui.Dashboard.LongTimeAgo" "LongTimeAgo": "long time ago"
}, },
"AddAlas": { "AddAlas": {
"PopupTitle": "Gui.AddAlas.PopupTitle", "PopupTitle": "Add new config",
"NewName": "Gui.AddAlas.NewName", "NewName": "New name",
"CopyFrom": "Gui.AddAlas.CopyFrom", "CopyFrom": "Copy from existing config",
"Confirm": "Gui.AddAlas.Confirm", "Confirm": "Add",
"FileExist": "Gui.AddAlas.FileExist", "FileExist": "A config with the same name exists, please choose another one",
"InvalidChar": "Gui.AddAlas.InvalidChar", "InvalidChar": "Config name cannot contain any of the following characters: .\\/:*?\"<>|",
"InvalidPrefixTemplate": "Gui.AddAlas.InvalidPrefixTemplate" "InvalidPrefixTemplate": "Config name cannot start with 'template'"
}, },
"Update": { "Update": {
"UpToDate": "Gui.Update.UpToDate", "UpToDate": "Latest version",
"HaveUpdate": "Gui.Update.HaveUpdate", "HaveUpdate": "A new version is available",
"UpdateStart": "Gui.Update.UpdateStart", "UpdateStart": "Start update",
"UpdateWait": "Gui.Update.UpdateWait", "UpdateWait": "Waiting for all AAS complete current task",
"UpdateRun": "Gui.Update.UpdateRun", "UpdateRun": "Updating",
"UpdateSuccess": "Gui.Update.UpdateSuccess", "UpdateSuccess": "Update succeeded, restarting",
"UpdateFailed": "Gui.Update.UpdateFailed", "UpdateFailed": "Update failed. Logs can be found in ./log/*_gui.txt",
"UpdateChecking": "Gui.Update.UpdateChecking", "UpdateChecking": "Checking for updates",
"UpdateCancel": "Gui.Update.UpdateCancel", "UpdateCancel": "Update canceled, restarting AAS",
"UpdateFinish": "Gui.Update.UpdateFinish", "UpdateFinish": "Update succeeded, please restart manually",
"Local": "Gui.Update.Local", "Local": "Local",
"Upstream": "Gui.Update.Upstream", "Upstream": "Upstream",
"Author": "Gui.Update.Author", "Author": "Author",
"Time": "Gui.Update.Time", "Time": "Commit time",
"Message": "Gui.Update.Message", "Message": "Commit message",
"DisabledWarn": "Gui.Update.DisabledWarn", "DisabledWarn": "Updater module is disabled. You need to manually restart AAS to update",
"DetailedHistory": "Gui.Update.DetailedHistory" "DetailedHistory": "Detailed Commit History"
}, },
"Remote": { "Remote": {
"Running": "Gui.Remote.Running", "Running": "Remote access on",
"NotRunning": "Gui.Remote.NotRunning", "NotRunning": "Not running, server disconnected or offline",
"NotEnable": "Gui.Remote.NotEnable", "NotEnable": "Disabled, set webui password in deploy.yaml and enable remote access",
"EntryPoint": "Gui.Remote.EntryPoint", "EntryPoint": "Entry point:",
"ConfigureHint": "Gui.Remote.ConfigureHint", "ConfigureHint": "Configuration tutorial:",
"SSHNotInstall": "Gui.Remote.SSHNotInstall" "SSHNotInstall": "No SSH command in your system. Please refer to the tutorial to download or install one"
}, },
"Text": { "Text": {
"InvalidFeedBack": "Gui.Text.InvalidFeedBack", "InvalidFeedBack": "Invalid format. Example: {0}",
"Clear": "Gui.Text.Clear" "Clear": "Clear"
} }
} }
} }
+3 -3
View File
@@ -313,19 +313,19 @@
"UpToDate": "已是最新版本", "UpToDate": "已是最新版本",
"HaveUpdate": "有新版本可用", "HaveUpdate": "有新版本可用",
"UpdateStart": "开始更新", "UpdateStart": "开始更新",
"UpdateWait": "等待所有 Alas 完成当前任务", "UpdateWait": "等待所有 AAS 完成当前任务",
"UpdateRun": "更新中", "UpdateRun": "更新中",
"UpdateSuccess": "更新成功,正在重启", "UpdateSuccess": "更新成功,正在重启",
"UpdateFailed": "更新失败,可在./log/*_gui.txt中找到错误日志", "UpdateFailed": "更新失败,可在./log/*_gui.txt中找到错误日志",
"UpdateChecking": "检查更新中", "UpdateChecking": "检查更新中",
"UpdateCancel": "取消更新,重启 Alas 中", "UpdateCancel": "取消更新,重启 AAS 中",
"UpdateFinish": "更新成功,请手动重启", "UpdateFinish": "更新成功,请手动重启",
"Local": "本地", "Local": "本地",
"Upstream": "上游仓库", "Upstream": "上游仓库",
"Author": "作者", "Author": "作者",
"Time": "提交时间", "Time": "提交时间",
"Message": "提交信息", "Message": "提交信息",
"DisabledWarn": "更新模块未启用,你需要手动重启 Alas 进行更新", "DisabledWarn": "更新模块未启用,你需要手动重启 AAS 进行更新",
"DetailedHistory": "详细提交历史" "DetailedHistory": "详细提交历史"
}, },
"Remote": { "Remote": {
+1 -1
View File
@@ -172,7 +172,7 @@ class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
self.click(ClickButton(button=area_offset(point_random, p2), name=name)) self.click(ClickButton(button=area_offset(point_random, p2), name=name))
# just used in cafe # just used in cafe
def pinch(self, box=(33, 130, 1247, 569), name='PINCH'): def pinch(self, box=(35, 130, 1250, 560), name='PINCH'):
self.handle_control_check(name) self.handle_control_check(name)
middle_point = (box[0] + box[2]) // 2, (box[1] + box[3]) // 2 middle_point = (box[0] + box[2]) // 2, (box[1] + box[3]) // 2
width = box[2] - middle_point[0] width = box[2] - middle_point[0]
+181
View File
@@ -0,0 +1,181 @@
import cv2
import numpy as np
from module.base.base import ModuleBase
from module.base.button import ButtonWrapper, ClickButton
from module.base.timer import Timer
from module.base.utils import area_pad, area_size, area_offset, random_rectangle_vector_opted
from module.logger import logger
from module.ocr.ocr import Ocr
class StageList:
drag_vector_range = (0.65, 0.85)
def __init__(
self,
name,
area_stage: ButtonWrapper,
area_index: ButtonWrapper,
area_item: ButtonWrapper,
button_enter: ButtonWrapper,
drag_direction: str = "down"
):
self.name = name
self.stage = area_stage
self.index_ocr = Ocr(area_index, lang='en')
self.stage_item = area_item.button
self.enter = button_enter
self.drag_direction = drag_direction
self.current_index_min = 1
self.current_index_max = 1
self.current_indexes = []
def __str__(self):
return f'StageList({self.name})'
__repr__ = __str__
def __eq__(self, other):
return str(self) == str(other)
def __hash__(self):
return hash(self.name)
def _get_indexes(self) -> list[int]:
return list(map(lambda x: int(x.ocr_text), self.current_indexes))
def load_stage_indexes(self, main: ModuleBase):
self.current_indexes = list(
filter(lambda x: x.ocr_text.isdigit(), self.index_ocr.detect_and_ocr(main.device.image))
)
if not self.current_indexes:
logger.warning(f'No valid index in {self.index_ocr.name}')
return
indexes = self._get_indexes()
self.current_index_min = min(indexes)
self.current_index_max = max(indexes)
logger.attr(self.index_ocr.name, f'Index range: {self.current_index_min} - {self.current_index_max}')
def drag_page(self, direction: str, main: ModuleBase, vector_range=None, reverse=False):
"""
Args:
direction: up, down
main:
vector_range (tuple[float, float]):
reverse (bool):
"""
if vector_range is None:
vector_range = self.drag_vector_range
vector = np.random.uniform(*vector_range)
width, height = area_size(self.stage.button)
if direction == 'up':
vector = (0, vector * height)
elif direction == 'down':
vector = (0, -vector * height)
else:
logger.warning(f'Unknown drag direction: {direction}')
return
if reverse:
vector = (-vector[0], -vector[1])
p1, p2 = random_rectangle_vector_opted(vector, box=self.stage.button)
main.device.drag(p1, p2, name=f'{self.name}_DRAG')
def insight_index(self, index: int, main: ModuleBase, skip_first_screenshot=True) -> bool:
"""
Args:
index:
main:
skip_first_screenshot:
Returns:
If success
"""
logger.info(f'Insight index: {index}')
last_indexes: set[int] = set()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
main.device.screenshot()
self.load_stage_indexes(main=main)
if self.current_index_min <= index <= self.current_index_max:
break
if index < self.current_index_min:
self.drag_page(self.drag_direction, main, reverse=True)
elif index > self.current_index_max:
self.drag_page(self.drag_direction, main)
main.wait_until_stable(
self.stage.button,
timer=Timer(0, 0),
timeout=Timer(1.5, 5)
)
indexes = self._get_indexes()
if indexes and last_indexes == set(indexes):
logger.warning(f'No more index {index}')
return False
last_indexes = set(indexes)
return True
@staticmethod
def _match_clickable_points(image, template, threshold=0.85):
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(res >= threshold)
return [point for point in zip(*loc[::-1])]
def select_index_enter(
self,
index: int,
main: ModuleBase,
insight: bool = True,
skip_first_screenshot: bool = True,
interval: int = 5
) -> bool:
if insight and not self.insight_index(index, main, skip_first_screenshot):
return False
logger.info(f'Select index: {index}')
click_interval = Timer(interval)
load_index_interval = Timer(1)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
main.device.screenshot()
if load_index_interval.reached_and_reset():
self.load_stage_indexes(main=main)
index_box = next(filter(lambda x: int(x.ocr_text) == index, self.current_indexes), None)
if index_box is None:
logger.warning(f'No index {index} in {self.index_ocr.name}')
return False
stage_item_box = area_pad((0, 0, *area_size(self.stage_item)))
search_box = area_offset(stage_item_box, index_box.box[:2])
search_image = main.image_crop(search_box)
points = self._match_clickable_points(search_image, self.enter.matched_button.image)
if not points:
logger.warning(f'No clickable {self.enter.name}')
return False
point = area_offset((0, 0, *area_size(self.enter.button)), points[0])
click_button = ClickButton(area_offset(point, search_box[:2]), name=self.enter.name)
if click_interval.reached_and_reset():
main.device.click(click_button)
return True
+33 -3
View File
@@ -13,6 +13,16 @@ AFFECTION_LEVEL_UP = ButtonWrapper(
button=(882, 244, 1176, 476), button=(882, 244, 1176, 476),
), ),
) )
AP_EXCEED = ButtonWrapper(
name='AP_EXCEED',
jp=Button(
file='./assets/jp/base/popup/AP_EXCEED.png',
area=(610, 124, 669, 153),
search=(590, 104, 689, 173),
color=(139, 153, 168),
button=(535, 494, 746, 565),
),
)
DAILY_NEWS = ButtonWrapper( DAILY_NEWS = ButtonWrapper(
name='DAILY_NEWS', name='DAILY_NEWS',
jp=Button( jp=Button(
@@ -27,9 +37,9 @@ DAILY_REWARD = ButtonWrapper(
name='DAILY_REWARD', name='DAILY_REWARD',
jp=Button( jp=Button(
file='./assets/jp/base/popup/DAILY_REWARD.png', file='./assets/jp/base/popup/DAILY_REWARD.png',
area=(854, 117, 1008, 165), area=(416, 165, 434, 216),
search=(834, 97, 1028, 185), search=(396, 145, 454, 236),
color=(178, 167, 112), color=(203, 227, 237),
button=(920, 632, 1140, 712), button=(920, 632, 1140, 712),
), ),
) )
@@ -63,6 +73,16 @@ GET_REWARD_SKIP = ButtonWrapper(
button=(1137, 34, 1243, 65), button=(1137, 34, 1243, 65),
), ),
) )
ITEM_EXPIRED = ButtonWrapper(
name='ITEM_EXPIRED',
jp=Button(
file='./assets/jp/base/popup/ITEM_EXPIRED.png',
area=(612, 147, 668, 175),
search=(592, 127, 688, 195),
color=(131, 145, 162),
button=(537, 487, 742, 553),
),
)
NETWORK_RECONNECT = ButtonWrapper( NETWORK_RECONNECT = ButtonWrapper(
name='NETWORK_RECONNECT', name='NETWORK_RECONNECT',
jp=Button( jp=Button(
@@ -73,3 +93,13 @@ NETWORK_RECONNECT = ButtonWrapper(
button=(663, 467, 870, 537), button=(663, 467, 870, 537),
), ),
) )
NETWORK_RECONNECT_OK = ButtonWrapper(
name='NETWORK_RECONNECT_OK',
jp=Button(
file='./assets/jp/base/popup/NETWORK_RECONNECT_OK.png',
area=(744, 487, 791, 515),
search=(724, 467, 811, 535),
color=(91, 165, 196),
button=(665, 468, 870, 536),
),
)
+14
View File
@@ -65,6 +65,8 @@ class PopupHandler(ModuleBase):
def handle_network_reconnect(self, interval=5) -> bool: def handle_network_reconnect(self, interval=5) -> bool:
if self.appear_then_click(NETWORK_RECONNECT, interval=interval): if self.appear_then_click(NETWORK_RECONNECT, interval=interval):
return True return True
if self.appear_then_click(NETWORK_RECONNECT_OK, interval=interval):
return True
return False return False
@@ -85,3 +87,15 @@ class PopupHandler(ModuleBase):
return True return True
return False return False
def handle_ap_exceed(self, interval=5) -> bool:
if self.appear_then_click(AP_EXCEED, interval=interval):
return True
return False
def handle_item_expired(self, interval=5) -> bool:
if self.appear_then_click(ITEM_EXPIRED, interval=interval):
return True
return False
+4
View File
@@ -343,6 +343,10 @@ class UI(MainPage):
return True return True
if self.handle_new_student(): if self.handle_new_student():
return True return True
if self.handle_ap_exceed():
return True
if self.handle_item_expired():
return True
return False return False
+24 -4
View File
@@ -67,10 +67,10 @@ CLICKABLE_TEMPLATE = ButtonWrapper(
name='CLICKABLE_TEMPLATE', name='CLICKABLE_TEMPLATE',
jp=Button( jp=Button(
file='./assets/jp/cafe/CLICKABLE_TEMPLATE.png', file='./assets/jp/cafe/CLICKABLE_TEMPLATE.png',
area=(0, 0, 42, 56), area=(619, 332, 660, 387),
search=(0, 0, 62, 76), search=(599, 312, 680, 407),
color=(77, 63, 1), color=(79, 65, 1),
button=(0, 0, 42, 56), button=(619, 332, 660, 387),
), ),
) )
GET_REWARD = ButtonWrapper( GET_REWARD = ButtonWrapper(
@@ -103,6 +103,26 @@ GOT_REWARD = ButtonWrapper(
button=(561, 501, 718, 556), button=(561, 501, 718, 556),
), ),
) )
INVENTORY = ButtonWrapper(
name='INVENTORY',
jp=Button(
file='./assets/jp/cafe/INVENTORY.png',
area=(553, 94, 725, 122),
search=(533, 74, 745, 142),
color=(198, 205, 213),
button=(1130, 94, 1156, 120),
),
)
MOMOTALK_CLOSE = ButtonWrapper(
name='MOMOTALK_CLOSE',
jp=Button(
file='./assets/jp/cafe/MOMOTALK_CLOSE.png',
area=(824, 82, 850, 108),
search=(804, 62, 870, 128),
color=(252, 182, 194),
button=(824, 82, 850, 108),
),
)
OCR_CAFE = ButtonWrapper( OCR_CAFE = ButtonWrapper(
name='OCR_CAFE', name='OCR_CAFE',
jp=Button( jp=Button(
+12 -4
View File
@@ -63,15 +63,16 @@ class Cafe(UI):
def _match_clickable_points(self, image, threshold=0.8): def _match_clickable_points(self, image, threshold=0.8):
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
template = self.btn.matched_button.image template = cv2.cvtColor(self.btn.matched_button.image, cv2.COLOR_BGR2GRAY)
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED) res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(res >= threshold) loc = np.where(res >= threshold)
return [point for point in zip(*loc[::-1])] return [point for point in zip(*loc[::-1])]
def _get_clickable_buttons(self, threshold=0.8, offset=(0, 0)): def _get_clickable_buttons(self, threshold=0.8, offset=(0, 0)):
image = cv2.copyMakeBorder(self.device.image, 20, 20, 10, 80, cv2.BORDER_CONSTANT, value=(0, 0, 0)) image = self.device.image
h, w = image.shape[:2]
image = cv2.rectangle(image, (0, 10), (w - 25, h - 10), (0, 0, 0), 50)
image = self._extract_clickable_from_image(image) image = self._extract_clickable_from_image(image)
points = self._match_clickable_points(image, threshold) points = self._match_clickable_points(image, threshold)
points = self.merge_points(points) points = self.merge_points(points)
@@ -120,6 +121,13 @@ class Cafe(UI):
logger.attr('Reward', num) logger.attr('Reward', num)
return num return num
def _cafe_additional(self) -> bool:
if self.appear_then_click(INVENTORY):
return True
if self.appear_then_click(MOMOTALK_CLOSE):
return True
return False
def _handle_cafe(self, status): def _handle_cafe(self, status):
match status: match status:
case CafeStatus.STUDENT_LIST: case CafeStatus.STUDENT_LIST:
@@ -206,7 +214,7 @@ class Cafe(UI):
self.device.screenshot() self.device.screenshot()
if self.ui_additional(): if self.ui_additional() or self._cafe_additional():
continue continue
if not loading_timer.reached(): if not loading_timer.reached():
+10
View File
@@ -23,3 +23,13 @@ LOGIN_LOADING = ButtonWrapper(
button=(34, 682, 60, 707), button=(34, 682, 60, 707),
), ),
) )
UPDATE = ButtonWrapper(
name='UPDATE',
jp=Button(
file='./assets/jp/login/UPDATE.png',
area=(526, 87, 756, 117),
search=(506, 67, 776, 137),
color=(183, 192, 201),
button=(666, 527, 872, 595),
),
)
+3 -2
View File
@@ -3,8 +3,7 @@ from module.exception import GameNotRunningError
from module.logger import logger from module.logger import logger
from tasks.base.page import page_main from tasks.base.page import page_main
from tasks.base.ui import UI from tasks.base.ui import UI
# from tasks.login.assets.assets_login import LOGIN_CONFIRM, USER_AGREEMENT_ACCEPT, LOGIN_LOADING from tasks.login.assets.assets_login import LOGIN_CONFIRM, LOGIN_LOADING, UPDATE
from tasks.login.assets.assets_login import LOGIN_CONFIRM, LOGIN_LOADING
class Login(UI): class Login(UI):
@@ -77,6 +76,8 @@ class Login(UI):
# continue # continue
# if self.handle_popup_confirm(): # if self.handle_popup_confirm():
# continue # continue
if self.appear_then_click(UPDATE):
continue
if self.ui_additional(): if self.ui_additional():
continue continue
@@ -116,8 +116,8 @@ class TacticalChallenge(UI):
if self.appear_then_click(CHALLENGE_LOSE): if self.appear_then_click(CHALLENGE_LOSE):
return TCStatus.LOSE return TCStatus.LOSE
case TCStatus.WIN | TCStatus.LOSE: case TCStatus.WIN | TCStatus.LOSE:
if self.appear(CHALLENGE_WIN) or self.appear(CHALLENGE_LOSE): if self.appear_then_click(CHALLENGE_WIN) or self.appear_then_click(CHALLENGE_LOSE):
return TCStatus.RESULT return status
is_valid, ticket = self._get_ticket() is_valid, ticket = self._get_ticket()
if not is_valid: if not is_valid:
return status return status