2828from custom import config
2929from custom .core .avatar import locate_oper
3030from custom .core .battle .action import Action , ActionType , DirectionType
31- from custom .core .battle .game_time import GameTime
3231from custom .core .geometry .convert_pos import convert_position
3332from custom .core .geometry .map_loader import load_map
3433from custom .core .geometry .view import transform_map_to_view
@@ -101,7 +100,7 @@ def _execute(self, context: Context, params: dict) -> CustomAction.RunResult:
101100 return CustomAction .RunResult (success = True )
102101
103102 def _parse_actions (self , raw : list [dict ], map_data : dict ) -> list [Action ]:
104- """解析 JSON 动作列表 → Action 对象(含投影坐标)。"""
103+ """解析 JSON 动作列表 → Action 对象(含投影坐标 + 目标帧 )。"""
105104 h , w = map_data ["height" ], map_data ["width" ]
106105 front = transform_map_to_view (map_data , side = False )
107106 side = transform_map_to_view (map_data , side = True )
@@ -113,9 +112,11 @@ def _parse_actions(self, raw: list[dict], map_data: dict) -> list[Action]:
113112 if frame is not None :
114113 cost_val = frame // config .TICK_MAX_DEFAULT
115114 tick_val = frame % config .TICK_MAX_DEFAULT
115+ target_frame = int (frame )
116116 else :
117117 cost_val = item .get ("cost" )
118118 tick_val = item .get ("tick" )
119+ target_frame = (cost_val or 0 ) * config .TICK_MAX_DEFAULT + (tick_val or 0 )
119120
120121 a = Action (
121122 cost = cost_val ,
@@ -131,6 +132,9 @@ def _parse_actions(self, raw: list[dict], map_data: dict) -> list[Action]:
131132 logger .warning ("跳过无效动作: %s" , a )
132133 continue
133134
135+ # 存储原始帧号用于计时
136+ a .target_frame = target_frame
137+
134138 # 棋盘坐标 → 格子 → 投影
135139 if a .pos :
136140 col , row = convert_position (a .pos , h , w )
@@ -159,30 +163,30 @@ def _perform_action(
159163 self , context : Context , ctrl : Controller , action : Action , ts : TimeSource , is_pc : bool
160164 ) -> None :
161165 """执行单个动作:逼近目标帧 → 子弹时间 → 逐帧 → 操作。"""
162- target = action .get_game_time ()
163- bullet_threshold = GameTime ( tick = config .BULLET_THRESHOLD )
166+ target_frame = action .target_frame
167+ bullet_threshold = config .BULLET_THRESHOLD
164168
165- # 读当前时间
166- current = self ._read_time (ctrl , ts )
169+ # 读当前累计帧
170+ current = self ._read_frames (ctrl , ts )
167171 if current is None :
168172 logger .warning ("无法读时间,直接执行" )
169- current = target
173+ current = target_frame
170174
171- logger .info ("当前 %s → 目标 %s " , current , target )
175+ logger .info ("当前帧 %d → 目标帧 %d " , current , target_frame )
172176
173- # 逼近:当前 + bullet_threshold < target → 需要逼近
174- if current + bullet_threshold < target :
175- logger .debug ("距离目标较远,等待接近" )
176- self ._wait_until (
177- ctrl , ts , target - bullet_threshold , context_tasker_stopping = lambda : False
177+ # 逼近:当前 + threshold < target → 等待
178+ if current + bullet_threshold < target_frame :
179+ logger .debug ("距离目标 %d 帧,等待" , target_frame - current )
180+ self ._wait_until_frames (
181+ ctrl , ts , target_frame - bullet_threshold , context_tasker_stopping = lambda : False
178182 )
179183
180- # 进入子弹时间(选中最后操作的干员)
184+ # 进入子弹时间
181185 self ._enter_bullet_time (ctrl , is_pc )
182186 time .sleep (config .GENERAL_WAIT_MS / 1000 )
183187
184188 # 逐帧步进到目标
185- self ._step_to_target (ctrl , ts , target , is_pc )
189+ self ._step_to_frames (ctrl , ts , target_frame , is_pc )
186190
187191 # 执行动作
188192 if action .action_type == ActionType .DEPLOY :
@@ -192,25 +196,25 @@ def _perform_action(
192196 elif action .action_type == ActionType .RETREAT :
193197 self ._retreat (ctrl , action , is_pc )
194198
195- def _read_time (self , ctrl : Controller , ts : TimeSource ) -> GameTime | None :
196- """截图 → tick → TimeSource → GameTime 。"""
199+ def _read_frames (self , ctrl : Controller , ts : TimeSource ) -> int | None :
200+ """截图 → TimeSource → 累计帧 。"""
197201 img = ctrl .post_screencap ().wait ().get ()
198202 lf = ts .update (img )
199203 if lf is None :
200204 return None
201- return GameTime ( cost = 0 , tick = lf , time = None ) # 简化:只用周期内 tick
205+ return ts . total_elapsed_frames
202206
203- def _wait_until (
204- self , ctrl : Controller , ts : TimeSource , target : GameTime , context_tasker_stopping
207+ def _wait_until_frames (
208+ self , ctrl : Controller , ts : TimeSource , target_frame : int , context_tasker_stopping
205209 ) -> None :
206- """等待直到费用条时间到达 target 。"""
207- deadline = time .time () + 120 # 2 分钟超时
210+ """等待直到累计帧到达 target_frame 。"""
211+ deadline = time .time () + 120
208212 while time .time () < deadline :
209213 if context_tasker_stopping ():
210214 return
211215 img = ctrl .post_screencap ().wait ().get ()
212216 lf = ts .update (img )
213- if lf is not None and GameTime ( tick = lf ) >= target :
217+ if lf is not None and ts . total_elapsed_frames >= target_frame :
214218 return
215219 time .sleep (0.016 )
216220
@@ -228,18 +232,18 @@ def _enter_bullet_time(self, ctrl: Controller, is_pc: bool) -> None:
228232 ).wait ()
229233 time .sleep (config .GENERAL_WAIT_MS / 1000 )
230234
231- def _step_to_target (
232- self , ctrl : Controller , ts : TimeSource , target : GameTime , is_pc : bool
235+ def _step_to_frames (
236+ self , ctrl : Controller , ts : TimeSource , target_frame : int , is_pc : bool
233237 ) -> None :
234- """逐帧步进到精确目标帧 。"""
238+ """逐帧步进到累计帧 target_frame 。"""
235239 max_steps = 60
236240 for _ in range (max_steps ):
237241 img = ctrl .post_screencap ().wait ().get ()
238242 lf = ts .update (img )
239243 if lf is None :
240244 break
241- if GameTime ( tick = lf ) >= target :
242- logger .debug ("到达目标帧 %d" , lf )
245+ if ts . total_elapsed_frames >= target_frame :
246+ logger .debug ("到达目标帧 %d" , target_frame )
243247 return
244248 self ._step_one_frame (ctrl , is_pc )
245249 time .sleep (config .GENERAL_WAIT_MS / 1000 )
0 commit comments