Skip to content

Commit 47acd3e

Browse files
authored
feat: 青春杯训练逻辑 (shiokaze#169)
* fix(install.ps1,-README.md,-requirements.txt): 更新依赖版本和安装方法 * fix(module/umamusume/asset/point.py,-module/umamusume/script/cultivate_task/info.py,-resource/umamusume/): (@maboroshi0651)同步了一部分国服更新导致的素材变动 * fix(web/src/components,-resource/umamusume/race): 同步其余国服更新素材,更新前端比赛名称 * feat(run.ps1,-check_update.ps1): 添加了自动检测更新的脚本 * feat: 可以在前端设置青春杯剧本,并且可以自动选择进入对应剧本 * Merge dev * feat(bot/server/handler.py): 强制不让浏览器获取缓存, 保证读到最新版前端页面 * feat: 青春杯训练逻辑 * feat: 前端青春杯额外配置UI * style: 优化青春杯配置展示界面 * feat: 允许青春杯配置生效 * fix: 修复了前端读取资源可能读取到缓存的问题
1 parent c81dda3 commit 47acd3e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2276
-1322
lines changed

bot/base/task.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class EndTaskReason(Enum):
3131
COMPLETE = "任务已完成"
3232
MANUAL_ABORTED = "任务被手动中止"
3333
SYSTEM_ERROR = "系统异常"
34+
SCENARIO_NOT_FOUND = "找不到育成剧本"
3435

3536

3637
class Task(metaclass=ABCMeta):

bot/recog/ocr.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
import cv2
12
import paddleocr
23
from difflib import SequenceMatcher
34
import bot.base.log as logger
5+
import time
46

57
log = logger.get_logger(__name__)
68

79
OCR_JP = paddleocr.PaddleOCR(lang="japan", show_log=False, use_angle_cls=False)
810
OCR_CH = paddleocr.PaddleOCR(lang="ch", show_log=False, use_angle_cls=False)
9-
11+
OCR_EN = paddleocr.PaddleOCR(lang="en", show_log=False, use_angle_cls=False)
1012

1113
# ocr 文字识别图片
1214
def ocr(img, lang="ch"):
@@ -26,6 +28,16 @@ def ocr_line(img, lang="ch"):
2628
text += text_info[1][0]
2729
return text
2830

31+
# ocr_digits 限制只识别数字,可以提升数字识别的准确度
32+
def ocr_digits(img):
33+
res = OCR_EN.ocr(img, cls=False)[0]
34+
# 提取所有识别结果,按置信度从高到低排序
35+
digits = [(info[1][0], info[1][1]) for info in res]
36+
if not digits:
37+
return ""
38+
# 选置信度最高的那一项
39+
best, _ = max(digits, key=lambda x: x[1])
40+
return best
2941

3042
# find_text_pos 查找目标文字在图片中的位置
3143
def find_text_pos(ocr_result, target):

bot/server/handler.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,27 @@ def stop_bot():
5151

5252
@server.get("/")
5353
async def get_index():
54-
return FileResponse('public/index.html')
54+
return FileResponse('public/index.html', headers={
55+
'Cache-Control': 'no-cache, no-store, must-revalidate',
56+
'Pragma': 'no-cache',
57+
'Expires': '0'
58+
})
5559

5660

5761
@server.get("/{whatever:path}")
5862
async def get_static_files_or_404(whatever):
5963
# try open file for path
6064
file_path = os.path.join("public", whatever)
65+
# 设置防缓存头
66+
no_cache_headers = {
67+
'Cache-Control': 'no-cache, no-store, must-revalidate',
68+
'Pragma': 'no-cache',
69+
'Expires': '0'
70+
}
71+
6172
if os.path.isfile(file_path):
6273
if file_path.endswith((".js", ".mjs")):
63-
return FileResponse(file_path, media_type="application/javascript")
74+
return FileResponse(file_path, media_type="application/javascript", headers=no_cache_headers)
6475
else:
65-
return FileResponse(file_path)
66-
return FileResponse('public/index.html')
76+
return FileResponse(file_path, headers=no_cache_headers)
77+
return FileResponse('public/index.html', headers=no_cache_headers)

module/umamusume/asset/template.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
from bot.base.resource import Template
2+
from module.umamusume.define import ScenarioType
23

34
UMAMUSUME_UI_TEMPLATE_PATH = "/umamusume/ui"
45
UMAMUSUME_BTN_TEMPLATE_PATH = "/umamusume/btn"
56
UMAMUSUME_REF_TEMPLATE_PATH = "/umamusume/ref"
67
UMAMUSUME_UMA_ICON_TEMPLATE_PATH = "/umamusume/uma_icon"
8+
UMAMUSUME_SCENARIO_TEMPLATE_PATH = "/umamusume/scenario"
9+
# 青春杯
10+
UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH = "/umamusume/ui/aoharuhai"
11+
UMAMUSUME_REF_AOHARUHAI_TEMPLATE_PATH = "/umamusume/ref/aoharuhai"
712
# 限时: 富士奇石的表演秀
813
UMAMUSUME_UI_FUJIKISEKI_SHOW_TEMPLATE_PATH = "/umamusume/ui/fujikiseki_show"
914

@@ -19,6 +24,15 @@
1924
UI_CULTIVATE_UMAMUSUME_SELECT = Template("CULTIVATE_UMAMUSUME_SELECT", UMAMUSUME_UI_TEMPLATE_PATH)
2025
UI_CULTIVATE_FINAL_CHECK = Template("CULTIVATE_FINAL_CHECK", UMAMUSUME_UI_TEMPLATE_PATH)
2126

27+
UI_SCENARIO_URA = Template("SCENARIO_URA", UMAMUSUME_SCENARIO_TEMPLATE_PATH)
28+
UI_SCENARIO_AOHARUHAI = Template("SCENARIO_AOHARUHAI", UMAMUSUME_SCENARIO_TEMPLATE_PATH)
29+
30+
UI_SCENARIO: dict[ScenarioType, Template] = {
31+
ScenarioType.SCENARIO_TYPE_UNKNOWN: None,
32+
ScenarioType.SCENARIO_TYPE_URA: UI_SCENARIO_URA,
33+
ScenarioType.SCENARIO_TYPE_AOHARUHAI: UI_SCENARIO_AOHARUHAI,
34+
}
35+
2236
UI_CULTIVATE_EVENT_UMAMUSUME = Template("CULTIVATE_EVENT_UMAMUSUME", UMAMUSUME_UI_TEMPLATE_PATH)
2337
UI_CULTIVATE_EVENT_SUPPORT_CARD = Template("CULTIVATE_EVENT_SUPPORT_CARD", UMAMUSUME_UI_TEMPLATE_PATH)
2438
UI_CULTIVATE_EVENT_SCENARIO = Template("CULTIVATE_EVENT_SCENARIO", UMAMUSUME_UI_TEMPLATE_PATH)
@@ -45,6 +59,28 @@
4559
UI_RACE_REWARD_1 = Template("RACE_REWARD_1", UMAMUSUME_UI_TEMPLATE_PATH)
4660
UI_RACE_REWARD_2 = Template("RACE_REWARD_2", UMAMUSUME_UI_TEMPLATE_PATH)
4761

62+
# 青春杯比赛
63+
UI_AOHARUHAI_RACE = Template("AOHARUHAI_RACE", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
64+
UI_AOHARUHAI_RACE_1 = Template("AOHARUHAI_RACE_1", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
65+
UI_AOHARUHAI_RACE_2 = Template("AOHARUHAI_RACE_2", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
66+
UI_AOHARUHAI_RACE_3 = Template("AOHARUHAI_RACE_3", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
67+
UI_AOHARUHAI_RACE_4 = Template("AOHARUHAI_RACE_4", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
68+
UI_AOHARUHAI_RACE_5 = Template("AOHARUHAI_RACE_5", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
69+
UI_AOHARUHAI_RACE_SELECT_OPPONENT = Template("AOHARUHAI_RACE_SELECT_OPPONENT", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
70+
UI_AOHARUHAI_RACE_FINAL_START = Template("AOHARUHAI_RACE_FINAL_START", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
71+
UI_AOHARUHAI_RACE_CONFIRM = Template("AOHARUHAI_RACE_CONFIRM", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
72+
UI_AOHARUHAI_RACE_INRACE = Template("AOHARUHAI_RACE_INRACE", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
73+
UI_AOHARUHAI_RACE_END = Template("AOHARUHAI_RACE_END", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
74+
UI_AOHARUHAI_RACE_SCHEDULE = Template("AOHARUHAI_RACE_SCHEDULE", UMAMUSUME_UI_AOHARUHAI_TEMPLATE_PATH)
75+
76+
REF_AOHARUHAI_TEAM_NAME_0 = Template("AOHARUHAI_TEAM_NAME_0", UMAMUSUME_REF_AOHARUHAI_TEMPLATE_PATH)
77+
REF_AOHARUHAI_TEAM_NAME_1 = Template("AOHARUHAI_TEAM_NAME_1", UMAMUSUME_REF_AOHARUHAI_TEMPLATE_PATH)
78+
REF_AOHARUHAI_TEAM_NAME_2 = Template("AOHARUHAI_TEAM_NAME_2", UMAMUSUME_REF_AOHARUHAI_TEMPLATE_PATH)
79+
REF_AOHARUHAI_TEAM_NAME_3 = Template("AOHARUHAI_TEAM_NAME_3", UMAMUSUME_REF_AOHARUHAI_TEMPLATE_PATH)
80+
81+
REF_AOHARUHAI_TEAM_NAME = [REF_AOHARUHAI_TEAM_NAME_0, REF_AOHARUHAI_TEAM_NAME_1,
82+
REF_AOHARUHAI_TEAM_NAME_2, REF_AOHARUHAI_TEAM_NAME_3]
83+
4884
UI_GOAL_ACHIEVED = Template("GOAL_ACHIEVED", UMAMUSUME_UI_TEMPLATE_PATH)
4985
UI_GOAL_FAILED = Template("GOAL_FAILED", UMAMUSUME_UI_TEMPLATE_PATH)
5086
UI_NEXT_GOAL = Template("NEXT_GOAL", UMAMUSUME_UI_TEMPLATE_PATH)

module/umamusume/asset/ui.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
CULTIVATE_URA_RACE_2 = UI("CULTIVATE_URA_RACE_1", [template.UI_CULTIVATE_GOAL_RACE_1, template.UI_CULTIVATE_URA_RACE_2],[])
2222
CULTIVATE_URA_RACE_3 = UI("CULTIVATE_URA_RACE_1", [template.UI_CULTIVATE_GOAL_RACE_1, template.UI_CULTIVATE_URA_RACE_3],[])
2323

24+
# 青春杯比赛
25+
AOHARUHAI_RACE = UI("AOHARUHAI_RACE", [template.UI_AOHARUHAI_RACE], [])
26+
AOHARUHAI_RACE_INRACE = UI("AOHARUHAI_RACE_INRACE", [template.UI_AOHARUHAI_RACE_INRACE], [])
27+
AOHARUHAI_RACE_END = UI("AOHARUHAI_RACE_END", [template.UI_AOHARUHAI_RACE_END], [])
28+
AOHARUHAI_RACE_SCHEDULE = UI("AOHARUHAI_RACE_SCHEDULE", [template.UI_AOHARUHAI_RACE_SCHEDULE], [])
29+
2430

2531
CULTIVATE_RACE_LIST = UI("CULTIVATE_RACE_LIST", [template.UI_CULTIVATE_RACE_LIST_1, template.UI_CULTIVATE_RACE_LIST_2], [])
2632

@@ -67,6 +73,7 @@
6773
CULTIVATE_SUPPORT_CARD_SELECT, CULTIVATE_FOLLOW_SUPPORT_CARD_SELECT, CULTIVATE_FINAL_CHECK, INFO,
6874
CULTIVATE_MAIN_MENU, CULTIVATE_TRAINING_SELECT, CULTIVATE_EXTEND, CULTIVATE_CATCH_DOLL_GAME,
6975
CULTIVATE_CATCH_DOLL_GAME_RESULT, CULTIVATE_LEVEL_RESULT,
76+
AOHARUHAI_RACE, AOHARUHAI_RACE_INRACE, AOHARUHAI_RACE_END, AOHARUHAI_RACE_SCHEDULE,
7077
CULTIVATE_GOAL_RACE, CULTIVATE_RACE_LIST, CULTIVATE_RESULT, CULTIVATE_RESULT_1, CULTIVATE_RESULT_2,
7178
CULTIVATE_LEARN_SKILL, RECEIVE_CUP,
7279
CULTIVATE_URA_RACE_1, CULTIVATE_URA_RACE_2,CULTIVATE_URA_RACE_3,

module/umamusume/context.py

Lines changed: 12 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,15 @@
11
from bot.base.context import BotContext
2+
from module.umamusume.scenario import base_scenario, ura_scenario, aoharuhai_scenario
23
from module.umamusume.task import UmamusumeTask, UmamusumeTaskType
34
from module.umamusume.define import *
5+
from module.umamusume.types import TurnInfo
46
import bot.base.log as logger
57

68
log = logger.get_logger(__name__)
7-
8-
9-
class SupportCardInfo:
10-
name: str
11-
card_type: SupportCardType
12-
favor: SupportCardFavorLevel
13-
has_event: bool
14-
15-
def __init__(self,
16-
name: str = "support_card",
17-
card_type: SupportCardType = SupportCardType.SUPPORT_CARD_TYPE_UNKNOWN,
18-
favor: SupportCardFavorLevel = SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN,
19-
has_event: bool = False):
20-
self.name = name
21-
self.card_type = card_type
22-
self.favor = favor
23-
self.has_event = has_event
24-
25-
26-
class TrainingInfo:
27-
support_card_info_list: list[SupportCardInfo]
28-
speed_incr: int
29-
stamina_incr: int
30-
power_incr: int
31-
will_incr: int
32-
intelligence_incr: int
33-
skill_point_incr: int
34-
35-
def __init__(self):
36-
self.speed_incr = 0
37-
self.stamina_incr = 0
38-
self.power_incr = 0
39-
self.will_incr = 0
40-
self.intelligence_incr = 0
41-
self.skill_point_incr = 0
42-
self.support_card_info_list = []
43-
44-
def log_training_info(self):
45-
log.info("训练结果:速度:%s, 耐力:%s, 力量:%s, 毅力:%s, 智力:%s, 技能点:%s", self.speed_incr,
46-
self.stamina_incr, self.power_incr, self.will_incr,
47-
self.intelligence_incr, self.skill_point_incr)
48-
text = "此训练附带支援卡列表:["
49-
for c in self.support_card_info_list:
50-
if c.favor != SupportCardFavorLevel.SUPPORT_CARD_FAVOR_LEVEL_UNKNOWN:
51-
text += "[支援卡名称:" + str(c.name) + "支援卡类型:" + str(c.card_type.name) + ", 支援卡羁绊阶段:" + str(c.favor.name) + "] "
52-
text += "]"
53-
log.info(text)
54-
55-
56-
class UmaAttribute:
57-
speed: int
58-
stamina: int
59-
power: int
60-
will: int
61-
intelligence: int
62-
skill_point: int
63-
64-
def __init__(self):
65-
self.speed = 0
66-
self.stamina = 0
67-
self.power = 0
68-
self.will = 0
69-
self.intelligence = 0
70-
self.skill_point = 0
71-
72-
73-
class TurnOperation:
74-
turn_operation_type: TurnOperationType
75-
turn_operation_type_replace: TurnOperationType
76-
training_type: TrainingType
77-
race_id: int
78-
79-
def __init__(self):
80-
self.turn_operation_type = TurnOperationType.TURN_OPERATION_TYPE_UNKNOWN
81-
self.turn_operation_type_replace = TurnOperationType.TURN_OPERATION_TYPE_UNKNOWN
82-
self.training_type = TrainingType.TRAINING_TYPE_UNKNOWN
83-
self.race_id = 0
84-
85-
def log_turn_operation(self):
86-
log.info("本回合执行操作:%s", self.turn_operation_type.name)
87-
log.info("本回合备选操作:%s", self.turn_operation_type_replace.name)
88-
if self.turn_operation_type == TurnOperationType.TURN_OPERATION_TYPE_TRAINING:
89-
log.info("训练类型:%s", self.training_type.name)
90-
91-
92-
class TurnInfo:
93-
date: int
94-
95-
parse_train_info_finish: bool
96-
training_info_list: list[TrainingInfo]
97-
parse_main_menu_finish: bool
98-
uma_attribute: UmaAttribute
99-
remain_stamina: int
100-
motivation_level: MotivationLevel
101-
medic_room_available: bool
102-
race_available: bool
103-
104-
turn_operation: TurnOperation | None
105-
turn_info_logged: bool
106-
turn_learn_skill_done: bool
107-
108-
def __init__(self):
109-
self.date = -1
110-
self.parse_train_info_finish = False
111-
self.training_info_list = [TrainingInfo(), TrainingInfo(), TrainingInfo(), TrainingInfo(), TrainingInfo()]
112-
self.parse_main_menu_finish = False
113-
self.uma_attribute = UmaAttribute()
114-
self.remain_stamina = -1
115-
self.motivation_level = MotivationLevel.MOTIVATION_LEVEL_UNKNOWN
116-
self.medic_room_available = False
117-
self.race_available = False
118-
self.turn_operation = None
119-
self.turn_info_logged = False
120-
self.turn_learn_skill_done = False
121-
122-
def log_turn_info(self):
123-
log.info("当前回合时间 >" + str(self.date))
124-
log.info("干劲状态 " + str(self.motivation_level.name))
125-
log.info("体力剩余" + str(self.remain_stamina))
126-
log.info("当前属性值 速度:%s, 耐力:%s, 力量:%s, 毅力:%s, 智力:%s, 技能点:%s", self.uma_attribute.speed,
127-
self.uma_attribute.stamina, self.uma_attribute.power, self.uma_attribute.will, self.uma_attribute.intelligence, self.uma_attribute.skill_point)
128-
log.info("速度训练结果:")
129-
self.training_info_list[0].log_training_info()
130-
log.info("耐力训练结果:")
131-
self.training_info_list[1].log_training_info()
132-
log.info("力量训练结果:")
133-
self.training_info_list[2].log_training_info()
134-
log.info("毅力训练结果:")
135-
self.training_info_list[3].log_training_info()
136-
log.info("智力训练结果:")
137-
self.training_info_list[4].log_training_info()
138-
139-
1409
class CultivateContextDetail:
14110
turn_info: TurnInfo | None
14211
turn_info_history: list[TurnInfo]
12+
scenario : base_scenario.BaseScenario
14313
expect_attribute: list[int] | None
14414
follow_support_card_name: str
14515
follow_support_card_level: int
@@ -198,6 +68,15 @@ def build_context(task: UmamusumeTask, ctrl) -> UmamusumeContext:
19868
ctx = UmamusumeContext(task, ctrl)
19969
if task.task_type == UmamusumeTaskType.UMAMUSUME_TASK_TYPE_CULTIVATE:
20070
detail = CultivateContextDetail()
71+
# 根据剧本类型初始化对应的继承类
72+
match task.detail.scenario:
73+
case ScenarioType.SCENARIO_TYPE_URA:
74+
detail.scenario = ura_scenario.URAScenario()
75+
case ScenarioType.SCENARIO_TYPE_AOHARUHAI:
76+
detail.scenario = aoharuhai_scenario.AoharuHaiScenario()
77+
case _: # 占位, 实际上不可能到达这里
78+
log.error("未知的场景")
79+
detail.scenario = None
20180
detail.expect_attribute = task.detail.expect_attribute
20281
detail.follow_support_card_name = task.detail.follow_support_card_name
20382
detail.follow_support_card_level = task.detail.follow_support_card_level

module/umamusume/define.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
class ScenarioType(Enum):
55
SCENARIO_TYPE_UNKNOWN = 0
66
SCENARIO_TYPE_URA = 1
7-
7+
SCENARIO_TYPE_AOHARUHAI = 2
88

99
class SupportCardType(Enum):
1010
SUPPORT_CARD_TYPE_UNKNOWN = 0

module/umamusume/manifest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
CULTIVATE_EVENT_UMAMUSUME: script_cultivate_event,
2828
CULTIVATE_EVENT_SUPPORT_CARD: script_cultivate_event,
2929
CULTIVATE_EVENT_SCENARIO: script_cultivate_event,
30+
AOHARUHAI_RACE: script_aoharuhai_race,
31+
AOHARUHAI_RACE_INRACE: script_aoharuhai_race_inrace,
32+
AOHARUHAI_RACE_END: script_aoharuhai_race_end,
33+
AOHARUHAI_RACE_SCHEDULE: script_aoharuhai_race_schedule,
3034
CULTIVATE_GOAL_RACE: script_cultivate_goal_race,
3135
CULTIVATE_RACE_LIST: script_cultivate_race_list,
3236
BEFORE_RACE: script_cultivate_before_race,

module/umamusume/scenario/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)