Ejemplo n.º 1
0
        private void Initialize(DirectoryInfo directory, uint level, ProgressDelegate Progress)
        {
            FileSystemInfo[] children = directory.GetFileSystemInfos();

            if (children != null)
            {
                Progress?.Invoke(this, new ProgressEventArgs(0, children.Length));
                int childNumberLength = children.Length.ToString().Length;
                for (int i = 0; i < children.Length; i++)
                {
                    IsoFolderElement child;
                    string           childNumber = string.Format("{0:D" + childNumberLength.ToString() + "}", i);
                    if (children[i].GetType() == typeof(DirectoryInfo))
                    {
                        child = new IsoDirectory(this, (DirectoryInfo)children[i], level + 1, childNumber);
                    }
                    else
                    {
                        child = new IsoFile((FileInfo)children[i], childNumber);
                    }

                    Children.Add(child);

                    Progress?.Invoke(this, new ProgressEventArgs(i));
                }
            }
            Children.Sort();

            CalculateSize();
        }
Ejemplo n.º 2
0
        private void Initialize(DirectoryInfo directory, UInt32 level, ProgressDelegate Progress)
        {
            Level = level;

            FileSystemInfo[] children = directory.GetFileSystemInfos();

            if (children != null)
            {
                Progress?.Invoke(this, new ProgressEventArgs(0, children.Length));

                int childNumberLength = children.Length.ToString().Length;
                for (int i = 0; i < children.Length; i++)
                {
                    string childNumber = String.Format("{0:D" + childNumberLength.ToString() + "}", i);

                    Children.Add(children[i] is DirectoryInfo ? (IsoFolderElement)
                                 new IsoDirectory(this, (DirectoryInfo)children[i], level + 1, childNumber) :
                                 new IsoFile((FileInfo)children[i], childNumber));

                    Progress?.Invoke(this, new ProgressEventArgs(i));
                }
            }

            Children.Sort();

            CalculateSize();
        }
Ejemplo n.º 3
0
        public static void CopyMod(string sourceFolder, string destinationFolder, string modId, ProgressDelegate progressCallback)
        {
            if (string.IsNullOrWhiteSpace(sourceFolder))
            {
                throw new DirectoryNotFoundException($"Source folder must be specified.");
            }
            if (!Directory.Exists(sourceFolder))
            {
                throw new DirectoryNotFoundException($"Source folder was not found.\r\n{sourceFolder}");
            }
            if (string.IsNullOrWhiteSpace(destinationFolder))
            {
                throw new DirectoryNotFoundException($"Destination folder must be specified.");
            }

            var modFileName  = $"{modId}.pak";
            var modFile      = IOUtils.NormalizePath(Path.Combine(destinationFolder, modFileName));
            var timeFileName = $"{modId}.txt";
            var timeFile     = IOUtils.NormalizePath(Path.Combine(destinationFolder, timeFileName));

            progressCallback?.Invoke(0, "Deleting existing mod files.");

            // delete the server mod file.
            if (File.Exists(modFile))
            {
                File.Delete(modFile);
            }
            if (File.Exists(timeFile))
            {
                File.Delete(timeFile);
            }

            progressCallback?.Invoke(0, "Copying mod files.");

            if (string.IsNullOrWhiteSpace(destinationFolder) || !Directory.Exists(destinationFolder))
            {
                Directory.CreateDirectory(destinationFolder);
            }

            // update the mod files from the cache.
            foreach (var sourceFile in Directory.GetFiles(sourceFolder, "*.pak", SearchOption.TopDirectoryOnly))
            {
                File.Copy(sourceFile, modFile, true);
            }

            // copy the last updated file.
            var fileName = IOUtils.NormalizePath(Path.Combine(sourceFolder, Config.Default.LastUpdatedTimeFile));

            if (File.Exists(fileName))
            {
                progressCallback?.Invoke(0, "Copying mod version file.");

                File.Copy(fileName, timeFile, true);
            }
        }
Ejemplo n.º 4
0
        public async Task ToDatabase() //method to load all data from server
        {
            try
            {
                if (Application.Current.Properties.ContainsKey("AllMedia")) //delete media if exists
                {
                    var mediaToDelete = Utils.DeserializeFromJson <List <Media> >((string)Application.Current.Properties["AllMedia"]).FindAll(m => m.Type == "image");
                    foreach (var media in mediaToDelete)
                    {
                        await FileSystem.Current.GetFileFromPathAsync(media.Url).Result.DeleteAsync();
                    }
                }
            }
            catch { }
            Process = 0;
            OnProgressEvent?.Invoke(Process);
            _risks     = new List <Risk>();
            _sections  = new List <Section>();
            _mediaList = new List <Media>();
            _locations = new List <Location>();
            var             sectsAPI = new List <SectionAPI>();
            List <Location> temp_locs;

            foreach (var lang in _langs)
            {
                temp_locs = (await _api.GetAll(lang)).Locations;
                foreach (var loc in temp_locs)
                {
                    _locations.Add(new Location
                    {
                        Name      = loc.Name,
                        Content   = loc.Content,
                        Lang      = lang,
                        Latitude  = loc.Latitude,
                        Longitude = loc.Longitude,
                        Id_l      = loc.Id_l
                    });
                }
                sectsAPI = (await _api.GetAll(lang)).Sections;
                Process  = 0.1 * (1 / ((double)_langs.Length));
                OnProgressEvent?.Invoke(Process);
                int n = sectsAPI.Count;
                foreach (var sAPI in sectsAPI)
                {
                    if (!sAPI.Name.StartsWith("service"))
                    {
                        DecompSectionAPI(lang, "null", sAPI, ref _sections, ref _risks, ref _mediaList);
                        Process += (0.7 / (double)n) * (1 / ((double)_langs.Length));
                        OnProgressEvent?.Invoke(Process);
                    }
                }
            }
            UploadAll();
        }
Ejemplo n.º 5
0
 public static void UpdateProgresssBar(double progress, ProgressDelegate progressDelegate)
 {
     if (progressDelegate != null)
     {
         progressDelegate.Invoke(progress);
     }
 }
 public static void UpdateProgresssBar(double progress, ProgressDelegate progressDelegate)
 {
     if (progressDelegate != null)
     {
         progressDelegate.Invoke(progress);
     }
 }
Ejemplo n.º 7
0
 public override void Write(OkBuffer p_source, long p_byteCount)
 {
     _currentLength += p_byteCount;
     // 回调进度
     _progressListener?.Invoke(p_byteCount, _currentLength, _totalLength);
     base.Write(p_source, p_byteCount);
 }
Ejemplo n.º 8
0
        public void Load(ProgressDelegate onProgress)
        {
            if (IsLoaded)
            {
                if (_firstLoadOccured)
                {
                    Unload();
                }
            }
            else
            {
                _firstLoadOccured = true;
            }

            AtlasData atlasData;
            var       cachedFile = new FileInfo(Path.Combine(_atlasCacheDirectory.FullName, "CachedAtlas.json"));

            if (cachedFile.Exists)
            {
                try
                {
                    atlasData = _jsonSerializer.Deserialize <AtlasData>(cachedFile);
                }
                finally
                {
                    cachedFile.Delete();
                }
                // TODO: this just screams for some kind of progress chain,
                void WeightedProgress(float x) => onProgress?.Invoke(x * 49 / 50f); //       there are like 5 places where a progress chain is needed

                // Progress Chain: multiple progress delegates with offsets and weights
                _textures = LoadTextures(atlasData, WeightedProgress);
            }
            else
            {
                var watch = Stopwatch.StartNew();
                (atlasData, _textures) = StitchAtlas((x) => onProgress?.Invoke(x * 49 / 50f));
                watch.Stop();

                Log.Info("Atlas stiching took " + watch.Elapsed.ToPreciseString());
            }
            UpdateKeys(atlasData);

            IsLoaded = true;
            OnLoad?.Invoke(this);
            onProgress?.Invoke(1f);
        }
Ejemplo n.º 9
0
 void ReportProgress(int processedSize)
 {
     if (m_progressCallback != null)
     {
         ProgressEventArgs args = new ProgressEventArgs(processedSize, m_totalSize, m_requestGuid, m_state);
         m_progressCallback.Invoke(this, args);
     }
 }
Ejemplo n.º 10
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="RootDir"></param>
 /// <param name="sFiles"></param>
 /// <param name="sOutFile"></param>
 /// <param name="progress"></param>
 public static void CompressDirGZip(string RootDir, string[] sFiles, string sOutFile, ProgressDelegate progress = null)
 {
     using (FileStream outFile = new FileStream(sOutFile, FileMode.Append, FileAccess.Write, FileShare.None))
         using (GZipStream str = new GZipStream(outFile, System.IO.Compression.CompressionMode.Compress, false))
             foreach (string sFilePath in sFiles)
             {
                 progress?.Invoke(sFilePath);
                 CompressFile(RootDir, sFilePath, str);
             }
 }
Ejemplo n.º 11
0
        private (AtlasData, Texture2D[]) StitchAtlas(ProgressDelegate onProgress)
        {
            int maxSize = _graphicsDevice.MaxTextureSize;

            Log.Debug($"Max Texture Size: {maxSize}x{maxSize}");

            var retreiver = new AtlasRootRetreiver(_atlasRoot);
            var packer    = new AtlasPacker(maxSize, new ImageSpacing(1, 1, 1, 1));

            List <AtlasRootDirectory> dirs = retreiver.GetDirectories();

            for (int i = 0; i < dirs.Count; i++)
            {
                AtlasRootDirectory dir   = dirs[i];
                AtlasImageBatch    batch = retreiver.GetImageBatch(dir);

                /*
                 * if (dir.Description.ForceSingle)
                 *  packer.PackSingleBatch(batch);
                 * else*/
                packer.PackBatch(batch);

                onProgress.Invoke((i + 1f) / dirs.Count * 0.09f); // 9% weight
            }

            packer.TrimStates();
            onProgress.Invoke(0.1f); // 1% weight (10% because we just finished the 9% weighted packing)

            var textures = new Texture2D[packer.PackCount];

            unsafe void OnTexture(IntPtr img, int width, int height, int texture)
            {
                textures[texture] = new Texture2D(_graphicsDevice, width, height);
                textures[texture].SetData(img, 0, sizeof(Rgba32), width * height);
            }

            var serializer = new AtlasSerializer(MonoGame.Imaging.ImageSaveFormat.Tga);
            var data       = serializer.Serialize(packer, _atlasCacheDirectory, OnTexture, (x) => onProgress(x * 0.9f + 0.1f));

            onProgress.Invoke(1f);

            return(data, textures);
        }
Ejemplo n.º 12
0
        public void WriteFiles(BinaryWriter writer, ProgressDelegate Progress)
        {
            foreach (IsoFolderElement child in Children)
            {
                if (!child.IsDirectory)
                {
                    ((IsoFile)child).Write(writer, Progress);
                    Progress?.Invoke(this, new ProgressEventArgs((int)(writer.BaseStream.Length / IsoAlgorithm.SectorSize)));
                }
            }

            foreach (IsoFolderElement child in Children)
            {
                if (child.IsDirectory)
                {
                    ((IsoDirectory)child).WriteFiles(writer, Progress);
                    Progress?.Invoke(this, new ProgressEventArgs((int)(writer.BaseStream.Length / IsoAlgorithm.SectorSize)));
                }
            }
        }
Ejemplo n.º 13
0
        private Texture2D[] LoadTextures(AtlasData data, ProgressDelegate onProgress)
        {
            var textures = new Texture2D[data.Textures.Length];

            for (int i = 0; i < textures.Length; i++)
            {
                string file = $"{_atlasCacheDirectory.FullName}/{data.Textures[i]}";
                using (var fs = new FileStream(file, FileMode.Open))
                    //using (var ds = new DeflateStream(fs, CompressionMode.Decompress))
                    textures[i] = Texture2D.FromStream(_graphicsDevice, fs);

                onProgress?.Invoke((i + 1) / textures.Length);
            }
            return(textures);
        }
Ejemplo n.º 14
0
 private void RunTask()
 {
     try
     {
         _method.Invoke(_progress);
     }
     catch (Exception e)
     {
         ThreadDispatcher.Invoke(() => MessageBox.Show(e.Message));
     }
     finally
     {
         ThreadDispatcher.Invoke(Close);
     }
 }
Ejemplo n.º 15
0
        public unsafe void Render()
        {
            Scene.UpdateVisibleObjects(Camera);

            RenderTarget result = new RenderTarget(_screenResolutionX, _screenResolutionY);

            //Bitmap result = new Bitmap(_screenResolutionX, _screenResolutionY, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            Rectangle rect = new Rectangle(0, 0, result.ColorBuffer.Bitmap.Width, result.ColorBuffer.Bitmap.Height);

            System.Drawing.Imaging.BitmapData bmpData = result.ColorBuffer.Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, result.ColorBuffer.Bitmap.PixelFormat);

            byte *scan0 = (byte *)bmpData.Scan0.ToPointer();

            for (int y = 0; y < _screenResolutionY; y++)
            {
                byte *scanLine = scan0 + y * bmpData.Stride;

                RaytracerData raytracerData = new RaytracerData()
                {
                    X0          = 0,
                    X1          = _screenResolutionX,
                    Y           = y,
                    Camera      = Camera,
                    Scene       = Scene,
                    ScanLine    = scanLine,
                    DepthBuffer = result.DepthBuffer
                };

                if (_renderDOF)
                {
                    RenderScanLineDOF(raytracerData);
                }
                else
                {
                    RenderScanLine(raytracerData);
                }

                RenderProgress?.Invoke((float)y / (float)_screenResolutionY);
            }

            result.ColorBuffer.Bitmap.UnlockBits(bmpData);

            RenderComplete?.Invoke(result);
        }
Ejemplo n.º 16
0
        private void EmitProgress()
        {
            long length = m_length;

            if (length < 0 && m_innerStream.CanSeek)
            {
                length = m_innerStream.Length;
            }

            if (length > 0)
            {
                int percentage = Math.Min((int)((m_position * 100) / length), 100);
                if (percentage != m_lastProgress)
                {
                    m_listener.Invoke(percentage);
                    m_lastProgress = percentage;
                }
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Add new translation language.
        /// </summary>
        /// <param name="key">Name of language to add.</param>
        /// <param name="autoTranslate">Auto translate by GoogleTranslator?</param>
        /// <param name="fromLanguage">Name of language from auto translate.</param>
        /// <param name="progress">Delegate execute by each translation item.</param>
        public void Add(string key, bool autoTranslate, string fromLanguage = "", ProgressDelegate progress = null)
        {
            Add(key, new TranslationClasses());
            if (fromLanguage.Trim() == "")
            {
                fromLanguage = GetEnglishName();
            }

            if (Exists(fromLanguage))
            {
                int maxValue = 0;
                foreach (KeyValuePair <string, TranslationProperties> classItem in this[fromLanguage])
                {
                    maxValue += classItem.Value.Count;
                }
                int value = 0;
                foreach (KeyValuePair <string, TranslationProperties> classItem in this[fromLanguage])
                {
                    foreach (KeyValuePair <string, TranslationProperty> propertyItem in this[fromLanguage][classItem.Key])
                    {
                        string message = "";
                        if (autoTranslate && Exists(fromLanguage, classItem.Key, propertyItem.Key))
                        {
                            try
                            {
                                message = GoogleTranslator.Translate(propertyItem.Value.Message,
                                                                     FindCultureInfo(fromLanguage).TwoLetterISOLanguageName,
                                                                     FindCultureInfo(key).TwoLetterISOLanguageName);
                            }
                            catch
                            {
                                message = "";
                            }
                        }
                        SetProperty(key, classItem.Key, propertyItem.Key, message, propertyItem.Value.IsStatic);
                        progress?.Invoke(value, maxValue);
                        value++;
                    }
                }
            }
        }
        public ArchiveDirectory BuildTree(IArchive archive, ProgressDelegate onProgress)
        {
            var topDir = new ArchiveDirectory(null, archive.Name);

            int processed = 0;

            foreach (IArchiveEntry entry in archive)
            {
                string[] segments = GetPathSegments(entry.FullName);
                if (entry.IsDirectory)
                {
                    CreateDirectoryTree(segments, 0, segments.Length, topDir);
                }
                else
                {
                    if (segments.Length == 1)
                    {
                        string segment = segments[0];
                        var    file    = CreateFileFromEntry(topDir, segment, entry);
                        topDir.Files.Add(segment, file);
                    }
                    else
                    {
                        var    dir     = CreateDirectoryTree(segments, 0, segments.Length - 1, topDir);
                        string segment = segments[segments.Length - 1];

                        var file = CreateFileFromEntry(topDir, segment, entry);
                        dir.Files.Add(segment, file);
                    }
                }
                processed++;
                onProgress?.Invoke(processed / (float)archive.Count);
            }

            return(topDir);
        }
        public static bool InstallGame( string gameTitle, string gameVersion, ProgressDelegate listener, ICancellable cancelObject )
        {
            var downloadPath = GetDownloadPath( gameTitle, gameVersion );
            var installPath = GetInstallPath( gameTitle, gameVersion );
            if( File.Exists( downloadPath ) )
            {
                try
                {
                    using( var zipFile = new ZipFile( downloadPath ) )
                    {
                        // Delete old install
                        if( Directory.Exists( installPath ) )
                        {
                            Directory.Delete( installPath, true );
                        }
                        Directory.CreateDirectory( installPath );

                        // Extract new install
                        int totalFiles = zipFile.Entries.Count;
                        int filesInstalled = 0;
                        int lastProgress = 0;
                        listener.Invoke( 0 );
                        foreach( var entry in zipFile.Entries )
                        {
                            // Extract the file
                            var entryInstallPath = Path.Combine( installPath, entry.FileName );
                            if( entry.IsDirectory )
                            {
                                Directory.CreateDirectory( entryInstallPath );
                            }
                            else
                            {
                                Directory.CreateDirectory( Path.GetDirectoryName( entryInstallPath ) );
                                using( var file = File.OpenWrite( entryInstallPath ) )
                                {
                                    try
                                    {
                                        using( var reader = new ProgressStream( entry.OpenReader(), -1, delegate {
                                            // TODO: Emit progress during installation of large individual files?
                                        }, cancelObject ) )
                                        {
                                            try
                                            {
                                                reader.CopyTo( file );
                                                if( Program.Platform == Platform.Linux ||
                                                    Program.Platform == Platform.OSX )
                                                {
                                                    Mono.Unix.Native.Syscall.chmod(
                                                        entryInstallPath,
                                                        Mono.Unix.Native.FilePermissions.ACCESSPERMS
                                                    );
                                                }
                                            }
                                            finally
                                            {
                                                reader.Close();
                                            }
                                        }
                                    }
                                    finally
                                    {
                                        file.Close();
                                    }
                                }
                            }

                            // Check for cancellation
                            if( cancelObject.Cancelled )
                            {
                                throw new IOCancelledException();
                            }

                            // Notify the progress listener
                            filesInstalled++;
                            int progress = (filesInstalled * 100) / totalFiles;
                            if( progress != lastProgress )
                            {
                                listener.Invoke( progress );
                                lastProgress = progress;
                            }
                        }
                    }
                    return true;
                }
                catch( IOException )
                {
                    if( Directory.Exists( installPath ) )
                    {
                        Directory.Delete( installPath, true );
                    }
                    return false;
                }
                catch( ZipException )
                {
                    if( Directory.Exists( installPath ) )
                    {
                        Directory.Delete( installPath, true );
                    }
                    return false;
                }
            }
            return false;
        }
Ejemplo n.º 20
0
        public static void CopyMod(string sourceFolder, string destinationFolder, string modId, ProgressDelegate progressCallback)
        {
            if (string.IsNullOrWhiteSpace(sourceFolder) || !Directory.Exists(sourceFolder))
            {
                throw new DirectoryNotFoundException($"Source folder was not found.\r\n{sourceFolder}");
            }

            var modSourceFolder = sourceFolder;

            progressCallback?.Invoke(0, "Reading mod base information.");

            var fileName = IOUtils.NormalizePath(Path.Combine(modSourceFolder, "mod.info"));
            var list     = new List <string>();

            ParseBaseInformation(fileName, list);

            progressCallback?.Invoke(0, "Reading mod meta information.");

            fileName = IOUtils.NormalizePath(Path.Combine(modSourceFolder, "modmeta.info"));
            var metaInformation = new Dictionary <string, string>();

            if (ParseMetaInformation(fileName, metaInformation))
            {
                modSourceFolder = IOUtils.NormalizePath(Path.Combine(modSourceFolder, "WindowsNoEditor"));
            }

            var modFile = $"{destinationFolder}.mod";

            progressCallback?.Invoke(0, "Deleting existing mod files.");

            // delete the server mod folder and mod file.
            if (Directory.Exists(destinationFolder))
            {
                Directory.Delete(destinationFolder, true);
            }
            if (File.Exists(modFile))
            {
                File.Delete(modFile);
            }

            progressCallback?.Invoke(0, "Copying mod files.");

            // update the mod files from the cache.
            var flag = Copy(modSourceFolder, destinationFolder, true);

            if (metaInformation.Count == 0 && flag)
            {
                metaInformation["ModType"] = "1";
            }

            progressCallback?.Invoke(0, "Creating mod file.");

            // create the mod file.
            WriteModFile(modFile, modId, metaInformation, list);

            // copy the last updated file.
            fileName = IOUtils.NormalizePath(Path.Combine(sourceFolder, Config.Default.LastUpdatedTimeFile));
            if (File.Exists(fileName))
            {
                progressCallback?.Invoke(0, "Copying mod version file.");

                var tempFile = IOUtils.NormalizePath(fileName.Replace(sourceFolder, destinationFolder));
                File.Copy(fileName, tempFile, true);
            }
        }
Ejemplo n.º 21
0
        public unsafe AtlasData Serialize(
            AtlasPacker packer, DirectoryInfo output,
            TextureDelegate onTexture, ProgressDelegate onProgress)
        {
            int stateCount  = packer._states.Count;
            int singleCount = packer._singles.Count;
            var textures    = new string[stateCount + singleCount];

            int totalItemCount = packer.TotalItemCount;
            var items          = new List <AtlasData.Item>(totalItemCount);

            if (!output.Exists)
            {
                output.Create();
            }

            void AddItem(AtlasData.Item item)
            {
                items.Add(item);
                onProgress.Invoke(items.Count / (float)totalItemCount);
            }

            for (int textureIndex = 0; textureIndex < stateCount; textureIndex++)
            {
                AtlasPackerState state = packer._states[textureIndex];
                int width  = state.Width;
                int height = state.Height;

                using (var result = new Image <Rgba32>(width, height))
                {
                    Span <Rgba32> resultSpan = result.GetPixelSpan();
                    foreach (AtlasPackerState.Item item in state.Items)
                    {
                        using (var img = Image.Load <Rgba32>(item.AtlasImage.File.OpenRead()))
                        {
                            var srcRect = new Rect(0, 0, img.Width, img.Height);
                            var input32 = img.GetPixelSpan();

                            Copy(input32, inputStride: srcRect.W, srcRect,
                                 resultSpan, outputStride: width, item.Rect);

                            AddItem(new AtlasData.Item(item.AtlasImage.RelativePath, textureIndex, item.Rect));
                        }
                    }

                    using (var fs = GetFileStream(textures, textureIndex, output))
                        result.Save(fs, SaveFormat);

                    onTexture?.Invoke(resultSpan, new Size(width, height), textureIndex);
                }
            }

            for (int singleIndex = 0; singleIndex < singleCount; singleIndex++)
            {
                AtlasImage item = packer._singles[singleIndex];
                using (var img = Image.Load <Rgba32>(item.File.OpenRead()))
                {
                    int index = singleIndex + stateCount; // add amount of states as offset
                    using (var fs = GetFileStream(textures, index, output))
                        img.Save(fs, SaveFormat);

                    AddItem(new AtlasData.Item(item.RelativePath, index, 0, 0, item.Width, item.Height));
                    onTexture?.Invoke(img.GetPixelSpan(), new Size(item.Width, item.Height), index);
                }
            }

            return(new AtlasData(textures, items));
        }
Ejemplo n.º 22
0
        private static void DownloadLanguageFiles(Dictionary <string, string> urls, string language, ProgressDelegate progress, CompletionDelegate completion)
        {
            OcrLanguage      currentlyDownloadingLanguage = null;
            List <Exception> downloadErrors = new List <Exception>();
            bool             cancelled      = false;

            try
            {
                if (urls.Count == 0)
                {
                    var downloadableLanguages = DownloadableLanguages.Where(l => l.Language.Equals(language));
                    if (downloadableLanguages.Count() > 0)
                    {
                        currentlyDownloadingLanguage = downloadableLanguages.ElementAt(0);
                    }
                    completion?.Invoke(currentlyDownloadingLanguage, null);
                    return;
                }

                currentlyDownloadingLanguage = GetCurrentlyDownloadingLanguage(urls.Values.ElementAt(0));
                if (currentlyDownloadingLanguage != null)
                {
                    if (currentlyDownloadingLanguage.CancellationTokenSource != null)
                    {
                        currentlyDownloadingLanguage.CancellationTokenSource.Dispose();
                        currentlyDownloadingLanguage.CancellationTokenSource = null;
                    }

                    currentlyDownloadingLanguage.CancellationTokenSource = new CancellationTokenSource();
                    currentlyDownloadingLanguage.IsDownloading           = true;
                }

                long totalSizeToDownload = 0;
                Task task = null;
                Dictionary <string, long> totalBytesReceivedForAllDownloads = new Dictionary <string, long>();

                List <Task>          downloadTasks        = new List <Task>();
                HttpClientDownloader httpClientDownloader = new HttpClientDownloader();
                httpClientDownloader.DownloadCompleted += (object sender, DownloadCompletedEventArgs e) =>
                {
                    if (!e.Cancelled && e.Error == null)
                    {
                        string finalPath = Path.Combine(LanguagesDirectory, Path.GetFileName(e.TargetFilePath));
                        MoveFile(e.TargetFilePath, finalPath);
                    }
                    else if (e.Cancelled)
                    {
                        cancelled = true;
                    }
                    else if (e.Error != null)
                    {
                        downloadErrors.Add(e.Error);
                    }

                    if (cancelled || e.Error != null)
                    {
                        // Delete temporary file in case or cancellation or error.
                        DeleteFile(e.TargetFilePath);
                    }
                };

                httpClientDownloader.DownloadProgressChanged += (object sender, DownloadProgressChangedEventArgs e) =>
                {
                    // if error occurred while downloading any of this language files, then abort the rest.
                    if (downloadErrors.Count > 0)
                    {
                        CancelDownloadForLanguage(currentlyDownloadingLanguage.Language);
                        return;
                    }

                    if (currentlyDownloadingLanguage != null)
                    {
                        if (!currentlyDownloadingLanguage.IsDownloading)
                        {
                            // User cancelled the download of this language
                            return;
                        }

                        long totalBytesReceived = 0;
                        lock (totalBytesReceivedForAllDownloads)
                        {
                            totalBytesReceivedForAllDownloads[e.SourceFileUrl] = e.BytesReceived;

                            foreach (KeyValuePair <string, long> entry in totalBytesReceivedForAllDownloads)
                            {
                                totalBytesReceived += entry.Value;
                            }
                        }

                        currentlyDownloadingLanguage.DownloadPercentage = Math.Round((double)totalBytesReceived / totalSizeToDownload * 100, 2);

                        progress?.Invoke(currentlyDownloadingLanguage, currentlyDownloadingLanguage.DownloadPercentage);
                    }
                };

                void StartDownloadTask(string url)
                {
                    try
                    {
                        if (downloadErrors.Count > 0)
                        {
                            return;
                        }

                        string targetFilePath = Path.Combine(_downloadLanguagesDirectory, Path.GetFileName(url));
                        task = httpClientDownloader.DownloadFileAsync(url, targetFilePath, currentlyDownloadingLanguage.CancellationTokenSource?.Token);
                        downloadTasks.Add(task);
                    }
                    catch (Exception ex2)
                    {
                        Console.WriteLine(ex2.Message);
                    }
                }

                foreach (KeyValuePair <string, string> entry in urls)
                {
                    string url          = entry.Value;
                    string languageFile = Path.GetFileName(url);
                    string identifier   = languageFile.Split('.')[1];
                    object sizeValue    = Manifest[identifier][languageFile][FileSizeKeyString];
                    if (sizeValue.GetType() == typeof(long))
                    {
                        totalSizeToDownload += (long)sizeValue;
                    }

                    StartDownloadTask(url);
                }

                Task.WaitAll(downloadTasks.ToArray(), -1, (currentlyDownloadingLanguage.CancellationTokenSource != null) ? currentlyDownloadingLanguage.CancellationTokenSource.Token : CancellationToken.None);
                downloadTasks.Clear();

                if (!cancelled)
                {
                    DownloadableLanguages.Remove(currentlyDownloadingLanguage);
                    LocalLanguages.Add(currentlyDownloadingLanguage);
                    //UpdateLanguagesWithCurrentManifest();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                if (ex.GetType() != typeof(TaskCanceledException) && ex.GetType() != typeof(OperationCanceledException) && currentlyDownloadingLanguage != null)
                {
                    downloadErrors.Add(ex);
                }
            }
            finally
            {
                Exception error = null;
                currentlyDownloadingLanguage.IsDownloading = false;

                var errors = downloadErrors.Where(e => e != null);
                if (errors != null && errors.Count() > 0)
                {
                    error = errors.ElementAt(0);
                }

                if (error != null)
                {
                    DownloadableLanguagesError = error;
                    currentlyDownloadingLanguage.DownloadPercentage = 0;
                }
                else
                {
                    currentlyDownloadingLanguage.DownloadPercentage = 100;
                }

                if (!cancelled)
                {
                    completion?.Invoke(currentlyDownloadingLanguage, error);
                }
            }
        }
Ejemplo n.º 23
0
        public async Task <bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, bool validate, bool updateMods, ProgressDelegate progressCallback)
        {
            if (updateServer && !Environment.Is64BitOperatingSystem)
            {
                var result = MessageBox.Show("The ARK server requires a 64-bit operating system to run. Your operating system is 32-bit and therefore the Ark Server Manager will be unable to start the server, but you may still install it or load and save profiles and settings files for use on other machines.\r\n\r\nDo you wish to continue?", "64-bit OS Required", MessageBoxButton.YesNo, MessageBoxImage.Warning);
                if (result == MessageBoxResult.No)
                {
                    return(false);
                }
            }

            try
            {
                await StopAsync();

                bool isNewInstallation = this.Status == ServerStatus.Uninstalled;

                this.Status = ServerStatus.Updating;

                // Run the SteamCMD to install the server
                var steamCmdFile = Updater.GetSteamCmdFile();
                if (string.IsNullOrWhiteSpace(steamCmdFile) || !File.Exists(steamCmdFile))
                {
                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************************");
                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: SteamCMD could not be found. Expected location is {steamCmdFile}");
                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************************");
                    return(false);
                }

                // record the start time of the process, this is used to determine if any files changed in the download process.
                var startTime = DateTime.Now;

                var gotNewVersion      = false;
                var downloadSuccessful = false;
                var success            = false;

                if (updateServer)
                {
                    // *********************
                    // Server Update Section
                    // *********************

                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Starting server update.");

                    // Check if this is a new server installation.
                    if (isNewInstallation)
                    {
                        // check if the auto-update facility is enabled and the cache folder defined.
                        if (!this.ProfileSnapshot.SotFServer && Config.Default.AutoUpdate_EnableUpdate && !string.IsNullOrWhiteSpace(Config.Default.AutoUpdate_CacheDir) && Directory.Exists(Config.Default.AutoUpdate_CacheDir))
                        {
                            // Auto-Update enabled and cache foldler exists.
                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Installing server from local cache...may take a while to copy all the files.");

                            // Install the server files from the cache.
                            var installationFolder = this.ProfileSnapshot.InstallDirectory;
                            int count = 0;
                            await Task.Run(() =>
                                           ServerApp.DirectoryCopy(Config.Default.AutoUpdate_CacheDir, installationFolder, true, Config.Default.AutoUpdate_UseSmartCopy, (p, m, n) =>
                            {
                                count++;
                                progressCallback?.Invoke(0, ".", count % DIRECTORIES_PER_LINE == 0);
                            }), cancellationToken);
                        }
                    }

                    progressCallback?.Invoke(0, "\r\n");
                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Updating server from steam.\r\n");

                    downloadSuccessful = !Config.Default.SteamCmdRedirectOutput;
                    DataReceivedEventHandler serverOutputHandler = (s, e) =>
                    {
                        var dataValue = e.Data ?? string.Empty;
                        progressCallback?.Invoke(0, dataValue);
                        if (!gotNewVersion && dataValue.Contains("downloading,"))
                        {
                            gotNewVersion = true;
                        }
                        if (dataValue.StartsWith("Success!"))
                        {
                            downloadSuccessful = true;
                        }
                    };

                    var steamCmdInstallServerArgsFormat = this.ProfileSnapshot.SotFServer ? Config.Default.SteamCmdInstallServerArgsFormat_SotF : Config.Default.SteamCmdInstallServerArgsFormat;
                    var steamCmdArgs = String.Format(steamCmdInstallServerArgsFormat, this.ProfileSnapshot.InstallDirectory, validate ? "validate" : string.Empty);

                    success = await ServerUpdater.UpgradeServerAsync(steamCmdFile, steamCmdArgs, this.ProfileSnapshot.InstallDirectory, Config.Default.SteamCmdRedirectOutput?serverOutputHandler : null, cancellationToken);

                    if (success && downloadSuccessful)
                    {
                        progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished server update.");

                        if (Directory.Exists(this.ProfileSnapshot.InstallDirectory))
                        {
                            if (!Config.Default.SteamCmdRedirectOutput)
                            {
                                // check if any of the server files have changed.
                                gotNewVersion = ServerApp.HasNewServerVersion(this.ProfileSnapshot.InstallDirectory, startTime);
                            }

                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} New server version - {gotNewVersion.ToString().ToUpperInvariant()}.");
                        }

                        progressCallback?.Invoke(0, "\r\n");
                    }
                    else
                    {
                        success = false;
                        progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ****************************");
                        progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Failed server update.");
                        progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ****************************\r\n");

                        if (Config.Default.SteamCmdRedirectOutput)
                        {
                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} If the server update keeps failing try disabling the '{_globalizer.GetResourceString("GlobalSettings_SteamCmdRedirectOutputLabel")}' option in the settings window.\r\n");
                        }
                    }
                }
                else
                {
                    success = true;
                }

                if (success)
                {
                    if (updateMods)
                    {
                        // ******************
                        // Mod Update Section
                        // ******************

                        // build a list of mods to be processed
                        var modIdList = new List <string>();
                        if (!string.IsNullOrWhiteSpace(this.ProfileSnapshot.ServerMapModId))
                        {
                            modIdList.Add(this.ProfileSnapshot.ServerMapModId);
                        }
                        if (!string.IsNullOrWhiteSpace(this.ProfileSnapshot.TotalConversionModId))
                        {
                            modIdList.Add(this.ProfileSnapshot.TotalConversionModId);
                        }
                        modIdList.AddRange(this.ProfileSnapshot.ServerModIds);

                        modIdList = ModUtils.ValidateModList(modIdList);

                        // get the details of the mods to be processed.
                        var modDetails = SteamUtils.GetSteamModDetails(modIdList);
                        if (modDetails != null)
                        {
                            // create a new list for any failed mod updates
                            var failedMods = new List <string>(modIdList.Count);

                            for (var index = 0; index < modIdList.Count; index++)
                            {
                                var modId      = modIdList[index];
                                var modTitle   = modId;
                                var modSuccess = false;
                                gotNewVersion      = false;
                                downloadSuccessful = false;

                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Started processing mod {index + 1} of {modIdList.Count}.");
                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Mod {modId}.");

                                // check if the steam information was downloaded
                                var modDetail = modDetails.publishedfiledetails?.FirstOrDefault(m => m.publishedfileid.Equals(modId, StringComparison.OrdinalIgnoreCase));
                                if (modDetail != null)
                                {
                                    modTitle = $"{modDetail.title} ({modId})";
                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} {modDetail.title ?? string.Empty}.\r\n");

                                    var modCachePath  = ModUtils.GetModCachePath(modId, this.ProfileSnapshot.SotFServer);
                                    var cacheTimeFile = ModUtils.GetLatestModCacheTimeFile(modId, this.ProfileSnapshot.SotFServer);
                                    var modPath       = ModUtils.GetModPath(this.ProfileSnapshot.InstallDirectory, modId);
                                    var modTimeFile   = ModUtils.GetLatestModTimeFile(this.ProfileSnapshot.InstallDirectory, modId);

                                    var modCacheLastUpdated = 0;
                                    var downloadMod         = true;
                                    var copyMod             = true;

                                    if (downloadMod)
                                    {
                                        // check if the mod needs to be downloaded, or force the download.
                                        if (Config.Default.ServerUpdate_ForceUpdateMods)
                                        {
                                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod download - ASM setting is TRUE.");
                                        }
                                        else
                                        {
                                            // check if the mod detail record is valid (private mod).
                                            if (modDetail.time_updated <= 0)
                                            {
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod download - mod is private.");
                                            }
                                            else
                                            {
                                                modCacheLastUpdated = ModUtils.GetModLatestTime(cacheTimeFile);
                                                if (modCacheLastUpdated <= 0)
                                                {
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod download - mod cache is not versioned.");
                                                }
                                                else
                                                {
                                                    var steamLastUpdated = modDetail.time_updated;
                                                    if (steamLastUpdated <= modCacheLastUpdated)
                                                    {
                                                        progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Skipping mod download - mod cache has the latest version.");
                                                        downloadMod = false;
                                                    }
                                                }
                                            }
                                        }

                                        if (downloadMod)
                                        {
                                            // mod will be downloaded
                                            downloadSuccessful = !Config.Default.SteamCmdRedirectOutput;
                                            DataReceivedEventHandler modOutputHandler = (s, e) =>
                                            {
                                                var dataValue = e.Data ?? string.Empty;
                                                progressCallback?.Invoke(0, dataValue);
                                                if (dataValue.StartsWith("Success."))
                                                {
                                                    downloadSuccessful = true;
                                                }
                                            };

                                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Starting mod download.\r\n");

                                            var steamCmdArgs = string.Empty;
                                            if (this.ProfileSnapshot.SotFServer)
                                            {
                                                if (Config.Default.SteamCmd_UseAnonymousCredentials)
                                                {
                                                    steamCmdArgs = string.Format(Config.Default.SteamCmdInstallModArgsFormat_SotF, Config.Default.SteamCmd_AnonymousUsername, modId);
                                                }
                                                else
                                                {
                                                    steamCmdArgs = string.Format(Config.Default.SteamCmdInstallModArgsFormat_SotF, Config.Default.SteamCmd_Username, modId);
                                                }
                                            }
                                            else
                                            {
                                                if (Config.Default.SteamCmd_UseAnonymousCredentials)
                                                {
                                                    steamCmdArgs = string.Format(Config.Default.SteamCmdInstallModArgsFormat, Config.Default.SteamCmd_AnonymousUsername, modId);
                                                }
                                                else
                                                {
                                                    steamCmdArgs = string.Format(Config.Default.SteamCmdInstallModArgsFormat, Config.Default.SteamCmd_Username, modId);
                                                }
                                            }

                                            modSuccess = await ServerUpdater.UpgradeModsAsync(steamCmdFile, steamCmdArgs, Config.Default.SteamCmdRedirectOutput?modOutputHandler : null, cancellationToken);

                                            if (modSuccess && downloadSuccessful)
                                            {
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished mod download.");
                                                copyMod = true;

                                                if (Directory.Exists(modCachePath))
                                                {
                                                    // check if any of the mod files have changed.
                                                    gotNewVersion = new DirectoryInfo(modCachePath).GetFiles("*.*", SearchOption.AllDirectories).Any(file => file.LastWriteTime >= startTime);

                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} New mod version - {gotNewVersion.ToString().ToUpperInvariant()}.");

                                                    var steamLastUpdated = modDetail.time_updated.ToString();
                                                    if (modDetail.time_updated <= 0)
                                                    {
                                                        // get the version number from the steamcmd workshop file.
                                                        steamLastUpdated = ModUtils.GetSteamWorkshopLatestTime(ModUtils.GetSteamWorkshopFile(this.ProfileSnapshot.SotFServer), modId).ToString();
                                                    }

                                                    // update the last updated file with the steam updated time.
                                                    File.WriteAllText(cacheTimeFile, steamLastUpdated);

                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Mod Cache version: {steamLastUpdated}\r\n");
                                                }
                                            }
                                            else
                                            {
                                                modSuccess = false;
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***************************");
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mod download failed.");
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***************************\r\n");

                                                if (Config.Default.SteamCmdRedirectOutput)
                                                {
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} If the mod update keeps failing try disabling the '{_globalizer.GetResourceString("GlobalSettings_SteamCmdRedirectOutputLabel")}' option in the settings window.\r\n");
                                                }
                                                copyMod = false;
                                            }
                                        }
                                        else
                                        {
                                            modSuccess = true;
                                        }
                                    }
                                    else
                                    {
                                        modSuccess = true;
                                    }

                                    if (copyMod)
                                    {
                                        // check if the mod needs to be copied, or force the copy.
                                        if (Config.Default.ServerUpdate_ForceCopyMods)
                                        {
                                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod copy - ASM setting is TRUE.");
                                        }
                                        else
                                        {
                                            // check the mod version against the cache version.
                                            var modLastUpdated = ModUtils.GetModLatestTime(modTimeFile);
                                            if (modLastUpdated <= 0)
                                            {
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod copy - mod is not versioned.");
                                            }
                                            else
                                            {
                                                modCacheLastUpdated = ModUtils.GetModLatestTime(cacheTimeFile);
                                                if (modCacheLastUpdated <= modLastUpdated)
                                                {
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Skipping mod copy - mod has the latest version.");
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Mod version: {modLastUpdated}");
                                                    copyMod = false;
                                                }
                                            }
                                        }

                                        if (copyMod)
                                        {
                                            try
                                            {
                                                if (Directory.Exists(modCachePath))
                                                {
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Started mod copy.");
                                                    int count = 0;
                                                    await Task.Run(() => ModUtils.CopyMod(modCachePath, modPath, modId, (p, m, n) =>
                                                    {
                                                        count++;
                                                        progressCallback?.Invoke(0, ".", count % DIRECTORIES_PER_LINE == 0);
                                                    }), cancellationToken);

                                                    progressCallback?.Invoke(0, "\r\n");
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished mod copy.");

                                                    var modLastUpdated = ModUtils.GetModLatestTime(modTimeFile);
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Mod version: {modLastUpdated}");
                                                }
                                                else
                                                {
                                                    modSuccess = false;
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ****************************************************");
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mod cache was not found, mod was not updated.");
                                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ****************************************************");
                                                }
                                            }
                                            catch (Exception ex)
                                            {
                                                modSuccess = false;
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************");
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Failed mod copy.\r\n{ex.Message}");
                                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************");
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    // no steam information downloaded, display an error, mod might no longer be available
                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} *******************************************************************");
                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mod cannot be updated, unable to download steam information.");
                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} *******************************************************************");
                                }

                                if (!modSuccess)
                                {
                                    success = false;
                                    failedMods.Add($"{index + 1} of {modIdList.Count} - {modTitle}");
                                }

                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished processing mod {modId}.\r\n");
                            }

                            if (failedMods.Count > 0)
                            {
                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} **************************************************************************");
                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: The following mods failed the update, check above for more details.");
                                foreach (var failedMod in failedMods)
                                {
                                    progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} {failedMod}");
                                }
                                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} **************************************************************************\r\n");
                            }
                        }
                        else
                        {
                            success = false;
                            // no steam information downloaded, display an error
                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ********************************************************************");
                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mods cannot be updated, unable to download steam information.");
                            progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ********************************************************************\r\n");
                        }
                    }
                }
                else
                {
                    if (updateServer && updateMods)
                    {
                        progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************************************************");
                        progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mods were not processed as server update had errors.");
                        progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************************************************\r\n");
                    }
                }

                progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished upgrade process.");
                return(success);
            }
            catch (TaskCanceledException)
            {
                return(false);
            }
            finally
            {
                this.Status = ServerStatus.Stopped;
            }
        }
Ejemplo n.º 24
0
        public static bool InstallGame(string gameTitle, string gameVersion, ProgressDelegate listener, ICancellable cancelObject)
        {
            var downloadPath = GetDownloadPath(gameTitle, gameVersion);
            var installPath  = GetInstallPath(gameTitle, gameVersion);

            if (File.Exists(downloadPath))
            {
                Logger.Log("Installing game ({0} {1})", gameTitle, gameVersion);
                try
                {
                    using (var zipFile = new ZipFile(downloadPath))
                    {
                        // Delete old install
                        if (Directory.Exists(installPath))
                        {
                            Directory.Delete(installPath, true);
                        }
                        Directory.CreateDirectory(installPath);

                        // Extract new install
                        int totalFiles     = zipFile.Entries.Count;
                        int filesInstalled = 0;
                        int lastProgress   = 0;
                        listener.Invoke(0);
                        foreach (var entry in zipFile.Entries)
                        {
                            // Extract the file
                            var entryInstallPath = Path.Combine(installPath, entry.FileName);
                            if (entry.IsDirectory)
                            {
                                Directory.CreateDirectory(entryInstallPath);
                            }
                            else
                            {
                                Directory.CreateDirectory(Path.GetDirectoryName(entryInstallPath));
                                using (var file = File.OpenWrite(entryInstallPath))
                                {
                                    try
                                    {
                                        using (var reader = new ProgressStream(entry.OpenReader(), -1, delegate {
                                            // TODO: Emit progress during installation of large individual files?
                                        }, cancelObject))
                                        {
                                            try
                                            {
                                                reader.CopyTo(file);
                                                try
                                                {
                                                    if (Program.Platform == Platform.Linux ||
                                                        Program.Platform == Platform.OSX)
                                                    {
                                                        MakeFileExecutable(entryInstallPath);
                                                    }
                                                }
                                                catch (Exception e)
                                                {
                                                    Logger.Log("Caught Exception: {0}", e.ToString());
                                                    Logger.Log("Failed to set file permissions on {0}", entryInstallPath);
                                                }
                                            }
                                            finally
                                            {
                                                reader.Close();
                                            }
                                        }
                                    }
                                    finally
                                    {
                                        file.Close();
                                    }
                                }
                            }

                            // Check for cancellation
                            if (cancelObject.Cancelled)
                            {
                                throw new IOCancelledException();
                            }

                            // Notify the progress listener
                            filesInstalled++;
                            int progress = (filesInstalled * 100) / totalFiles;
                            if (progress != lastProgress)
                            {
                                listener.Invoke(progress);
                                lastProgress = progress;
                            }
                        }
                    }
                    return(true);
                }
                catch (Exception e)
                {
                    Logger.Log("Caught Exception: {0}", e.ToString());
                    if (Directory.Exists(installPath))
                    {
                        Directory.Delete(installPath, true);
                    }
                    return(false);
                }
            }
            return(false);
        }