@@ -146,8 +146,36 @@ def _stage(
146146 from gamedev_shared .progress import emit_progress
147147
148148 profiler_tool = name .replace ("-" , "_" )
149- if item_id :
150- emit_progress (item_id , profiler_tool , phase = "run" , percent = 0 )
149+
150+ def _emit (phase : str , percent : float , status : str = "progress" , ** meta : object ) -> None :
151+ """Emite progresso E alimenta o dashboard directamente.
152+
153+ ``emit_progress`` escreve no stdout do processo gameassets, que NÃO
154+ passa pelo callback ``on_progress_line`` do dashboard (esse só vê
155+ stdout dos sub-processos via ``run_cmd_streaming``). Sem este
156+ encaminhamento manual o dashboard congela em "Paint3D 100%" durante
157+ os stages do master pipeline (que duram dezenas de segundos cada).
158+ """
159+ if not item_id :
160+ return
161+ emit_progress (item_id , profiler_tool , phase = phase , percent = percent , ** meta )
162+ if on_progress_line is not None :
163+ import json as _json
164+
165+ data : dict = {
166+ "id" : item_id ,
167+ "tool" : profiler_tool ,
168+ "status" : status ,
169+ "phase" : phase ,
170+ "percent" : round (percent , 1 ),
171+ }
172+ data .update (meta )
173+ try :
174+ on_progress_line (_json .dumps (data ))
175+ except Exception : # noqa: BLE001
176+ pass
177+
178+ _emit ("run" , 0 )
151179
152180 t0 = _time .perf_counter ()
153181 try :
@@ -158,13 +186,39 @@ def _stage(
158186 ):
159187 if on_progress_line is not None and _run_cmd_streaming is not None :
160188 # Stream stdout para callback (dashboard) E acumula resultado.
189+ # Sub-tools (text3d/rigging3d/animator3d) emitem events com
190+ # ``id`` derivado do filename (ex.: "goblin_lod0"); o
191+ # dashboard chaveia por ``row.id`` ("goblin"), portanto
192+ # reescrevemos o ``id`` em cada linha JSON antes de
193+ # encaminhar para que a célula do asset reflicta a fase
194+ # corrente. ``phase`` ganha o nome do stage para distinguir
195+ # entre rigging-merge-lod0/lod1/animate-lod0/etc.
196+ import json as _json
197+
161198 stdout_buf : list [str ] = []
162199 stderr_buf : list [str ] = []
163200
164201 def _on_out (line : str ) -> None :
165202 stdout_buf .append (line )
166203 try :
167- on_progress_line (line )
204+ forwarded = line
205+ s = line .strip ()
206+ if item_id and s .startswith ("{" ) and s .endswith ("}" ):
207+ try :
208+ data = _json .loads (s )
209+ except (ValueError , _json .JSONDecodeError ):
210+ data = None
211+ if isinstance (data , dict ) and "id" in data :
212+ # Preserva o id original em sub_id e mostra
213+ # o ``name`` (stage do master) como tool.
214+ data ["sub_id" ] = data .get ("id" )
215+ data ["sub_tool" ] = data .get ("tool" , "" )
216+ data ["id" ] = item_id
217+ data ["tool" ] = profiler_tool
218+ if "phase" not in data and data .get ("sub_tool" ):
219+ data ["phase" ] = data ["sub_tool" ]
220+ forwarded = _json .dumps (data )
221+ on_progress_line (forwarded )
168222 except Exception : # noqa: BLE001
169223 pass
170224
@@ -183,22 +237,21 @@ def _on_err(line: str) -> None:
183237 r = run_cmd (argv , extra_env = env , cwd = cwd )
184238 except Exception as exc : # noqa: BLE001
185239 dt = _time .perf_counter () - t0
186- if item_id :
187- emit_progress (item_id , profiler_tool , phase = "run" , percent = 100 , status = "error" )
240+ _emit ("run" , 100 , status = "error" )
188241 return StageResult (name , False , dt , f"ProfilerSession: { exc } " , output )
189242
190243 dt = _time .perf_counter () - t0
191244 if r .returncode != 0 :
192245 err = merge_subprocess_output (r , max_chars = 400 ) or f"{ name } falhou (rc={ r .returncode } )"
193- if item_id :
194- emit_progress (item_id , profiler_tool , phase = "run" , percent = 100 , status = "error" )
246+ _emit ("run" , 100 , status = "error" )
195247 return StageResult (name , False , dt , err , output )
196248 if output is not None and not output .is_file ():
197- if item_id :
198- emit_progress (item_id , profiler_tool , phase = "run" , percent = 100 , status = "error" )
249+ _emit ("run" , 100 , status = "error" )
199250 return StageResult (name , False , dt , f"{ name } : output não foi criado" , output )
200- if item_id :
201- emit_progress (item_id , profiler_tool , phase = "run" , percent = 100 , status = "ok" )
251+ # Emite como ``progress`` (não ``ok``) — ``ok`` no dashboard sinaliza
252+ # conclusão do asset INTEIRO; usá-lo aqui faria a célula piscar OK entre
253+ # cada stage e contar duplicado no progresso global.
254+ _emit ("run" , 100 , status = "progress" , seconds = round (dt , 2 ))
202255 return StageResult (name , True , dt , output = output )
203256
204257
0 commit comments