SHARE
TWEET

c3mm.py

7163D Oct 2nd, 2016 80 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # Cossacks 3 (Text) Mod Manager version 1.3.0
  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.0 === #
  7.     Re-writing the script, simplify and normalize data use and adding some comentary
  8.     Now mods and configs files are stored in .json files
  9.     Now mods are check before install
  10.     Now give just the name of the mod without extention (mod in place of mod.json)
  11.     Patching file function are modified to save file in case of an unexpected error during patching
  12.     If the program failed to uninstall a mod, it will restore all corupted files
  13.     New command uninstall_all
  14.     New command giveall, who print all installed mod
  15.     Now logs are saved in "c3mm/logs.txt"
  16.  
  17.     Warning : Don't modify a file (already modded with c3mm) by yourself! I know isn't convenient for modder, so I'm working on a Cossacks3 (Text) Mod Creator.
  18. """
  19.  
  20.  
  21. """
  22. Structur uses
  23. Mod  := {'name':name, 'version':version, 'info':info, 'file':{name => list of (str old, str new)}}
  24. Data := {'mod':{name => mod mod}, 'file':{name => list of str mod}}
  25. """
  26.  
  27. import json, sys, os, time
  28.  
  29. CONFIG_PATH = "c3mm/"
  30. MOD_PATH    = "mod/"
  31. COPY_PATH   = "c3mm/copy/"
  32. BCKUP_PATH  = "c3mm/bckup/"
  33. INFO_PATH   = "c3mm/c3mm.json"
  34. LOG_PATH    = "c3mm/log.txt"
  35. HELP = """
  36. Cossacks3 (text) Mod Manager Version 1.3.0.
  37. Type python c3mm.py action [parameter]
  38.     action:
  39.         install modname   -> intall a mod find by name
  40.         uninstall modname -> unintall a mod find by name
  41.         help              -> show this message
  42.         uninstall_all     -> uninstall all mod
  43. """
  44.  
  45. PATH = [CONFIG_PATH, MOD_PATH, COPY_PATH, BCKUP_PATH]
  46. FILE = [INFO_PATH, LOG_PATH]
  47. for path in PATH:
  48.     try:
  49.         os.mkdir(path)
  50.     except:
  51.         pass
  52. for file in FILE:
  53.     try:
  54.         open(file, 'r')
  55.     except:
  56.         open(file, 'w')
  57.  
  58. class Alert:
  59.     linfo = []
  60.     lerror = []
  61.  
  62.     def info(i):
  63.         Alert.linfo.append(i)
  64.         print(i)
  65.  
  66.     def error(e, data):
  67.         Alert.lerror.append(e)
  68.         print(e)
  69.         quit(data)
  70.  
  71.     def input(m):
  72.         return input(m)
  73.  
  74.     def list(l):
  75.         for i in l:
  76.             print(i)
  77.  
  78. def loadjson(path):
  79.     return json.loads(open(path, 'r').read())
  80.  
  81. def savejson(path, data):
  82.     open(path, "w").write(json.dumps(data))
  83.  
  84. def mkPath(path):
  85.     rpath = ""
  86.     for dir in path.split('/')[:-1]:
  87.         rpath += dir
  88.         try:
  89.             os.mkdir(rpath)
  90.         except:
  91.             pass
  92.         rpath += '/'
  93.  
  94. def copyFile(file, path):
  95.     mkPath(path)
  96.     open(path, "w").write(open(file, 'r').read())
  97.  
  98. def checkMod(mod):
  99.     """
  100.     checkMod function, use to check if a mod is valid
  101.     Mod mod     -> mod to check
  102.     Bool return -> is the mod valid?
  103.     """
  104.     for file in mod['file']:
  105.         Alert.info("Check existence of '" + file + "'")
  106.         try:
  107.             f = open(file, 'r').read()
  108.             Alert.info("'" + file + "' exist.")
  109.         except:
  110.             Alert.info("'" + file + "' don't exist.")
  111.             return False
  112.  
  113.         for old in mod['file'][file]:
  114.             Alert.info("Check exsitence of '" + old + "' in '" + file + "'")
  115.             if not old in f:
  116.                 Alert.info("Not found.")
  117.                 return False
  118.             else:
  119.                 Alert.info("Found.")
  120.     return True
  121.  
  122. def apply(mod):
  123.     """
  124.     apply function, use to modify files
  125.     Mod mod -> mod that contain all modifications
  126.     None return
  127.     """
  128.     mfile = {}
  129.     for file in mod['file']:
  130.         Alert.info("Patching '" + file + '"')
  131.         f = open(file, 'r').read()
  132.  
  133.         #Calculate modifications
  134.         for old in mod['file'][file]:
  135.             new = mod['file'][file][old]
  136.             f = f.replace(old, new)
  137.  
  138.         mfile[file] = f
  139.    
  140.     #Apply mod
  141.     for file in mfile:
  142.         open(file, 'w').write(mfile[file])
  143.  
  144. def install(mod, data):
  145.     """
  146.     install function, use to add a mod.
  147.     Mod mod   -> mod to install
  148.     Data data -> c3mm main data
  149.     None return
  150.     """
  151.     if not checkMod(mod):
  152.         Alert.error("'" + mod['name'] + "' mod version " + mod['version'] + " isn't valid", data)
  153.  
  154.     Alert.info("Install '" + mod['name'] + "' version " + mod['version'])
  155.  
  156.     #Add mod to list of installed mod
  157.     data['mod'][mod['name']] = mod
  158.  
  159.     #Adding mod in list of file modification
  160.     for file in mod['file']:
  161.         if not file in data['file']:
  162.             data['file'][file] = [mod['name']]
  163.             #backup file
  164.             copyFile(file, BCKUP_PATH + file)
  165.         else:
  166.             data['file'][file].append(mod['name'])
  167.  
  168.     apply(mod)
  169.  
  170.     for file in mod['file']:
  171.         #make a save of the file
  172.         copyFile(file, COPY_PATH + file)
  173.  
  174. def uninstall(mod, data):
  175.     """
  176.     uninstall function, use to delete a mod.
  177.     Mod mod   -> mod to uninstall
  178.     Data data -> c3mm main data
  179.     None return
  180.     """
  181.     uninstallmod = mkuninstallmod(mod)
  182.  
  183.     if not checkMod(uninstallmod):
  184.         Alert.info("'" + mod['name'] + "' mod uninstaller isn't valid.")
  185.         Alert.info("Do you want restore all files concerned by this mod?")
  186.         Alert.info("List of mod will uninstalled in this case:")
  187.         modlist = []
  188.         for file in mod['file']:
  189.             for mod in data['file'][file]:
  190.                 if not mod in modlist:
  191.                     modlist.append(mod)
  192.                     Alert.info(mod)
  193.         choice = Alert.chocie("Restore all file? yes/no:")
  194.         if choice == 'no':
  195.             quit(data)
  196.  
  197.         filelist = [file for file in mod['file']]
  198.         for file in filelist:
  199.             Alert("Restore '" + file + "'")
  200.             copyFile(BCKUP_PATH + file, file)
  201.             data['mod'][mod]['file'].remove(file)
  202.  
  203.         for mod in modlist():
  204.             uninstall(mod, data)
  205.  
  206.        
  207.  
  208.     #Delete mod to list of installed mod
  209.     del data['mod'][mod['name']]
  210.  
  211.     #Delete mod of list of file modification
  212.     for file in data['file']:
  213.         if mod['name'] in data['file'][file]:
  214.             data['file'][file].remove(mod['name'])
  215.  
  216.     Alert.info("Uninstall '" + mod['name'] + "' version " + mod['version'])
  217.  
  218.     apply(uninstallmod)
  219.  
  220. def mkuninstallmod(mod):
  221.     """
  222.     mkuninstallmod function, use to make an uninstalator from a mod
  223.     Mod mod    -> mod to uninstall
  224.     Mod return -> uninstalator mod
  225.     """
  226.     uninstallmod = {}
  227.     uninstallmod['file'] = {}
  228.  
  229.     for file in mod['file']:
  230.         uninstallmod['file'][file] = {}
  231.         for old in mod['file'][file]:
  232.             new = mod['file'][file][old]
  233.             #For each modification of mod, inverse new and old
  234.             uninstallmod['file'][file][new] = old
  235.  
  236.     return uninstallmod
  237.  
  238. def checkStatu(data):
  239.     """
  240.     checkStatu funtion, check if a modded file has been modified since last launch of this program
  241.     Data data   -> main data
  242.     Bool return ->
  243.     """
  244.     badfile = []
  245.     #Check all modded file
  246.     for file in data['file']:
  247.         if open(file, 'r').read() != open(COPY_PATH + file, 'r').read():
  248.             Alert.info("File '" + file + "' has been modified since last launch of c3mm.")
  249.             badfile.append(file)
  250.  
  251.     badmod = []
  252.     #Uninstall all mod concerned by these files
  253.     for file in badfile:
  254.         for mod in data['file'][file]:
  255.             if not mod in badmod:
  256.                 badmod.append(mod)
  257.  
  258.     for mod in badmod:
  259.         _mod = data['mod'][mod]
  260.         for file in badfile:
  261.             if file in _mod['file']:
  262.                 del _mod['file'][file]
  263.         uninstall(_mod, data)
  264.  
  265.     return len(badmod) == 0
  266.  
  267. def quit(data):
  268.  
  269.     dfile = []
  270.     for file in data['file']:
  271.         if data['file'][file] == []:
  272.             dfile.append(file)
  273.  
  274.     for file in dfile:
  275.         del data['file'][file]
  276.  
  277.     savejson(INFO_PATH, data)
  278.  
  279.     logs = time.strftime('%D %H:%M\n',time.localtime())
  280.     for info in Alert.linfo:
  281.         logs += info + '\n'
  282.     for error in Alert.lerror:
  283.         logs += error + '\n'
  284.  
  285.     open(LOG_PATH, "a").write(logs)
  286.     exit()
  287.  
  288. def main(argc, argv):
  289.  
  290.     try:
  291.         data = loadjson(INFO_PATH)
  292.     except:
  293.         open(INFO_PATH, "w").write('{"mod":{}, "file":{}}')
  294.         data = loadjson(INFO_PATH)
  295.  
  296.     if not checkStatu(data):
  297.         quit(data)
  298.  
  299.     elif argc == 1 or argv[1] == "help":
  300.         print(HELP)
  301.  
  302.     elif argv[1] == 'install':
  303.  
  304.         if argc < 3:
  305.             Alert.error("You must give a mod name", data)
  306.  
  307.         mod = loadjson(MOD_PATH + argv[2] + '.json')
  308.         modname = mod['name']
  309.  
  310.         if modname in data['mod']:
  311.             if mod["version"] == data["mod"][modname]["version"]:
  312.                 Alert.error("Mod '" + modname + "' version " + mod["version"] + " is already install.", data)
  313.             else:
  314.                 Alert.info("Mod '" + modname + "' version " + data["mod"][modname]["version"] + " is already install. Do you want change it for version " + mod["version"] + "?")
  315.                 choice = Alert.input("yes/no:")
  316.                 if choice == "no":
  317.                     quit()
  318.  
  319.                 uninstall(data['mod'][modname], data)
  320.  
  321.         install(mod, data)
  322.  
  323.     elif argv[1] == 'uninstall':
  324.  
  325.         if argc < 3:
  326.             Alert.error("You must give a mod name", data)
  327.  
  328.         mod = loadjson(MOD_PATH + argv[2] + '.json')
  329.         modname = mod['name']
  330.         uninstall(data['mod'][modname], data)
  331.  
  332.     elif argv[1] == 'uninstall_all':
  333.  
  334.         Alert.info("Restore all files")
  335.         for file in data['file']:
  336.             Alert.info("Restore '" + file + "'")
  337.             copyFile(BCKUP_PATH + file, file)
  338.  
  339.         data['file'] = {}
  340.         data['mod'] = {}
  341.  
  342.     elif argv[1] == 'giveall':
  343.         Alert.list([mod + " version " + data['mod'][mod]['version'] for mod in data['mod']])
  344.  
  345.     quit(data)
  346.  
  347. if __name__ == '__main__':
  348.     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