
    UHj                       d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	 ej                  j                  d e e	e      j                         j                               ddlmZmZmZ ddlmZmZmZ  e	e      j                         j0                  d   Zedz  Zdd	Zed
dd	 	 	 	 	 	 	 	 	 ddZddZddZddZe dk(  r e        yy)z>Extract savedat scene selector table entries from Hwanse2.exe.    )annotationsN)Path)SCENE_SELECTOR_TABLE_VAcollect_linked_cnsdword_window)find_cns_stringsread_sectionsva_to_offset   outc                v    t        ||      }||dz   t        |       kD  ry t        j                  d| |      d   S )N   z<Ir   )r
   lenstructunpack_from)datasectionsvaoffsets       9/home/exedev/hwanse/tools/extract_save_scene_selectors.pyread_u32r      s?    (B'F~!c$i/dD&1!44    @       )table_va
max_groups	max_slotsc          
        t        |       }t        | |      }g }t        |      D ]W  }||dz  z   }t        | ||      }	t	        |	t
              rd|	cxk  rdk  sn 7t        ||	      Dt        |      D ]  }
|	|
dz  z   }t        | ||      }t	        |t
              rd|cxk  rdk  sn 7t        ||      Dt        | |||      }|j                  d      sdt        | |||d      }|j                  i d|d|
d	d
ddd|dd|dd|	dd|	dd|dd|dd|dd|dd|j                  dg       d|j                  dg       d|j                  d      d|j                  d      d|        Z |S )Nr   i  @ i  ` 	linkedCns   )countgroupslotselectorBytes      )groupOffset
slotOffsetrowPointerVarowPointerVaHex0x08x
rowPointerrowPointerHexselectedPointerVaselectedPointerVaHexselectedPointerselectedPointerHex	fieldMapslinkedScanDepth	scanDepthlinkedScannedPointersscannedPointersfirstDwords)r	   r   ranger   
isinstanceintr
   r   getr   append)r   r   r   r   r   stringsrowsr"   row_pointer_varow_pointerr#   selected_pointer_vaselected_pointerlinkedfirst_dwordss                  r   extract_selectorsrF      s<    T"HtX.GDz" %!EAI-tX~>+s+J+4[Q[4[+.6)$ 	D"-q"8'h8KL.4ZK[=i_i=iH&67?'hAQRF::k*'hAQYZ[LKKUD $Qa%H #N	
 &N3+?'@ !+ $r+c):%; ()< +b1DS0I,J &'7 )B/?.D*E  K!<  K!< &vzz+'> ,VZZ8I-J  "<!	%L Kr   c                8   dddddddt        |        ddddg
}| D ][  }|j                  d	|d
    d|d    d|d    ddj                  |d         xs d ddj                  |d   d d       xs d d       ] |j                  d       dj                  |      S )Nz# Save Scene Selectors z:Generated from the original loader's scene selector table.zSave bytes `0x0002` and `0x0003` select `group` and `slot`. The loader uses table `0x00442d35` and stores the selected pointer in `0x0059de30`.zRows: .z=| group | slot | selected pointer | field maps | linked CNS |z!| ---: | ---: | --- | --- | --- |z| r"   z | r#   z | `r2   z` | , r3   -r   
   z |
)r   r=   join)r?   linesrows      r   markdownrQ   P   s     
D
 	Z

T1
G+E  
Wc#f+d37K3L2MTyy[)*1c2#diiK@PQTRT@U6V6]Z]5^^`b	


 
LL99Ur   c                   ddddddddd	d
ddddddddddt        |        ddddg}| D ]  }d|d    d|d    }g }|j                  d      xs g D ]@  }|j                  dt        j                  |       dt        j                  |       d        B d!j                  d" |j                  d#      xs g d d$ D              xs d%}|j                  d&d'|d    d(d'|d    d(d)t        j                  |       d*|d    d+|d    d,d-d.j                  |      xs d% d/d0t        j                  |d1          d2d'| d(d3g        |j                  g d4       d5j                  |      S )6Nz<!doctype html>z<html lang="en">z<head>z  <meta charset="utf-8">zF  <meta name="viewport" content="width=device-width, initial-scale=1">z%  <title>Save Scene Selectors</title>z	  <style>z^    body { margin: 24px; background: #101010; color: #eee; font: 14px system-ui, sans-serif; }z5    table { border-collapse: collapse; width: 100%; }zM    th, td { border: 1px solid #333; padding: 6px 8px; vertical-align: top; }z9    th { background: #1d1d1d; position: sticky; top: 0; }z    a { color: #9bd4ff; }z    code { color: #ffd447; }z=    .links { display: flex; flex-wrap: wrap; gap: 6px 10px; }z
  </style>z</head>z<body>z  <h1>Save Scene Selectors</h1>z  <p>Save bytes <code>0x0002</code>/<code>0x0003</code> select group/slot. Links open the web runtime without loading all maps at startup.</p>z  <p>Rows: z.</p>z	  <table>z    <thead><tr><th>group</th><th>slot</th><th>open selector</th><th>field maps</th><th>selected pointer</th><th>linked CNS</th></tr></thead>z    <tbody>z../web/game.html?saveGroup=r"   z
&saveSlot=r#   r3   z<a href="../web/game.html?map=z">z</a>rJ   c              3  F   K   | ]  }t        j                  |        y w)N)htmlescape).0names     r   	<genexpr>z selector_html.<locals>.<genexpr>   s     XdD)Xs   !r      rK   z
      <tr>z        <td>z</td>z        <td><a href="z">saveGroup=z&amp;saveSlot=z	</a></td>z        <td><div class="links">rH   z</div></td>z        <td><code>r2   z</code></td>z      </tr>)z    </tbody>z
  </table>z</body>z</html>rH   rM   )r   r<   r=   rT   rU   rN   extend)r?   rO   rP   selector_hreffield_linksrW   cnss          r   selector_htmlr^   f   s   "P/h?WC#&G) 	Y
c$i[& 	W/E2  
5c'l^:cRXk][GGK(.B 	nD!?D@Q?RRTUYU`U`aeUfTggklm	niiXsww{7K7QrSVTV6WXX_\_s7|nE2s6{m51'M(B'C<PST[P\~]klopvlwkx  yB  C1"''+2F2M#1NkZ$T[[5I1J%K$LLYse5)		

$ 
LLIJ99Ur   c                     t        j                  t              } | j                  dt        t	        d             | j                  dt        t
        dz         | j                         }t        |j                  j                               }|j                  j                  j                  dd       |j                  j                  t        j                  |d	d
      dz   d       t!        dt#        |       d|j                          y )N)descriptionz--exezHwanse2.exe)typedefaultz
--json-outzsave_scene_selectors.jsonT)parentsexist_okF),:)ensure_ascii
separatorsrM   zutf-8)encodingzwrote z save scene selectors -> )argparseArgumentParser__doc__add_argumentr   OUT
parse_argsrF   exe
read_bytesjson_outparentmkdir
write_textjsondumpsprintr   )parserargsr?   s      r   mainr{      s    $$9F
dD4GH
4?Z9Z[DTXX0023DMMtd;MMTZZ5ZX[__jqr	F3t9+6t}}o
FGr   __main__)r   bytesr   
list[dict]r   r;   returnz
int | None)
r   r}   r   r;   r   r;   r   r;   r   r~   )r?   r~   r   str)r   None)!rl   
__future__r   rj   rT   rv   r   syspathlibr   pathinsertr   __file__resolvers   parse_savedatar   r   r   probe_exe_scene_tablesr   r	   r
   rc   ROOTrn   r   rF   rQ   r^   r{   __name__ r   r   <module>r      s    D "     
  3tH~--/667 8 T T P P H~''*
Ul5 ,0
0 0 	0
 0 0f,-`	H zF r   