def __init__(self, fullInstallConfiguration, extractDirectlyToGameDirectory):
		# type: (installConfiguration.FullInstallConfiguration, bool) -> None

		"""
		Installer Init

		:param str directory: The directory of the game
		:param dict info: The info dictionary from server JSON file for the requested target
		"""
		self.info = fullInstallConfiguration
		self.directory = fullInstallConfiguration.installPath

		if common.Globals.IS_MAC:
			self.dataDirectory = path.join(self.directory, "Contents/Resources/Data")
		else:
			self.dataDirectory = path.join(self.directory, self.info.subModConfig.dataName)

		logger.getGlobalLogger().trySetSecondaryLoggingPath(
			os.path.join(self.dataDirectory, common.Globals.LOG_BASENAME)
		)

		self.assetsDir = path.join(self.dataDirectory, "StreamingAssets")

		possibleSteamPaths = [
			path.join(self.directory, "steam_api.dll"),
			path.join(self.directory, "Contents/Plugins/CSteamworks.bundle"),
			path.join(self.directory, "libsteam_api.so")
		]

		self.isSteam = False
		for possibleSteamPath in possibleSteamPaths:
			if path.exists(possibleSteamPath):
				self.isSteam = True

		self.downloadDir = self.info.subModConfig.modName + " Downloads"
		self.extractDir = self.directory if extractDirectlyToGameDirectory else (self.info.subModConfig.modName + " Extraction")

		self.fileVersionManager = fileVersionManagement.VersionManager(
			subMod=self.info.subModConfig,
			modFileList=self.info.buildFileListSorted(datadir=self.dataDirectory),
			localVersionFolder=self.directory)

		modFileList = self.fileVersionManager.getFilesRequiringUpdate()
		self.downloaderAndExtractor = common.DownloaderAndExtractor(modFileList=modFileList,
		                                                            downloadTempDir=self.downloadDir,
		                                                            extractionDir=self.extractDir)

		self.downloaderAndExtractor.buildDownloadAndExtractionList()

		parser = installConfiguration.ModOptionParser(self.info)

		for opt in parser.downloadAndExtractOptionsByPriority:
			self.downloaderAndExtractor.addItemManually(
				url=opt.url,
				extractionDir=os.path.join(self.extractDir, opt.relativeExtractionPath),
			)

		self.downloaderAndExtractor.printPreview()
Exemple #2
0
            def getInitStatus(requestData):
                initError = None
                if self.initErrorMessage is not None:
                    initError = self.initErrorMessage
                    self.initErrorMessage = None

                return {
                    'initCompleted': self.initCompleted,
                    'initErrorMessage': initError,
                    'consoleLines':
                    logger.getGlobalLogger().threadSafeReadAll()
                }
Exemple #3
0
 def statusUpdate(requestData):
     return [
         _loggerMessageToStatusDict(x)
         for x in logger.getGlobalLogger().threadSafeReadAll()
     ]
Exemple #4
0
def mainUmineko(conf):
    # type: (installConfiguration.FullInstallConfiguration) -> None
    logger.getGlobalLogger().trySetSecondaryLoggingPath(
        os.path.join(conf.installPath, common.Globals.LOG_BASENAME))

    isQuestionArcs = 'question' in conf.subModConfig.modName.lower()

    print("CONFIGURATION:")
    print("Install path", conf.installPath)
    print("Mod Option", conf.subModConfig.modName)
    print("Sub Option", conf.subModConfig.subModName)
    print("Is Question Arcs", isQuestionArcs)
    print("Is Windows", common.Globals.IS_WINDOWS)
    print("Is Linux", common.Globals.IS_LINUX)
    print("Is Mac", common.Globals.IS_MAC)

    ####################################### VALIDATE AND PREPARE FOLDERS ###############################################
    # do a quick verification that the directory is correct before starting installer
    if not os.path.isfile(os.path.join(conf.installPath, "arc.nsa")):
        raise Exception(
            "ERROR - wrong game path. Installation Stopped.\n"
            "There is no 'arc.nsa' in the game folder. Are you sure the correct game folder was selected?"
        )

    for filename in os.listdir(conf.installPath):
        # Stop the user installing the mod on pirated versions of the game.
        # Use SHA256 hash of the lowercase filename to avoid listing the website names in our source code.
        if hashlib.sha256(filename.lower().encode('utf-8')).hexdigest() in [
                '2c02ec6f6de9281a68975257a477e8f994affe4eeaaf18b0b56b4047885461e0',
                '4fae41c555fe50034065e59ce33a643c1d93ee846221ecc5756f00e039035076',
        ]:
            raise Exception(
                "\nInstall Failed - The {} mod is not compatible with the pirated version of the game\n"
                "(Detected file [{}]) Please install the latest Steam or Mangagamer release."
                .format(conf.subModConfig.modName, filename))

        # Stop the user installing the mod on the old/original Japanese game.
        # This probably means the user placed a fake identifier (eg the game exe) in the old game's folder.
        if filename == 'snow.dll':
            raise Exception(
                "\nInstall Failed - The {} mod is not compatible with the old/original Japanese game.\n"
                "(Detected [{}]) Please install the latest Steam or Mangagamer release."
                .format(conf.subModConfig.modName, filename))

    # Create aliases for the temp directories, and ensure they exist beforehand
    downloadTempDir = conf.subModConfig.modName + " Downloads"

    if os.path.isdir(downloadTempDir):
        print(
            "Information: Temp directories already exist - continued or overwritten install"
        )

    common.makeDirsExistOK(downloadTempDir)

    ######################################## Query and Download Files ##################################################
    fileVersionManager = fileVersionManagement.VersionManager(
        subMod=conf.subModConfig,
        modFileList=conf.buildFileListSorted(),
        localVersionFolder=conf.installPath)

    filesRequiringUpdate = fileVersionManager.getFilesRequiringUpdate()
    print("Perform Full Install: {}".format(
        fileVersionManager.fullUpdateRequired()))
    downloaderAndExtractor = common.DownloaderAndExtractor(
        filesRequiringUpdate,
        downloadTempDir,
        conf.installPath,
        downloadProgressAmount=45,
        extractionProgressAmount=45)
    downloaderAndExtractor.buildDownloadAndExtractionList()

    parser = installConfiguration.ModOptionParser(conf)

    for opt in parser.downloadAndExtractOptionsByPriority:
        downloaderAndExtractor.addItemManually(
            url=opt.url,
            extractionDir=os.path.join(conf.installPath,
                                       opt.relativeExtractionPath),
        )

    downloaderAndExtractor.printPreview()

    # Delete all non-checksummed files from the download folder, if they exist
    print("Removing non-checksummed downloads:")
    deleteExtractablesFromFolder(
        downloadTempDir,
        [x for x in downloaderAndExtractor.extractList if not x.fromMetaLink])

    downloaderAndExtractor.download()

    # Treat the install as "started" once the "download" stage is complete
    fileVersionManager.saveVersionInstallStarted()

    ###################### Backup/clear the .exe and script files, and old graphics ####################################
    backupOrRemoveFiles(conf.installPath)

    if fileVersionManager.fullUpdateRequired():
        # Remove old graphics from a previous installation, as they can conflict with the voice-only patch
        graphicsPathsToDelete = [
            os.path.join(conf.installPath, x) for x in ['big', 'bmp', 'en']
        ]

        for folderPath in graphicsPathsToDelete:
            if os.path.exists(folderPath):
                print("Deleting {}".format(folderPath))
                try:
                    shutil.rmtree(folderPath)
                except:
                    print("WARNING: failed to remove folder {}".format(
                        folderPath))

    ######################################## Extract Archives ##########################################################
    downloaderAndExtractor.extract()

    ############################################# FIX .ARC FILE NAMING #################################################
    # Steam release has arc files labeled arc.nsa, arc1.nsa, arc2.nsa, arc3.nsa.
    # Mangagamer release has only one arc file labeled arc.nsa
    # Generate dummy arc1-arc3 nsa files if they don't already exist, so the game can find the arc4.nsa that we provide
    for i in range(1, 4):
        nsaPath = os.path.join(conf.installPath, 'arc{}.nsa'.format(i))
        if not os.path.exists(nsaPath):
            print(
                ".nsa archive check: Generating dummy [{}] as it does not already exist (Mangagamer)"
                .format(nsaPath))
            with open(nsaPath, 'wb') as dummyNSAFile:
                dummyNSAFile.write(bytes([0, 0, 0, 0, 0, 6]))
        else:
            print(".nsa archive check: [{}] already exists (Steam)".format(
                nsaPath))

    #################################### MAKE EXECUTABLE, WRITE HELPER SCRIPTS #########################################
    gameBaseName = "Umineko5to8"
    if isQuestionArcs:
        gameBaseName = "Umineko1to4"

    if common.Globals.IS_MAC:
        print("Un-quarantining game executable")
        subprocess.call([
            "xattr", "-d", "com.apple.quarantine",
            os.path.join(conf.installPath, gameBaseName + ".app")
        ])

    print("Creating debug mode batch files")
    # write batch file to let users launch game in debug mode
    with open(os.path.join(conf.installPath, gameBaseName + "_DebugMode.bat"),
              'w') as f:
        f.writelines([gameBaseName + ".exe --debug\n", "pause"])

    #make the following files executable, if they exist
    makeExecutableList = [
        os.path.join(conf.installPath, "Umineko1to4"),
        os.path.join(conf.installPath,
                     "Umineko1to4.app/Contents/MacOS/umineko4"),
        os.path.join(conf.installPath, "Umineko5to8"),
        os.path.join(conf.installPath,
                     "Umineko5to8.app/Contents/MacOS/umineko8")
    ]

    print("Making executables ... executable")
    for exePath in makeExecutableList:
        if os.path.exists(exePath):
            common.makeExecutable(exePath)

    # Patched game uses mysav folder, which Steam can't see so can't get incompatible saves by accident.
    # Add batch file which reverses this behaviour by making a linked folder from (saves->mysav)
    print("Creating EnableSteamSync.bat")
    with open(os.path.join(conf.installPath, "EnableSteamSync.bat"), 'w') as f:
        f.write("""
if exist saves (
    ren saves backup-saves
    mklink /J saves mysav
) else (
    mklink /J saves mysav
)
pause
""")

    # For now, don't copy save data

    steamGridExtractor.extractSteamGrid()
    fileVersionManager.saveVersionInstallFinished()

    if not parser.keepDownloads:
        print("Removing temporary downloads:")
        deleteExtractablesFromFolder(downloadTempDir,
                                     downloaderAndExtractor.extractList)

    commandLineParser.printSeventhModStatusUpdate(
        100, "Umineko install script completed!")
Exemple #5
0
	def __init__(self, fullInstallConfiguration, extractDirectlyToGameDirectory, modOptionParser, forcedExtractDirectory=None):
		# type: (installConfiguration.FullInstallConfiguration, bool, installConfiguration.ModOptionParser, Optional[str]) -> None

		"""
		Installer Init

		:param str directory: The directory of the game
		:param dict info: The info dictionary from server JSON file for the requested target
		"""
		self.forcedExtractDirectory = forcedExtractDirectory
		self.info = fullInstallConfiguration
		self.directory = fullInstallConfiguration.installPath
		self.dataDirectory = self.getDataDirectory(self.directory)
		self.clearScripts = False  # If true, will clear CompiledUpdateScripts before extraction stage
		self.languagePatchIsEnabled = False  # True if at least one language patch will be installed

		logger.getGlobalLogger().trySetSecondaryLoggingPath(
			os.path.join(self.dataDirectory, common.Globals.LOG_BASENAME)
		)

		self.assetsDir = path.join(self.dataDirectory, "StreamingAssets")

		possibleSteamPaths = [
			path.join(self.directory, "steam_api.dll"),
			path.join(self.directory, "Contents/Plugins/CSteamworks.bundle"),
			path.join(self.directory, "libsteam_api.so")
		]

		self.isSteam = False
		for possibleSteamPath in possibleSteamPaths:
			if path.exists(possibleSteamPath):
				self.isSteam = True

		self.downloadDir = self.info.subModConfig.modName + " Downloads"
		self.extractDir = self.directory if extractDirectlyToGameDirectory else (self.info.subModConfig.modName + " Extraction")
		if forcedExtractDirectory is not None:
			self.extractDir = forcedExtractDirectory

		self.fileVersionManager = fileVersionManagement.VersionManager(
			subMod=self.info.subModConfig,
			modFileList=self.info.buildFileListSorted(datadir=self.dataDirectory),
			localVersionFolder=self.directory)

		modFileList = self.fileVersionManager.getFilesRequiringUpdate()

		for modFile in modFileList:
			if modFile.name == 'script':
				self.clearScripts = True

		self.info.subModConfig.printEnabledOptions()
		self.downloaderAndExtractor = common.DownloaderAndExtractor(modFileList=modFileList,
		                                                            downloadTempDir=self.downloadDir,
		                                                            extractionDir=self.extractDir)

		self.downloaderAndExtractor.buildDownloadAndExtractionList()

		self.optionParser = modOptionParser

		for opt in self.optionParser.downloadAndExtractOptionsByPriority:
			self.downloaderAndExtractor.addItemManually(
				url=opt.url,
				extractionDir=os.path.join(self.extractDir, opt.relativeExtractionPath),
			)
			if opt.group == 'Alternate Languages':
				self.clearScripts = True
				self.languagePatchIsEnabled = True

		self.downloaderAndExtractor.printPreview()
Exemple #6
0
def main(conf):
    # type: (installConfiguration.FullInstallConfiguration) -> None
    logger.getGlobalLogger().trySetSecondaryLoggingPath(
        os.path.join(conf.installPath, common.Globals.LOG_BASENAME))

    print("CONFIGURATION:")
    print("Install path", conf.installPath)
    print("Mod Option", conf.subModConfig.modName)
    print("Sub Option", conf.subModConfig.subModName)
    print("Is Windows", common.Globals.IS_WINDOWS)
    print("Is Linux", common.Globals.IS_LINUX)
    print("Is Mac", common.Globals.IS_MAC)

    if not common.Globals.IS_WINDOWS:
        raise Exception(
            "Error: Umineko Hane Mod (onscripter version) is not supported on Mac or Linux!"
        )

    ####################################### VALIDATE AND PREPARE FOLDERS ###############################################
    # do a quick verification that the directory is correct before starting installer
    if not os.path.isfile(os.path.join(conf.installPath, "arc.nsa")):
        raise Exception(
            "ERROR - wrong game path. Installation Stopped.\n"
            "There is no 'arc.nsa' in the game folder. Are you sure the correct game folder was selected?"
        )

    # Create aliases for the temp directories, and ensure they exist beforehand
    downloadTempDir = conf.subModConfig.modName + " Downloads"

    if os.path.isdir(downloadTempDir):
        print(
            "Information: Temp directories already exist - continued or overwritten install"
        )

    common.makeDirsExistOK(downloadTempDir)

    ######################################## DOWNLOAD, BACKUP, THEN EXTRACT ############################################
    fileVersionManager = fileVersionManagement.VersionManager(
        subMod=conf.subModConfig,
        modFileList=conf.buildFileListSorted(),
        localVersionFolder=conf.installPath)

    filesRequiringUpdate = fileVersionManager.getFilesRequiringUpdate()
    conf.subModConfig.printEnabledOptions()
    downloaderAndExtractor = common.DownloaderAndExtractor(
        filesRequiringUpdate,
        downloadTempDir,
        conf.installPath,
        downloadProgressAmount=45,
        extractionProgressAmount=45)
    downloaderAndExtractor.buildDownloadAndExtractionList()

    parser = installConfiguration.ModOptionParser(conf)

    for opt in parser.downloadAndExtractOptionsByPriority:
        downloaderAndExtractor.addItemManually(
            url=opt.url,
            extractionDir=os.path.join(conf.installPath,
                                       opt.relativeExtractionPath),
        )

    downloaderAndExtractor.printPreview()

    # Download files
    # Delete all non-checksummed files from the download folder, if they exist
    for extractableItem in downloaderAndExtractor.extractList:
        extractableItemPath = os.path.join(downloadTempDir,
                                           extractableItem.filename)
        if not extractableItem.fromMetaLink and os.path.exists(
                extractableItemPath):
            print("Removing existing non-checksummed download: [{}]".format(
                extractableItemPath))
            os.remove(extractableItemPath)

    downloaderAndExtractor.download()

    # Extract files
    fileVersionManager.saveVersionInstallStarted()
    downloaderAndExtractor.extract()

    fileVersionManager.saveVersionInstallFinished()
    commandLineParser.printSeventhModStatusUpdate(
        100, "Umineko Hane install script completed!")