a
    <^iZ                     @   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Z	reduction RC:\Program Files (x86)\Steam\steamapps\common\Selene ~Apoptosis~\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idoZo_reprsizeiookvr)   statefZo_repr_cachevisitr&   r(   rR   <   s|    




zsave_dump.<locals>.visitzsave_dump.txtwrootslogN)renpyerroropen_error_file)rT   rU   _r'   rP   r(   	save_dump3   s    h
rZ   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.   )r/   addr2   r3   r4   r5   r9   r:   rC   r1   r=   rD   r6   r>   r?   r7   r8   rE   rF   copyr"   )rG   rH   rI   rK   rL   rvrM   rN   r]   r)   rO   seenrR   r&   r(   rR      sh    







z!find_bad_reduction.<locals>.visitNzrenpy.game.log)setrD   )rT   rU   rM   rN   r^   r'   r_   r(   find_bad_reduction   s    S

rb   c                   @   s   e Zd ZdS )	SaveAbortN)r<   
__module____qualname__r'   r'   r'   r(   rc     s   rc   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)osrH   existsunlinkrenamerF   oldnewr'   r'   r(   safe_rename  s    

rm   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jsonrU   first_filename)selfro   rp   rq   rU   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.newNrS   zscreenshot.pngrp   zutf-8rq   Zrenpy_versionrU   )rr   shutilcopyfilerm   zipfileZipFileZIP_DEFLATEDro   Zwritestrrp   encoderq   rV   versionrU   )rs   filenameZfilename_newzfr'   r'   r(   
write_file@  s    


,
zSaveRecord.write_fileN)r<   rd   re   __doc__rt   r~   r'   r'   r'   r(   rn   1  s   rn    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_nameZ_renpy_versionZ_version)"rV   
persistentupdate
revertablemutate_flaggamerU   freezeconfigrZ   ioBytesIOr   rF   sysexc_infor   rb   argsr1   rc   	interfaceget_screenshotr:   version_tupler{   save_json_callbacks
json_dumpsrn   getvaluelocationsavescan
clear_slot)slotnamerp   r   rT   ZlogftetbZbadro   rq   rK   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   rp   r   )cycle_savesrV   r   autosave_slotsauto_save_extra_infoexportstake_screenshotr   autosave_counterrF   autosave_not_runningra   
emscriptenZsyncfs)r   rp   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)rV   r   autosave_frequencyhas_autosaver   is_setskippingr"   r   contextsr   store	main_menuZ	_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   )rp   )targetr   T)rV   r   r   r   after_rollbackr   in_rollbackr   r   autosave_threadjoinr   r   
_in_replayr   r   r   r   r   clearr   	threadingThreadr   daemonstart)r   blockrp   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mtimerq   rp   ro   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.0rK   regexpr'   r(   
<listcomp>n      z$list_saved_games.<locals>.<listcomp>r   r   )	r   r:   sortr   r   r)   r   r   append)
r   fastslotsr^   sr   rq   rp   ro   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   r^   Z	max_mtimer   rK   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.
    Z_after_load)labelN)r   r   loadunfreeze)r|   rT   rU   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   rh   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   ri   r   rj   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   rj   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countrK   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   )rs   r   r'   r'   r(   rt   E  s    zCache.__init__c                 C   s   t | _t | _t | _d S r    )r   r   rq   ro   rs   r'   r'   r(   r   I  s    zCache.clearc                 C   s$   | j }|tu r t | j }| _ |S r    )r   r   r   r   rs   r^   r'   r'   r(   r   S  s    zCache.get_mtimec                 C   s$   | j }|tu r t | j }| _ |S r    )rq   r   r   r   r   r'   r'   r(   r   \  s    zCache.get_jsonc                 C   s&   | j }|tu r t | j }| _ | j S r    )ro   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<   rd   re   r   rt   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   r^   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   rV   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   rV   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.
    rY   N)r   
startswithr   r   )rK   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   rw   r   r   r6   ru   rf   r   rV   rq   r   r   renpy.compat.pickler   r   savegame_suffixrZ   rb   rF   rc   rm   rA   rn   r   r   Eventr   ra   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   ZsavelocationZFileLocationr'   r'   r'   r(   <module>   sh   8xi2
K"
E
5

#

:

