SHARE
TWEET

c3mm.py

7163D Oct 5th, 2016 70 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # Cossacks 3 Mod Manager version 1.3.7
  2. # Require python 3.5.x to work : https://python.org/downloads
  3. # Get all update at http://www.cossacks3.com/forum/index.php?threads/cossacks-3-text-mod-manager.17753
  4.  
  5. """
  6. # === News in 1.3.7 === #
  7.     >Fix bugs
  8.  
  9. """
  10.  
  11.  
  12. """
  13. Structur uses
  14. Mod  := {'name':name, 'version':version, 'info':info, 'author':author, file':{name => list of (str old, str new)}, 'otherfile':{name => new}}
  15. Data := {'mod':{name => mod mod}, 'file':{name => list of str mod}}
  16. """
  17.  
  18. import json, sys, os, time
  19. from random import randrange
  20.  
  21. CONFIG_PATH = "c3mm/"
  22. MOD_PATH    = "mod/"
  23. COPY_PATH   = "c3mm/copy/"
  24. BCKUP_PATH  = "c3mm/bckup/"
  25. INFO_PATH   = "c3mm/c3mm.json"
  26. LOG_PATH    = "c3mm/log.txt"
  27. HELP = """
  28. Cossacks3 (text) Mod Manager Version 1.3.7.
  29. Type python c3mm.py action [parameter]
  30.     action:
  31.         install modname   -> intall a mod find by name
  32.         uninstall modname -> unintall a mod find by name
  33.         help              -> show this message
  34.         uninstall_all     -> uninstall all mod
  35.         giveall           -> print all installed mods
  36.         valid_mod modname -> check if mod modname is valid
  37.         info modname      -> print all informations about mod modname
  38. """
  39.  
  40. PATH = [CONFIG_PATH, MOD_PATH, COPY_PATH, BCKUP_PATH]
  41. FILE = [INFO_PATH, LOG_PATH]
  42. for path in PATH:
  43.     try:
  44.         os.mkdir(path)
  45.     except:
  46.         pass
  47. for file in FILE:
  48.     try:
  49.         open(file, 'r')
  50.     except:
  51.         open(file, 'w')
  52.  
  53. class Alert:
  54.     linfo = []
  55.     lerror = []
  56.     show = True
  57.  
  58.     def info(i):
  59.         if Alert.show:
  60.             Alert.linfo.append(i)
  61.         print(i)
  62.  
  63.     def error(e, data):
  64.         Alert.lerror.append(e)
  65.         if Alert.show:
  66.             print(e)
  67.         quit(data)
  68.  
  69.     def input(m):
  70.         return input(m)
  71.  
  72.     def list(l):
  73.         for i in l:
  74.             if Alert.show:
  75.                 print(i)
  76.  
  77. def loadjson(path):
  78.     return json.loads(open(path, 'r').read())
  79.  
  80. def savejson(path, data):
  81.     open(path, "w").write(json.dumps(data))
  82.  
  83. def loadjsonmod(path):
  84.     try:
  85.         mod = loadjson(path)
  86.     except:
  87.         Alert.info("Impossible to open " + path)
  88.         return False
  89.  
  90.     if not "otherfile" in mod:
  91.         mod["otherfile"] = {}
  92.     if not "addfile" in mod:
  93.         mod["addfile"] = {}
  94.     if not "file" in mod:
  95.         mod["file"] = mod["modify_file"]
  96.     if not "otherfile" in mod:
  97.         mod["otherfile"] = mod["replace_file"]
  98.     if not "addfile" in mod:
  99.         mod["addfile"] = mod["add_file"]
  100.     if not "remove_file" in mod:
  101.         mod["remove_file"] = {}
  102.     if not validMod(mod):
  103.         return False
  104.     return mod
  105.  
  106. def mkPath(path):
  107.     rpath = ""
  108.     for dir in path.split('/')[:-1]:
  109.         rpath += dir
  110.         try:
  111.             os.mkdir(rpath)
  112.         except:
  113.             pass
  114.         rpath += '/'
  115.  
  116. def copyFile(file, path):
  117.     mkPath(path)
  118.     open(path, "w").write(open(file, 'r').read())
  119.  
  120. def copyBFile(file, path):
  121.     mkPath(path)
  122.     open(path, "wb").write(open(file, 'rb').read())
  123.  
  124. def checkMod(mod, data):
  125.     """
  126.     checkMod function, use to check if a mod is valid
  127.     Mod mod     -> mod to check
  128.     Bool return -> is the mod valid?
  129.     """
  130.     for file in mod['file']:
  131.         Alert.info("Check existence of '" + file + "'")
  132.         try:
  133.             f = open(file, 'r').read()
  134.             Alert.info("'" + file + "' exist.")
  135.         except:
  136.             Alert.info("'" + file + "' don't exist.")
  137.             return False
  138.  
  139.         for old in mod['file'][file]:
  140.             Alert.info("Check exsitence of '" + old + "' in '" + file + "'")
  141.             if not old in f:
  142.                 Alert.info("Not found.")
  143.                 return False
  144.             else:
  145.                 Alert.info("Found.")
  146.  
  147.     for file in mod["otherfile"]:
  148.         Alert.info("Check existence of '" + file + "'")
  149.         try:
  150.             open(file, 'r')
  151.             Alert.info("'" + file + "' exist.")
  152.         except:
  153.             Alert.info("'" + file + "' don't exist.")
  154.             return False
  155.  
  156.         Alert.info("Check existence of '" + MOD_PATH + mod["otherfile"][file] + "'")
  157.         try:
  158.             open(MOD_PATH + mod["otherfile"][file], 'r')
  159.             Alert.info("'" + MOD_PATH + mod["otherfile"][file] + "' exist.")
  160.         except:
  161.             Alert.info("'" + MOD_PATH + mod["otherfile"][file] + "' don't exist.")
  162.             return False
  163.  
  164.         if file in data["otherfile"]:
  165.             Alert.info(file + " is already modified by " + data["otherfile"][file][0])
  166.             Alert.info("You have to uninstall " + data["otherfile"][file][0] + " to install " + mod['name'])
  167.             return False
  168.  
  169.     for file in mod["addfile"]:
  170.         Alert.info("Check existence of '" + MOD_PATH + mod["addfile"][file] + "'")
  171.         try:
  172.             open(MOD_PATH + mod["addfile"][file], 'r')
  173.             Alert.info("'" + MOD_PATH + mod["addfile"][file] + "' exist.")
  174.         except:
  175.             Alert.info("'" + MOD_PATH + mod["addfile"][file] + "' don't exist.")
  176.             return False
  177.  
  178.         if file in data["addfile"]:
  179.             Alert.info(file + " is already added by " + data["addfile"][file][0])
  180.             Alert.info("You have to uninstall " + data["addfile"][file][0] + " to install " + mod['name'])
  181.             return False
  182.  
  183.     return True
  184.  
  185. def validMod(mod):
  186.     """
  187.     validMod function, assert not error occured when install mod
  188.     Mod mod -> mod to check
  189.     Bool return
  190.     """
  191.     for field in ['name', 'info', 'file', 'version', 'author']:
  192.         if not field in mod:
  193.             Alert.info("Missing field '" + field + "'")
  194.             return False
  195.  
  196.     if not type(mod['file']) == type({}):
  197.         Alert.info("Wrong data mod")
  198.         return False
  199.  
  200.     for file in mod['file']:
  201.         if not type(mod['file'][file]) == type({}):
  202.             Alert.info("Wrong data mod")
  203.             return False
  204.         try:
  205.             for old in mod['file'][file]:
  206.                 new = mod['file'][file][old]
  207.                 if not type(old) == type("") or not type(new) == type(""):
  208.                     Alert.info("Wrong data mod")
  209.                     return False
  210.         except:
  211.             Alert.info("Wrong data mod")
  212.             return False
  213.  
  214.     if not type(mod['otherfile']) == type({}):
  215.         Alert.info("Wrong data mod")
  216.         return False
  217.  
  218.     if not type(mod['addfile']) == type({}):
  219.         Alert.info("Wrong data mod")
  220.         return False
  221.  
  222.  
  223.     return True
  224.  
  225.  
  226. def apply(mod):
  227.     """
  228.     apply function, use to modify files
  229.     Mod mod -> mod that contain all modifications
  230.     None return
  231.     """
  232.     mfile = {}
  233.     for file in mod['file']:
  234.         Alert.info("Calculate'" + file + '"')
  235.         f = open(file, 'r').read()
  236.  
  237.         #Calculate modifications
  238.         for old in mod['file'][file]:
  239.             new = mod['file'][file][old]
  240.             f = f.replace(old, new)
  241.  
  242.         mfile[file] = f
  243.    
  244.     #Apply mod
  245.     for file in mfile:
  246.         Alert.info("Patching '" + file + '"')
  247.         open(file, 'w').write(mfile[file])
  248.  
  249.     for file in mod["otherfile"]:
  250.         Alert.info("Replace '" + file+ "'")
  251.         copyBFile(MOD_PATH + mod["otherfile"][file], file)
  252.  
  253.     for file in mod["addfile"]:
  254.         Alert.info("Add '" + file + "'")
  255.         copyBFile(MOD_PATH + mod["addfile"][file], file)
  256.  
  257.     for file in mod["remove_file"]:
  258.         Alert.info("Remove'" + file + "'")
  259.         os.remove(file)
  260.  
  261. def install(mod, data):
  262.     """
  263.     install function, use to add a mod.
  264.     Mod mod   -> mod to install
  265.     Data data -> c3mm main data
  266.     None return
  267.     """
  268.     if not checkMod(mod, data):
  269.         Alert.error("'" + mod['name'] + "' mod version " + mod['version'] + " isn't valid", data)
  270.  
  271.     Alert.info("Install '" + mod['name'] + "' version " + mod['version'])
  272.  
  273.     #Add some "signature"
  274.     for file in mod['file']:
  275.         for old in mod['file'][file]:
  276.             mod['file'][file][old] = mod['file'][file][old] + "//" + str(randrange(100000, 999999))
  277.  
  278.     #Add mod to list of installed mod
  279.     data['mod'][mod['name']] = mod
  280.  
  281.     #Adding mod in list of file modification
  282.     for file in mod['file']:
  283.         if not file in data['file']:
  284.             data['file'][file] = [mod['name']]
  285.             #backup file
  286.             copyFile(file, BCKUP_PATH + file)
  287.         else:
  288.             data['file'][file].append(mod['name'])
  289.  
  290.     for file in mod["otherfile"]:
  291.         if not file in data['otherfile']:
  292.             data['otherfile'][file] = [mod['name']]
  293.             #backup file
  294.             copyBFile(file, BCKUP_PATH + file)
  295.         else:
  296.             data['otherfile'][file].append(mod['name'])
  297.  
  298.     for file in mod["addfile"]:
  299.         if not file in data['otherfile']:
  300.             data['addfile'][file] = [mod['name']]
  301.         else:
  302.             data['addfile'][file].append(mod['name'])
  303.  
  304.     for file in mod["remove_file"]:
  305.         copyBFile(file, BCKUP_PATH + file)
  306.         data["remove_file"][file] = [mod['name']]
  307.  
  308.     apply(mod)
  309.  
  310.     for file in mod['file']:
  311.         #make a save of the file
  312.         copyFile(file, COPY_PATH + file)
  313.  
  314. def uninstall(mod, data):
  315.     """
  316.     uninstall function, use to delete a mod.
  317.     Mod mod   -> mod to uninstall
  318.     Data data -> c3mm main data
  319.     None return
  320.     """
  321.     uninstallmod = mkuninstallmod(mod)
  322.  
  323.     if not checkMod(uninstallmod, data):
  324.         Alert.info("'" + mod['name'] + "' mod uninstaller isn't valid.")
  325.         Alert.info("Do you want restore all files concerned by this mod?")
  326.         Alert.info("List of mod will uninstalled in this case:")
  327.         modlist = []
  328.         for file in mod['file']:
  329.             for mod in data['file'][file]:
  330.                 if not mod in modlist:
  331.                     modlist.append(mod)
  332.                     Alert.info(mod)
  333.         choice = Alert.input("Restore all file? yes/no:")
  334.         if choice == 'no':
  335.             quit(data)
  336.  
  337.         filelist = [file for file in mod['file']]
  338.         for file in filelist:
  339.             Alert("Restore '" + file + "'")
  340.             copyFile(BCKUP_PATH + file, file)
  341.             for mod in modlist:
  342.                 if file in mod["file"]:
  343.                     del mod["file"][file]
  344.                 if file in mod["otherfile"]:
  345.                     del mod["otherfile"][file]
  346.                 if file in mod["addfile"]:
  347.                     del mod["addfile"][file]
  348.                 if file in mod["remove_file"]:
  349.                     mod["remove_file"].remove("file")
  350.  
  351.         for mod in modlist:
  352.             uninstall(mod, data)
  353.     #Delete mod to list of installed mod
  354.     del data['mod'][mod['name']]
  355.  
  356.     #Delete mod of list of file modification
  357.     for file in data['file']:
  358.         if mod['name'] in data['file'][file]:
  359.             data['file'][file].remove(mod['name'])
  360.  
  361.     Alert.info("Uninstall '" + mod['name'] + "' version " + mod['version'])
  362.  
  363.     for file in mod["otherfile"]:
  364.         Alert.info("Restore " + file)
  365.         copyBFile(BCKUP_PATH + file, file)
  366.         del data["otherfile"][file]
  367.  
  368.     for file in mod["addfile"]:
  369.         Alert.info("Delete " + file)
  370.         os.remove(file)
  371.         del data["addfile"][file]
  372.  
  373.     for file in mod["remove_file"]:
  374.         Alert.info("Restore " + file)
  375.         copyBFile(BCKUP_PATH + file, file)
  376.         del data["remove_file"][file]
  377.  
  378.     apply(uninstallmod)
  379.  
  380. def mkuninstallmod(mod):
  381.     """
  382.     mkuninstallmod function, use to make an uninstalator from a mod
  383.     Mod mod    -> mod to uninstall
  384.     Mod return -> uninstalator mod
  385.     """
  386.     uninstallmod = {}
  387.     uninstallmod['file'] = {}
  388.  
  389.     for file in mod['file']:
  390.         uninstallmod['file'][file] = {}
  391.         for old in mod['file'][file]:
  392.             new = mod['file'][file][old]
  393.             #For each modification of mod, inverse new and old
  394.             uninstallmod['file'][file][new] = old
  395.  
  396.     uninstallmod["otherfile"] = {}
  397.     uninstallmod["addfile"] = {}
  398.     uninstallmod["remove_file"] = {}
  399.  
  400.     return uninstallmod
  401.  
  402. def checkStatu(data):
  403.     """
  404.     checkStatu funtion, check if a modded file has been modified since last launch of this program
  405.     Data data   -> main data
  406.     Bool return ->
  407.     """
  408.     badfile = []
  409.     #Check all modded file
  410.     for file in data['file']:
  411.         if open(file, 'r').read() != open(COPY_PATH + file, 'r').read():
  412.             Alert.info("File '" + file + "' has been modified since last launch of c3mm.")
  413.             badfile.append(file)
  414.  
  415.     badotherfile = []
  416.     for file in data["otherfile"]:
  417.         if open(file, 'rb').read() != open(BCKUP_PATH + file, 'rb').read():
  418.             Alert.info("File '" + file + "' has been modified since last launch of c3mm.")
  419.             badotherfile.append(file)
  420.  
  421.     badmod = []
  422.     #Uninstall all mod concerned by these files
  423.     for file in badfile:
  424.         for mod in data['file'][file]:
  425.             if not mod in badmod and not checkMod(mkuninstallmod(data['mod'][mod]), data):
  426.                 badmod.append(mod)
  427.     for file in badotherfile:
  428.         if not data["otherfile"][file][0] in badmod:
  429.             badmod.append(data["otherfile"][file][0])
  430.  
  431.     for mod in badmod:
  432.         _mod = data['mod'][mod]
  433.         for file in badfile:
  434.             if file in _mod['file']:
  435.                 del _mod['file'][file]
  436.         uninstall(_mod, data)
  437.  
  438.     #make a new copy of all modified files
  439.     for file in badfile:
  440.         copyFile(file, COPY_PATH + file)
  441.  
  442.     return len(badmod) == 0
  443.  
  444. def quit(data):
  445.     """
  446.     Save all data before exit the program
  447.     """
  448.     dfile = []
  449.     for file in data['file']:
  450.         if data['file'][file] == []:
  451.             dfile.append(file)
  452.  
  453.     for file in dfile:
  454.         del data['file'][file]
  455.  
  456.     savejson(INFO_PATH, data)
  457.  
  458.     logs = time.strftime('%D %H:%M\n',time.localtime())
  459.     for info in Alert.linfo:
  460.         logs += info + '\n'
  461.     for error in Alert.lerror:
  462.         logs += error + '\n'
  463.  
  464.     open(LOG_PATH, "a").write(logs)
  465.     exit()
  466.  
  467. def main(argc, argv):
  468.  
  469.     try:
  470.         data = loadjson(INFO_PATH)
  471.     except:
  472.         open(INFO_PATH, "w").write('{"mod":{}, "file":{}}')
  473.         data = loadjson(INFO_PATH)
  474.  
  475.     if not "otherfile" in data:
  476.         data["otherfile"] = {}
  477.  
  478.     if not "addfile" in data:
  479.         data["addfile"] = {}
  480.  
  481.     if not "remove_file" in data:
  482.         data["remove_file"] = {}
  483.  
  484.     if not checkStatu(data):
  485.         quit(data)
  486.  
  487.     elif argc == 1 or argv[1] == "help":
  488.         print(HELP)
  489.  
  490.     elif argv[1] == 'install':
  491.  
  492.         if argc < 3:
  493.             Alert.error("You must give a mod name", data)
  494.  
  495.         mod = loadjsonmod(MOD_PATH + argv[2] + '.json')
  496.         if not mod:
  497.             quit(data)
  498.         modname = mod['name']
  499.  
  500.         if modname in data['mod']:
  501.             if mod["version"] == data["mod"][modname]["version"]:
  502.                 Alert.error("Mod '" + modname + "' version " + mod["version"] + " is already install.", data)
  503.             else:
  504.                 Alert.info("Mod '" + modname + "' version " + data["mod"][modname]["version"] + " is already install. Do you want change it for version " + mod["version"] + "?")
  505.                 choice = Alert.input("yes/no:")
  506.                 if choice == "no":
  507.                     quit()
  508.  
  509.                 uninstall(data['mod'][modname], data)
  510.  
  511.         install(mod, data)
  512.  
  513.     elif argv[1] == 'uninstall':
  514.  
  515.         if argc < 3:
  516.             Alert.error("You must give a mod name", data)
  517.  
  518.         mod = loadjsonmod(MOD_PATH + argv[2] + '.json')
  519.         if not mod:
  520.             quit(data)
  521.         if not mod in data['mod']:
  522.             Alert.error(mod + " isn't installed!")
  523.         modname = mod['name']
  524.         uninstall(data['mod'][modname], data)
  525.  
  526.     elif argv[1] == 'uninstall_all':
  527.  
  528.         Alert.info("Restore all files")
  529.         for file in data['file']:
  530.             Alert.info("Restore '" + file + "'")
  531.             copyFile(BCKUP_PATH + file, file)
  532.         for file in data['otherfile']:
  533.             Alert.info("Restore '" + file + "'")
  534.             copyFile(BCKUP_PATH + file, file)
  535.         for file in data['remove_file']:
  536.             Alert.info("Restore '" + file + "'")
  537.             copyBFile(BCKUP_PATH + file, file)
  538.         for file in data['addfile']:
  539.             Alert.info("Remove '" + file + "'")
  540.             os.remove(file)
  541.  
  542.         data['file'] = {}
  543.         data["otherfile"] = {}
  544.         data["addfile"] = {}
  545.         data["remove_file"] = {}
  546.         data['mod'] = {}
  547.  
  548.     elif argv[1] == 'giveall':
  549.         Alert.list([mod + " version " + data['mod'][mod]['version'] + " by " + data['mod'][mod]["author"] for mod in data['mod']])
  550.  
  551.     elif argv[1] == 'valid_mod':
  552.         if argc < 3:
  553.             Alert.error("You must give a mod name", data)
  554.  
  555.         mod = loadjsonmod(MOD_PATH + argv[2] + '.json')
  556.         if mod and checkMod(mod, data):
  557.             Alert.info("Mod is valid")
  558.         else:
  559.             Alert.info("Mod isn't valid!")
  560.  
  561.     elif argv[1] == "info":
  562.         if argc < 3:
  563.             Alert.error("You must give a mod name", data)
  564.  
  565.         Alert.show = False
  566.         mod = loadjsonmod(MOD_PATH + argv[2] + '.json')
  567.         Alert.show = True
  568.  
  569.         if not mod:
  570.             Alert.info("Impossible to load mod.")
  571.         else:
  572.             Alert.info(mod["name"] + " version " + mod["version"] + " by " + mod["author"])
  573.             Alert.list(["\t" + line for line in mod["info"].split("\n")])
  574.         Alert.info()
  575.  
  576.     quit(data)
  577.  
  578. if __name__ == '__main__':
  579.     main(len(sys.argv), sys.argv)
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top