a
    V$cZ                     @   s  d dl mZmZmZmZmZ d dlmZmZm	Z	m
Z
mZmZmZmZmZmZmZmZ d dlm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Zd dlZd dlZd dlZd dl m!Z" d dl#m$Z$m%Z% ej&Z&dd	 Z'd
d Z(G dd de)Z*dd Z+G dd de,Z-dDddZ.da/e0 Z1e12  d a3dd Z4dd Z5dEddZ6dd Z7dFdd Z8dGd!d"Z9i Z:dHd#d$Z;d%d& Z<d'd( Z=d)d* Z>dId+d,Z?d-d. Z@d/d0 ZAd1d2 ZBd3d4 ZCd5d6 ZDej,Ed7ZFG d8d9 d9e,ZGi ZHd:d; ZId<d= ZJd>d? ZKd@dA ZLdZMdBd krejNOdCZMdS )J    )divisionabsolute_importwith_statementprint_functionunicode_literals)PY2
basestringbchrbordchropenpystrrangeroundstrtobytesunicode)reraise)OptionalN)dumps)dumploadsc                    sb   i  fddt jdd\ } $ | d |d W d   n1 sT0    Y  dS )z
    Dumps information about the save to save_dump.txt. We dump the size
    of the object (including unique children), the path to the object,
    and the type or repr of the object.
    c                    sl  t | }|v r,dd||  dS t| tttd tjtfrPt	| }nt| t
rt| dkrpt	| }nt	| d d d }nt| ttfrd| jj d }nt| trd| jj d }nnt| tjrtrd| jjj| jj}nd| jjj| j}n.t| tr dt| j}nd	t| j}||< t| tttd tjtfr\d
}nt| tr|t| d d
 }nt| ttfrd
}t| D ](\}}|d
7 }||d||7 }qnt| trd}|  D ](\}}|d7 }||d||7 }qސnDt| tjr2d
| j|d  }nz| d W n  ty`   g  d| }Y n0  fdd}	d
}|	di }
t|
tr|
 D ](\}}|d7 }|||d | 7 }qn||
|d 7 }t|	dg D ](\}}|d
7 }||d||7 }q|	dg D ]>}t|dkr&q|\}}|d7 }||d||7 }qd|||  |S )Nz{0: 7d} {1} = alias {2}
r   P   z...<>z<method {0}.{1}>z<{0}>zBAD TYPE <{0}>   (   
{0}[{1!r}]   .im_selfzBAD REDUCTION c                    s(   | t  k r  |  d ur  |  S |S d S Nlenidxdefault	reduction renpy/loadsave.pyget   s    z%save_dump.<locals>.visit.<locals>.get..__getstate__()   {0}[{1}]   z{0: 7d} {1} = {2}
)idwriteformat
isinstanceintfloattypetypes
ModuleTypereprr   r"   tuplelist	__class____name__dict
MethodTyper   __self____func__objectbytes	enumerateitems__reduce_ex__	Exception)opathidoo_reprsizeiookvr*   statefo_repr_cachevisitr&   r)   rU   <   s|    




zsave_dump.<locals>.visitzsave_dump.txtwrootslogN)renpyerroropen_error_file)rW   rX   _r(   rR   r)   	save_dump3   s    h
r]   c                    sJ   t    fdd|  D ]"\}}||}|dur|  S q|dS )z7
    Finds objects that can't be reduced properly.
    c                    sx  t | }|v rd S | t| tttd tfr8d S t| ttfr~t| D ]*\}}|d	||}|d urN|  S qNnt| t
r|  D ]*\}}|d	||}|d ur|  S qnt| tjr܈| j|d S t| tjrd	|t| d d S z| d W n\ tyl   dd l}z||  W Y d S  tyN   Y n0 d	|t| d d  Y S 0  fdd}	|	di }
t|
t
r|
 D ].\}}||d	 | }|d ur|  S qn|
|d
 }|d ur|S t|	dg D ].\}}|d	||}|d ur|  S q|	dg D ]D}t|dkrDq.|\}}|d	||}|d ur.|  S q.d S )Nr   r   z{} = {}   r   r   c                    s(   | t  k r  |  d ur  |  S |S d S r    r!   r#   r&   r(   r)   r*      s    z.find_bad_reduction.<locals>.visit.<locals>.getr+   r,   r-   r.   r/   )r0   addr3   r4   r5   r6   r:   r;   rD   r2   r>   rE   r7   r?   r@   r8   r9   rF   rG   copyr"   )rH   rI   rJ   rM   rN   rvrO   rP   r`   r*   rQ   seenrU   r&   r)   rU      sh    







z!find_bad_reduction.<locals>.visitNzrenpy.game.log)setrE   )rW   rX   rO   rP   ra   r(   rb   r)   find_bad_reduction   s    S

re   c                   @   s   e Zd ZdS )	SaveAbortN)r=   
__module____qualname__r(   r(   r(   r)   rf     s   rf   c                 C   s   t j|rt | zt | | W nb ty   zt | t | | W n4 ty   zt |  W n ty|   Y n0 Y n0 Y n0 dS )z#
    Safely rename old to new.
    N)osrI   existsunlinkrenamerG   oldnewr(   r(   r)   safe_rename  s    

rp   c                   @   s    e Zd ZdZdd Zdd ZdS )
SaveRecordz
    This is passed to the save locations. It contains the information that
    goes into a save file in uncompressed form, and the logic to save that
    information to a Ren'Py-standard format save file.
    c                 C   s"   || _ || _|| _|| _d | _d S r    )
screenshot
extra_infojsonrX   first_filename)selfrr   rs   rt   rX   r(   r(   r)   __init__8  s
    zSaveRecord.__init__c                 C   s   |d }| j dur.t| j | t|| dS t|dtjf}| jdurX|d| j |d| j	
d |d| j |dtj |d	| j W d   n1 s0    Y  t|| || _ dS )
zG
        This writes a standard-format savefile to `filename`.
        z.newNrV   zscreenshot.pngrs   zutf-8rt   renpy_versionrX   )ru   shutilcopyfilerp   zipfileZipFileZIP_DEFLATEDrr   writestrrs   encodert   rY   versionrX   )rv   filenamefilename_newzfr(   r(   r)   
write_file@  s    


,
zSaveRecord.write_fileN)r=   rg   rh   __doc__rw   r   r(   r(   r(   r)   rq   1  s   rq    Fc                 C   s  |st j  |rdt j_t jjd}t jj	r>t	|t jj t
 }zt|t jjf| W n ty   t \}}}|rt||| zt|t jj}W n ty   t||| Y n0 |du rt||| |jr|jd d| f|jdd  |_t||| Y n0 |r$t jjr$t t jj }	|tt jt jjd}
t jjD ]}||
 qNt|
}
t|	||
| }t| | t   t!|  dS )a  
    :doc: loadsave
    :args: (filename, extra_info='')

    Saves the game state to a save slot.

    `filename`
        A string giving the name of a save slot. Despite the variable name,
        this corresponds only loosely to filenames.

    `extra_info`
        An additional string that should be saved to the save file. Usually,
        this is the value of :var:`save_name`.

    :func:`renpy.take_screenshot` should be called before this function.
    FNr   z (perhaps {})r   )
_save_name_renpy_version_version)"rY   
persistentupdate
revertablemutate_flaggamerX   freezeconfigr]   ioBytesIOr   rG   sysexc_infor   re   argsr2   rf   	interfaceget_screenshotr;   version_tupler   save_json_callbacks
json_dumpsrq   getvaluelocationsavescan
clear_slot)slotnamers   r   rW   logftetbbadrr   rt   rM   srr(   r(   r)   r   c  sD    
&r   c                 C   s   zzNt dtjj tjjr&tj }nd}| r<tjjdd tdd|d daW n t	yb   Y n0 W t
  tjrdd l}|  n t
  tjrdd l}|  0 d S )Nauto-r   T)
backgroundauto-1)r   rs   r   )cycle_savesrY   r   autosave_slotsauto_save_extra_infoexportstake_screenshotr   autosave_counterrG   autosave_not_runningrd   
emscriptensyncfs)r   rs   r   r(   r(   r)   autosave_thread_function  s(    
r   c                   C   s   t jjsd S t jjsd S t s$d S t jjr0d S tt jj	dkrDd S t
d7 a
t
t jjk r\d S t jjrhd S t jjstd S td d S )Nr   T)rY   r   autosave_frequencyhas_autosaver   is_setskippingr"   r   contextsr   store	main_menu	_autosaveforce_autosaver(   r(   r(   r)   autosave  s$    r   c                 C   s   t jjsdS t jjst j r"dS t s.dS t	durBt	
  da	t jjrNdS t jjrZdS |rt jjrrt j }nd}tdt jj | rt j  td|d dS t  t jstjt| fda	dt	_t	  nt|  dS )a  
    :doc: other

    Forces a background autosave to occur.

    `take_screenshot`
        If True, a new screenshot will be taken. If False, the existing
        screenshot will be used.

    `block`
        If True, blocks until the autosave completes.
    Nr   r   r   )rs   )targetr   T)rY   r   r   r   after_rollbackr   in_rollbackr   r   autosave_threadjoinr   r   
_in_replayr   r   r   r   r   clearr   	threadingThreadr   daemonstart)r   blockrs   r(   r(   r)   r     s8    

r   c                 C   sZ   t | }| }|d u rd S | }|d u r0d S |dd}| }|d u rPd S |||fS )Nr   r   )	get_cache	get_mtimeget_jsonr*   r   )r   cmtimert   rs   rr   r(   r(   r)   scan_saved_game>  s    r   r+   c           
         s   t  } dur" fdd|D }|  |r2|S g }|D ]X}t|}|dur:| }|durl|dd}nd}| }| }	|||||	f q:|S )a3  
    :doc: loadsave

    Lists the save games. For each save game, returns a tuple containing:

    * The filename of the save.
    * The extra_info that was passed in.
    * A displayable that, when displayed, shows the screenshot that was
      used when saving the game.
    * The time the game was stayed at, in seconds since the UNIX epoch.

    `regexp`
        A regular expression that is matched against the start of the
        filename to filter the list.

    `fast`
        If fast is true, the filename is returned instead of the
        tuple.
    Nc                    s   g | ]}t  |r|qS r(   rematch.0rM   regexpr(   r)   
<listcomp>n      z$list_saved_games.<locals>.<listcomp>r   r   )	r   r;   sortr   r   r*   r   r   append)
r   fastslotsra   sr   rt   rs   rr   r   r(   r   r)   list_saved_gamesU  s$    r   c                    s.   t  } dur" fdd|D }|  |S )z
    :doc: loadsave

    Returns a list of non-empty save slots. If `regexp` exists, only slots
    that begin with `regexp` are returned. The slots are sorted in
    string-order.
    Nc                    s   g | ]}t  |r|qS r(   r   r   r   r(   r)   r     r   zlist_slots.<locals>.<listcomp>)r   r;   r   )r   r   r(   r   r)   
list_slots  s
    
r   c                 C   sv   t | t}|tu rjd}d}t }|D ]@}| durBt| |sBq(t| }|du rXq(||kr(|}|}q(|t | < |S )z
    :doc: loadsave

    Returns the name of the newest save slot (the save slot with the most
    recent modification time), or None if there are no (matching) saves.

    If `regexp` exists, only slots that begin with `regexp` are returned.
    r   N)	newest_slot_cacher*   unknownr   r;   r   r   r   r   )r   ra   	max_mtimer   rM   r   r(   r(   r)   newest_slot  s     
r   c                 C   s   t |  S )ze
    :doc: loadsave

    Returns the modification time for `slot`, or None if the slot is empty.
    r   r   r   r(   r(   r)   
slot_mtime  s    r   c                 C   s   t |  S )aJ  
    :doc: loadsave

    Returns the json information for `slotname`, or None if the slot is
    empty.

    Much like the ``d`` argument to the :var:`config.save_json_callback`
    function, it will be returned as a dictionary. More precisely, the
    dictionary will contain the same data as it did when the game was saved.
    )r   r   r   r(   r(   r)   	slot_json  s    r   c                 C   s   t |  S )z
    :doc: loadsave

    Returns a display that can be used as the screenshot for `slotname`,
    or None if the slot is empty.
    )r   r   r   r(   r(   r)   slot_screenshot  s    r   c                 C   s   t | }| rdS dS dS )zd
    :doc: loadsave

    Returns true if `filename` exists as a save slot, and False otherwise.
    TFNr   )r   testr   r(   r(   r)   can_load  s    r   c                 C   s$   t t| \}}|j|dd dS )z
    :doc: loadsave

    Loads the game state from the save slot `filename`. If the file is loaded
    successfully, this function never returns.
    _after_load)labelN)r   r   loadunfreeze)r   rW   rX   r(   r(   r)   r     s    r   c                 C   s   t |  t|  dS )zH
    :doc: loadsave

    Deletes the save slot with the given name.
    N)r   rk   r   )r   r(   r(   r)   unlink_save  s    
r   c                 C   s    t | | t|  t| dS )zm
    :doc: loadsave

    Renames a save from `old` to `new`. (Does nothing if `old` does not
    exist.)
    N)r   rl   r   rm   r(   r(   r)   rename_save  s    r   c                 C   s   t | | t| dS )zl
    :doc: loadsave

    Copies the save at `old` to `new`. (Does nothing if `old` does not
    exist.)
    N)r   r`   r   rm   r(   r(   r)   	copy_save  s    r   c                 C   s8   t |d ddD ]"}t| t| | t|d   qdS )a  
    :doc: loadsave

    Rotates the first `count` saves beginning with `name`.

    For example, if the name is auto- and the count is 10, then
    auto-9 will be renamed to auto-10, auto-8 will be renamed to auto-9,
    and so on until auto-1 is renamed to auto-2.
    r   r   N)r   r   r   )namecountrM   r(   r(   r)   r   )  s    r   r   c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )Cachez?
    This represents cached information about a save slot.
    c                 C   s   || _ |   d S r    )r   r   )rv   r   r(   r(   r)   rw   E  s    zCache.__init__c                 C   s   t | _t | _t | _d S r    )r   r   rt   rr   rv   r(   r(   r)   r   I  s    zCache.clearc                 C   s$   | j }|tu r t | j }| _ |S r    )r   r   r   r   rv   ra   r(   r(   r)   r   S  s    zCache.get_mtimec                 C   s$   | j }|tu r t | j }| _ |S r    )rt   r   r   r   r   r(   r(   r)   r   \  s    zCache.get_jsonc                 C   s&   | j }|tu r t | j }| _ | j S r    )rr   r   r   r   r   r(   r(   r)   r   e  s    zCache.get_screenshotc                 C   s   |    |   |   dS )zR
        Preloads all the save data (that won't take up a ton of memory).
        N)r   r   r   r   r(   r(   r)   preloadn  s    zCache.preloadN)
r=   rg   rh   r   rw   r   r   r   r   r   r(   r(   r(   r)   r   @  s   
			r   c                 C   s(   t | d }|d u r$t|  }t | < |S r    )cacher*   r   )r   ra   r(   r(   r)   r   }  s    r   c                 C   s"   t |   t  tj  dS )z,
    Clears a single slot in the cache.
    N)r   r   r   rY   r   restart_interactionr   r(   r(   r)   r     s    r   c                  C   s,   t  D ]} |   qt  tj  dS )z"
    Clears the entire cache.
    N)r   valuesr   r   rY   r   r   )r   r(   r(   r)   clear_cache  s    
r   c                  C   s&   t  D ]} | dst|   qdS )z:
    Scans all the metadata from the save slot cache.
    r\   N)r   
startswithr   r   )rM   r(   r(   r)   init  s    

r   r   Zblah)r   F)FF)r+   F)N)N)F)P
__future__r   r   r   r   r   renpy.compatr   r   r	   r
   r   r   r   r   r   r   r   r   future.utilsr   typingr   r   r{   r   r   r7   ry   ri   r   rY   rt   r   r   renpy.compat.pickler   r   savegame_suffixr]   re   rG   rf   rp   rB   rq   r   r   Eventr   rd   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   Sentinelr   r   r   r   r   r   r   r   savelocationFileLocationr(   r(   r(   r)   <module>   sh   8xi2
K"
E
5

#

:

