Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Cossacks 3 Mod Manager version 1.3.8
- # Require python 3.5.x to work : https://python.org/downloads
- # Get all update at http://www.cossacks3.com/forum/index.php?threads/cossacks-3-text-mod-manager.17753
- """
- # === News in 1.3.8 === #
- >Fix bugs
- """
- import json, sys, os, time
- from random import randrange
- from typing import List, Dict
- Mod = {"name":str, "version":str, "info":str, "author":str, "file":{str:{str:str}}, "otherfile":{str:str}, "addfile":{str:str}, "removefile":[str]}
- Data = {"mod":{str:Mod}, "file":{str:[Mod]}, "otherfile":{str:[Mod]}, "remove_file":{str:[Mod]},"addfile":{str:[Mod]}}
- CONFIG_PATH = "c3mm/"
- MOD_PATH = "mod/"
- COPY_PATH = "c3mm/copy/"
- BCKUP_PATH = "c3mm/bckup/"
- INFO_PATH = "c3mm/c3mm.json"
- LOG_PATH = "c3mm/log.txt"
- HELP = """
- Cossacks3 (text) Mod Manager Version 1.3.8.
- Type python c3mm.py action [parameter]
- action:
- install modname -> intall a mod find by name
- uninstall modname -> unintall a mod find by name
- help -> show this message
- uninstall_all -> uninstall all mod
- giveall -> print all installed mods
- valid_mod modname -> check if mod modname is valid
- info modname -> print all informations about mod modname
- """
- PATH = [CONFIG_PATH, MOD_PATH, COPY_PATH, BCKUP_PATH]
- FILE = [INFO_PATH, LOG_PATH]
- for path in PATH:
- try:
- os.mkdir(path)
- except:
- pass
- for file in FILE:
- try:
- open(file, 'r')
- except:
- open(file, 'w')
- class Alert:
- linfo = []
- lerror = []
- show = True
- def info(i):
- if Alert.show:
- Alert.linfo.append(i)
- print(i)
- def error(e, data):
- Alert.lerror.append(e)
- if Alert.show:
- print(e)
- quit(data)
- def input(m):
- return input(m)
- def list(l):
- for i in l:
- if Alert.show:
- print(i)
- def loadjson(path: str) -> str:
- return json.loads(open(path, 'r').read())
- def savejson(path: str, data: {}) -> None:
- open(path, "w").write(json.dumps(data))
- def loadjsonmod(path: str) -> Mod:
- try:
- mod = loadjson(path)
- except:
- Alert.info("Impossible to open " + path)
- return False
- if not "file" in mod:
- mod["file"] = mod["modify_file"]
- if not "otherfile" in mod:
- mod["otherfile"] = mod["replace_file"]
- if not "addfile" in mod:
- mod["addfile"] = mod["add_file"]
- if not "otherfile" in mod:
- mod["otherfile"] = {}
- if not "addfile" in mod:
- mod["addfile"] = {}
- if not "remove_file" in mod:
- mod["remove_file"] = {}
- if not validMod(mod):
- return False
- return mod
- def mkPath(path: str) -> None:
- rpath = ""
- for dir in path.split('/')[:-1]:
- rpath += dir
- try:
- os.mkdir(rpath)
- except:
- pass
- rpath += '/'
- def copyFile(file: str, path: str) -> None:
- mkPath(path)
- open(path, "w").write(open(file, 'r').read())
- def copyBFile(file: str, path: str) -> None:
- mkPath(path)
- open(path, "wb").write(open(file, 'rb').read())
- def checkMod(mod: Mod, data: Data) -> bool:
- """
- checkMod function, use to check if a mod is valid
- Mod mod -> mod to check
- Bool return -> is the mod valid?
- """
- for file in mod['file']:
- Alert.info("Check existence of '" + file + "'")
- try:
- f = open(file, 'r').read()
- Alert.info("'" + file + "' exist.")
- except:
- Alert.info("'" + file + "' don't exist.")
- return False
- for old in mod['file'][file]:
- Alert.info("Check exsitence of '" + old + "' in '" + file + "'")
- if not old in f:
- Alert.info("Not found.")
- return False
- else:
- Alert.info("Found.")
- for file in mod["otherfile"]:
- Alert.info("Check existence of '" + file + "'")
- try:
- open(file, 'r')
- Alert.info("'" + file + "' exist.")
- except:
- Alert.info("'" + file + "' don't exist.")
- return False
- Alert.info("Check existence of '" + MOD_PATH + mod["otherfile"][file] + "'")
- try:
- open(MOD_PATH + mod["otherfile"][file], 'r')
- Alert.info("'" + MOD_PATH + mod["otherfile"][file] + "' exist.")
- except:
- Alert.info("'" + MOD_PATH + mod["otherfile"][file] + "' don't exist.")
- return False
- if file in data["otherfile"]:
- Alert.info(file + " is already modified by " + data["otherfile"][file][0])
- Alert.info("You have to uninstall " + data["otherfile"][file][0] + " to install " + mod['name'])
- return False
- for file in mod["addfile"]:
- Alert.info("Check existence of '" + MOD_PATH + mod["addfile"][file] + "'")
- try:
- open(MOD_PATH + mod["addfile"][file], 'r')
- Alert.info("'" + MOD_PATH + mod["addfile"][file] + "' exist.")
- except:
- Alert.info("'" + MOD_PATH + mod["addfile"][file] + "' don't exist.")
- return False
- if file in data["addfile"]:
- Alert.info(file + " is already added by " + data["addfile"][file][0])
- Alert.info("You have to uninstall " + data["addfile"][file][0] + " to install " + mod['name'])
- return False
- return True
- def validMod(mod: Mod) -> bool:
- """
- validMod function, assert not error occured when install mod
- Mod mod -> mod to check
- Bool return
- """
- for field in ['name', 'info', 'file', 'version', 'author']:
- if not field in mod:
- Alert.info("Missing field '" + field + "'")
- return False
- if not type(mod['file']) == type({}):
- Alert.info("Wrong data mod")
- return False
- for file in mod['file']:
- if not type(mod['file'][file]) == type({}):
- Alert.info("Wrong data mod")
- return False
- try:
- for old in mod['file'][file]:
- new = mod['file'][file][old]
- if not type(old) == type("") or not type(new) == type(""):
- Alert.info("Wrong data mod")
- return False
- except:
- Alert.info("Wrong data mod")
- return False
- if not type(mod['otherfile']) == type({}):
- Alert.info("Wrong data mod")
- return False
- if not type(mod['addfile']) == type({}):
- Alert.info("Wrong data mod")
- return False
- return True
- def apply(mod: Mod) -> None:
- """
- apply function, use to modify files
- Mod mod -> mod that contain all modifications
- None return
- """
- mfile = {}
- for file in mod['file']:
- Alert.info("Calculate'" + file + '"')
- f = open(file, 'r').read()
- #Calculate modifications
- for old in mod['file'][file]:
- new = mod['file'][file][old]
- f = f.replace(old, new)
- mfile[file] = f
- #Apply mod
- for file in mfile:
- Alert.info("Patching '" + file + '"')
- open(file, 'w').write(mfile[file])
- for file in mod["otherfile"]:
- Alert.info("Replace '" + file+ "'")
- copyBFile(MOD_PATH + mod["otherfile"][file], file)
- for file in mod["addfile"]:
- Alert.info("Add '" + file + "'")
- copyBFile(MOD_PATH + mod["addfile"][file], file)
- for file in mod["remove_file"]:
- Alert.info("Remove'" + file + "'")
- os.remove(file)
- def install(mod: Mod, data: Data) -> None:
- """
- install function, use to add a mod.
- Mod mod -> mod to install
- Data data -> c3mm main data
- None return
- """
- if not checkMod(mod, data):
- Alert.error("'" + mod['name'] + "' mod version " + mod['version'] + " isn't valid", data)
- Alert.info("Install '" + mod['name'] + "' version " + mod['version'])
- #Add some "signature"
- for file in mod['file']:
- for old in mod['file'][file]:
- mod['file'][file][old] = mod['file'][file][old] + "//" + str(randrange(100000, 999999))
- #Add mod to list of installed mod
- data['mod'][mod['name']] = mod
- #Adding mod in list of file modification
- for file in mod['file']:
- if not file in data['file']:
- data['file'][file] = [mod['name']]
- #backup file
- copyFile(file, BCKUP_PATH + file)
- else:
- data['file'][file].append(mod['name'])
- for file in mod["otherfile"]:
- if not file in data['otherfile']:
- data['otherfile'][file] = [mod['name']]
- #backup file
- copyBFile(file, BCKUP_PATH + file)
- else:
- data['otherfile'][file].append(mod['name'])
- for file in mod["addfile"]:
- if not file in data['otherfile']:
- data['addfile'][file] = [mod['name']]
- else:
- data['addfile'][file].append(mod['name'])
- for file in mod["remove_file"]:
- copyBFile(file, BCKUP_PATH + file)
- data["remove_file"][file] = [mod['name']]
- apply(mod)
- for file in mod['file']:
- #make a save of the file
- copyFile(file, COPY_PATH + file)
- def uninstall(mod: Mod, data: Data) -> None:
- """
- uninstall function, use to delete a mod.
- Mod mod -> mod to uninstall
- Data data -> c3mm main data
- None return
- """
- uninstallmod = mkuninstallmod(mod)
- if not checkMod(uninstallmod, data):
- Alert.info("'" + mod['name'] + "' mod uninstaller isn't valid.")
- Alert.info("Do you want restore all files concerned by this mod?")
- Alert.info("List of mod will uninstalled in this case:")
- modlist = []
- for file in mod['file']:
- for mod in data['file'][file]:
- if not mod in modlist:
- modlist.append(mod)
- Alert.info(mod)
- choice = Alert.input("Restore all file? yes/no:")
- if choice == 'no':
- quit(data)
- filelist = [file for file in mod['file']]
- for file in filelist:
- Alert("Restore '" + file + "'")
- copyFile(BCKUP_PATH + file, file)
- for mod in modlist:
- if file in mod["file"]:
- del mod["file"][file]
- if file in mod["otherfile"]:
- del mod["otherfile"][file]
- if file in mod["addfile"]:
- del mod["addfile"][file]
- if file in mod["remove_file"]:
- mod["remove_file"].remove("file")
- for mod in modlist:
- uninstall(mod, data)
- #Delete mod to list of installed mod
- del data['mod'][mod['name']]
- #Delete mod of list of file modification
- for file in data['file']:
- if mod['name'] in data['file'][file]:
- data['file'][file].remove(mod['name'])
- Alert.info("Uninstall '" + mod['name'] + "' version " + mod['version'])
- for file in mod["otherfile"]:
- Alert.info("Restore " + file)
- copyBFile(BCKUP_PATH + file, file)
- del data["otherfile"][file]
- for file in mod["addfile"]:
- Alert.info("Delete " + file)
- os.remove(file)
- del data["addfile"][file]
- for file in mod["remove_file"]:
- Alert.info("Restore " + file)
- copyBFile(BCKUP_PATH + file, file)
- del data["remove_file"][file]
- apply(uninstallmod)
- def mkuninstallmod(mod: Mod) -> None:
- """
- mkuninstallmod function, use to make an uninstalator from a mod
- Mod mod -> mod to uninstall
- Mod return -> uninstalator mod
- """
- uninstallmod = {}
- uninstallmod['file'] = {}
- for file in mod['file']:
- uninstallmod['file'][file] = {}
- for old in mod['file'][file]:
- new = mod['file'][file][old]
- #For each modification of mod, inverse new and old
- uninstallmod['file'][file][new] = old
- uninstallmod["otherfile"] = {}
- uninstallmod["addfile"] = {}
- uninstallmod["remove_file"] = {}
- return uninstallmod
- def checkStatu(data: Data) -> bool:
- """
- checkStatu funtion, check if a modded file has been modified since last launch of this program
- Data data -> main data
- Bool return ->
- """
- badfile = []
- #Check all modded file
- for file in data['file']:
- if open(file, 'r').read() != open(COPY_PATH + file, 'r').read():
- Alert.info("File '" + file + "' has been modified since last launch of c3mm.")
- badfile.append(file)
- badotherfile = []
- for file in data["otherfile"]:
- if open(file, 'rb').read() != open(BCKUP_PATH + file, 'rb').read():
- Alert.info("File '" + file + "' has been modified since last launch of c3mm.")
- badotherfile.append(file)
- badmod = []
- #Uninstall all mod concerned by these files
- for file in badfile:
- for mod in data['file'][file]:
- if not mod in badmod and not checkMod(mkuninstallmod(data['mod'][mod]), data):
- badmod.append(mod)
- for file in badotherfile:
- if not data["otherfile"][file][0] in badmod:
- badmod.append(data["otherfile"][file][0])
- for mod in badmod:
- _mod = data['mod'][mod]
- for file in badfile:
- if file in _mod['file']:
- del _mod['file'][file]
- uninstall(_mod, data)
- #make a new copy of all modified files
- for file in badfile:
- copyFile(file, COPY_PATH + file)
- return len(badmod) == 0
- def quit(data: Data) -> None:
- """
- Save all data before exit the program
- """
- dfile = []
- for file in data['file']:
- if data['file'][file] == []:
- dfile.append(file)
- for file in dfile:
- del data['file'][file]
- savejson(INFO_PATH, data)
- logs = time.strftime('%D %H:%M\n',time.localtime())
- for info in Alert.linfo:
- logs += info + '\n'
- for error in Alert.lerror:
- logs += error + '\n'
- open(LOG_PATH, "a").write(logs)
- exit()
- def main(argc: int, argv: List[str]) -> None:
- try:
- data = loadjson(INFO_PATH)
- except:
- open(INFO_PATH, "w").write('{"mod":{}, "file":{}}')
- data = loadjson(INFO_PATH)
- if not "otherfile" in data:
- data["otherfile"] = {}
- if not "addfile" in data:
- data["addfile"] = {}
- if not "remove_file" in data:
- data["remove_file"] = {}
- if not checkStatu(data):
- quit(data)
- elif argc == 1 or argv[1] == "help":
- print(HELP)
- elif argv[1] == 'install':
- if argc < 3:
- Alert.error("You must give a mod name", data)
- mod = loadjsonmod(MOD_PATH + argv[2] + '.json')
- if not mod:
- quit(data)
- modname = mod['name']
- if modname in data['mod']:
- if mod["version"] == data["mod"][modname]["version"]:
- Alert.error("Mod '" + modname + "' version " + mod["version"] + " is already install.", data)
- else:
- Alert.info("Mod '" + modname + "' version " + data["mod"][modname]["version"] + " is already install. Do you want change it for version " + mod["version"] + "?")
- choice = Alert.input("yes/no:")
- if choice == "no":
- quit()
- uninstall(data['mod'][modname], data)
- install(mod, data)
- elif argv[1] == 'uninstall':
- if argc < 3:
- Alert.error("You must give a mod name", data)
- mod = loadjsonmod(MOD_PATH + argv[2] + '.json')
- if not mod:
- quit(data)
- if not mod["name"] in data['mod'].keys():
- Alert.error(mod + " isn't installed!")
- modname = mod['name']
- uninstall(data['mod'][modname], data)
- elif argv[1] == 'uninstall_all':
- Alert.info("Restore all files")
- for file in data['file']:
- Alert.info("Restore '" + file + "'")
- copyFile(BCKUP_PATH + file, file)
- for file in data['otherfile']:
- Alert.info("Restore '" + file + "'")
- copyFile(BCKUP_PATH + file, file)
- for file in data['remove_file']:
- Alert.info("Restore '" + file + "'")
- copyBFile(BCKUP_PATH + file, file)
- for file in data['addfile']:
- Alert.info("Remove '" + file + "'")
- os.remove(file)
- data['file'] = {}
- data["otherfile"] = {}
- data["addfile"] = {}
- data["remove_file"] = {}
- data['mod'] = {}
- elif argv[1] == 'giveall':
- Alert.list([mod + " version " + data['mod'][mod]['version'] + " by " + data['mod'][mod]["author"] for mod in data['mod']])
- elif argv[1] == 'valid_mod':
- if argc < 3:
- Alert.error("You must give a mod name", data)
- mod = loadjsonmod(MOD_PATH + argv[2] + '.json')
- if mod and checkMod(mod, data):
- Alert.info("Mod is valid")
- else:
- Alert.info("Mod isn't valid!")
- elif argv[1] == "info":
- if argc < 3:
- Alert.error("You must give a mod name", data)
- Alert.show = False
- mod = loadjsonmod(MOD_PATH + argv[2] + '.json')
- Alert.show = True
- if not mod:
- Alert.info("Impossible to load mod.")
- else:
- Alert.info(mod["name"] + " version " + mod["version"] + " by " + mod["author"])
- Alert.list(["\t" + line for line in mod["info"].split("\n")])
- Alert.info()
- quit(data)
- if __name__ == '__main__':
- main(len(sys.argv), sys.argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement