using CommonLibrary; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace Mitria_Minecraft_Launcher.Updater { public class GameUpdateManager { public delegate void GameUpdateManagerMessageHandler(object sender, GameUpdateManagerMessageEventArgs downloaderProgressChangedEventArgs); public event GameUpdateManagerMessageHandler GameUpdateManagerMessage; public GameUpdateManager() { } public GameUpdateStatus Start() { GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.Message, 0, 0, "[0/9] GameUpdatStart")); CommonLibrary.Log.INFO("Game Update Start"); // Downloader 선언 var downloader = new Downloader(); downloader.DownloaderProgressChangedEvent += Downloader_DownloaderProgressChangedEvent; // Version File Download CommonLibrary.Log.INFO("download version file."); var verionData = downloader.DownloadString(CommonLibrary.Extensions.PathCombineL(Settings.ServerBaseUrl,"Servers", Settings.NowProfile.ServerName, Settings.ServerDataPatchInformationFile)); // Versoin File 받기에 실패하였을때 업데이트 전체 실패처리 if (verionData == string.Empty) { GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.Message, 0, 0, "★★ Update Fail ★★")); CommonLibrary.Log.FATAL("Failed to download version file"); return GameUpdateStatus.Fail; } // Version File Xml 형태로 변환 var dataPatchInformation = CommonLibrary.XmlSystem.LoadFromData(verionData); // 임시 폴더 생성 var tempDirectory = System.IO.Path.GetFullPath("temp"); if (!System.IO.Directory.Exists(tempDirectory)) { System.IO.Directory.CreateDirectory(tempDirectory); Log.INFO("[GameUpdateManager] +[F] " + tempDirectory); } // 런타임 업데이트 #region Runtime Update GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 1, 9, "[1/9] Runtime Version Check")); Log.INFO("[Runtime] Version Check"); // 버전 비교 var thisVersion = Version.Parse(Settings.NowProfile.RuntimeVersion); var remoteVersion = Version.Parse(dataPatchInformation.RuntimeVersion); CommonLibrary.Log.INFO("[Runtime] LocalVersion : " + thisVersion); CommonLibrary.Log.INFO("[Runtime] RemoteVersion : " + remoteVersion); var result = remoteVersion.CompareTo(thisVersion); // 1 : 리모트가 큼, 0 : 같음, -1 리모트가 적음 if (result == 0) { CommonLibrary.Log.INFO("[Runtime] Version Same"); } else { CommonLibrary.Log .INFO(string.Format("{0}", result == 1 ? "remote is the upper version" : "remote is the lower version")); CommonLibrary.Log.INFO("Runtime delete it for update."); // 런타임 폴더 경로 가져오기 var rootDirectoryInfo = new System.IO.DirectoryInfo(System.IO.Path.GetFullPath(CommonLibrary.Extensions.PathCombineW(Settings.RuntimeLocation,Settings.NowProfile.ServerName))); // 런타임 폴더 삭제후 새로만들기 if (!rootDirectoryInfo.Exists) { rootDirectoryInfo.Create(); Log.INFO("[Runtime] +[D] " + rootDirectoryInfo.FullName); } else { rootDirectoryInfo.Delete(true); Log.INFO("[Runtime] -[D] " + rootDirectoryInfo.FullName); rootDirectoryInfo.Create(); Log.INFO("[Runtime] +[D] " + rootDirectoryInfo.FullName); } // 런타임 다운로드 시작 GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 2, 9, "[2/9] Runtime Download")); Log.INFO("[Runtime] Data Download Start"); var downloadUrl = CommonLibrary.Extensions.PathCombineL(Settings.ServerBaseUrl, "Servers", Settings.NowProfile.ServerName, dataPatchInformation.RuntimeUrl, dataPatchInformation.RuntimeFileName); var targetPath = System.IO.Path.Combine(tempDirectory, dataPatchInformation.RuntimeFileName); // 임시폴더에 다운로드 downloader.DownloadFile(downloadUrl, targetPath); Log.INFO("[Runtime] Data Download End"); // 런타임 다운로드 완료 // 런타임 언패킹 작업 var progressPacker = new ProgressPacker(); var unpackPath = rootDirectoryInfo.FullName; GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 3, 9, "[3/9] Runtime Unpack")); Log.INFO("[Runtime] Unpack Start"); progressPacker.UnPack(targetPath, unpackPath, new BasicProgress(p => Change(p))); Settings.NowProfile.RuntimeVersion = remoteVersion.ToString(); //임시폴더 삭제 System.IO.File.Delete(targetPath); Log.INFO("[Runtime] -[F] " + targetPath); Log.INFO("[Runtime] Unpack End"); } #endregion Runtime Update #region Package Update GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 4, 9, "[4/9] Package Version Check")); Log.INFO("[Package] Version Check"); thisVersion = Version.Parse(Settings.UserClientVersion.PackageVersion); remoteVersion = Version.Parse(dataPatchInformation.PackageVersion); CommonLibrary.Log.INFO("[Package] LocalVersion : " + thisVersion); CommonLibrary.Log.INFO("[Package] RemoteVersion : " + remoteVersion); result = remoteVersion.CompareTo(thisVersion); // 1 : 리모트가 큼, 0 : 같음, -1 리모트가 적음 if (result == 0) { CommonLibrary.Log.INFO("[Package] Version Same"); } else { CommonLibrary.Log .INFO(string.Format("{0}", result == 1 ? "remote is the upper version" : "remote is the lower version")); CommonLibrary.Log.INFO("[Package] delete it for update."); var rootDirectoryInfo = new System.IO.DirectoryInfo(System.IO.Path.GetFullPath(CommonLibrary.Extensions.PathCombineW(Settings.UserLauncherConfig.GameDirectory,Settings.NowProfile.ServerName))); if (!rootDirectoryInfo.Exists) { rootDirectoryInfo.Create(); Log.INFO("[Package] +[D] " + rootDirectoryInfo.FullName); } else { // 비우기 전에 스크린샷폴더 보존 /screenshots string oldScreenshotsDirectory = CommonLibrary.Extensions.PathCombineW(Settings.UserLauncherConfig.GameDirectory, Settings.NowProfile.ServerName, "screenshots"); string newScreenshotsDirectory = System.IO.Path.GetFullPath("screenshots_" + DateTime.Now.ToString("yyyyMMddHHmmss")); if (System.IO.Directory.Exists(oldScreenshotsDirectory) && System.IO.Directory.GetFiles(oldScreenshotsDirectory, "*", System.IO.SearchOption.AllDirectories).Length > 0) { Log.INFO("[Package] Screenshots Directory Backup : " + newScreenshotsDirectory); System.IO.Directory.Move(oldScreenshotsDirectory, newScreenshotsDirectory); } Extensions.EmptyDirectory(rootDirectoryInfo.FullName); Log.INFO("[Package] Empty GameDirectory"); } var downloadUrl = CommonLibrary.Extensions.PathCombineL(Settings.ServerBaseUrl, "Servers", Settings.NowProfile.ServerName, dataPatchInformation.PackageUrl, dataPatchInformation.PackageFileName); var targetPath = System.IO.Path.Combine(tempDirectory, dataPatchInformation.PackageFileName); GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 5, 9, "[5/9] Package Download")); Log.INFO("[Package] Download Start"); downloader.DownloadFile(downloadUrl, targetPath); Log.INFO("[Package] Download End"); if (Settings.UserClientVersion.PackageDirectorys != null) { foreach (var item in Settings.UserClientVersion.PackageDirectorys) { var directoryInfo = new System.IO.DirectoryInfo(System.IO.Path.GetFullPath(item)); if (directoryInfo.Exists) { directoryInfo.Delete(true); Log.INFO("[Package] -[D] " + directoryInfo.FullName); } } } if (dataPatchInformation.PackageDirectorys != null) { foreach (var item in dataPatchInformation.PackageDirectorys) { var directoryInfo = new System.IO.DirectoryInfo(System.IO.Path.GetFullPath(item)); if (directoryInfo.Exists) { directoryInfo.Delete(true); Log.INFO("[Package] -[D] " + directoryInfo.FullName); } } } // 패키지 언팩 var progressPacker = new ProgressPacker(); var unpackPath = System.IO.Path.GetFullPath(rootDirectoryInfo.FullName); GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 6, 9, "[6/9] Package Unpack")); Log.INFO("[Package] Unpack Start"); progressPacker.UnPack(targetPath, unpackPath, new BasicProgress(p => Change(p))); Settings.UserClientVersion.PackageVersion = remoteVersion.ToString(); //임시파일 삭제 System.IO.File.Delete(targetPath); Log.INFO("[Package] -[F] " + targetPath); Log.INFO("[Package] Unpack End"); Settings.UserClientVersion.ComponentVersion = "0.0.0.0"; } #endregion Package Update #region Coomponent Update GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 7, 9, "[7/9] Component Version Check")); Log.INFO("[Component] Version Check"); thisVersion = Version.Parse(Settings.UserClientVersion.ComponentVersion); remoteVersion = Version.Parse(dataPatchInformation.ComponentVersion); CommonLibrary.Log.INFO("[Component] LocalVersion : " + thisVersion); CommonLibrary.Log.INFO("[Component] RemoteVersion : " + remoteVersion); result = remoteVersion.CompareTo(thisVersion); if (result == 0) { CommonLibrary.Log.INFO("[Component] Version Same"); } else { // 제거된 폴더 삭제 var resultDirectorys = new List(); foreach (var directory in Settings.UserClientVersion.ComponentDirectorys) { if (!dataPatchInformation.ComponentDirectorys.Contains(directory)) { resultDirectorys.Add(directory); } } foreach (var directory in resultDirectorys) { var directoryPath = System.IO.Path.GetFullPath(CommonLibrary.Extensions.PathCombineW(Settings.UserLauncherConfig.GameDirectory,Settings.NowProfile.ServerName, directory)); if (System.IO.Directory.Exists(directoryPath)) { System.IO.Directory.Delete(directoryPath, true); Log.INFO("[Component] -[D] " + directoryPath); } } var reverseDirectorys = dataPatchInformation.ComponentDirectorys; reverseDirectorys.Reverse(); string gameDirectory = CommonLibrary.Extensions.PathCombineW(Settings.UserLauncherConfig.GameDirectory, Settings.NowProfile.ServerName) + "\\"; foreach (var directory in reverseDirectorys) { var directoryPath = System.IO.Path.GetFullPath(CommonLibrary.Extensions.PathCombineW(Settings.UserLauncherConfig.GameDirectory, Settings.NowProfile.ServerName, directory)); if (System.IO.Directory.Exists(directoryPath)) { var lowDirectorys = System.IO.Directory.GetDirectories(directoryPath); foreach (var lowDirectory in lowDirectorys) { var directoryName = lowDirectory.Replace(gameDirectory, string.Empty); directoryName = directoryName.Replace("\\", "/"); if (!dataPatchInformation.ComponentDirectorys.Contains(directoryName)) { System.IO.Directory.Delete(lowDirectory, true); Log.INFO("[Component] -[D] " + directoryPath); } } } } foreach (var directory in dataPatchInformation.ComponentDirectorys) { var directoryPath = System.IO.Path.GetFullPath(CommonLibrary.Extensions.PathCombineW(Settings.UserLauncherConfig.GameDirectory, Settings.NowProfile.ServerName, directory)); if (!System.IO.Directory.Exists(directoryPath)) { System.IO.Directory.CreateDirectory(directoryPath); Log.INFO("[Component] +[D] " + directoryPath); } } var auditFile = new AuditFile(); var localFiles = auditFile.GetLocalFileList(dataPatchInformation.ComponentDirectorys); var removeFiles = auditFile.GetRemoveFiles(localFiles, dataPatchInformation.ComponentList); var needFiles = auditFile.GetNeedFiles(localFiles, dataPatchInformation.ComponentList); //var customFiles = foreach (var fileDetail in removeFiles) { var filePath = CommonLibrary.Extensions.PathCombineW(Settings.UserLauncherConfig.GameDirectory,Settings.NowProfile.ServerName, fileDetail.Directory, fileDetail.FileName); FileInfo fileInfo= new FileInfo(filePath); fileInfo.IsReadOnly = false; if (fileInfo.Exists) { Log.INFO("[Component] -[F] " + filePath); fileInfo.Delete(); } } // 디렉토리 삭제 GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 8, 9, "[8/9] Component Download")); Log.INFO("[Component] Download Start"); for (int i = 0; i < needFiles.Count; i++) { var url = CommonLibrary.Extensions.PathCombineL(Settings.ServerBaseUrl, "Servers", Settings.NowProfile.ServerName, dataPatchInformation.ComponentUrl, needFiles[i].Directory, needFiles[i].FileName); var path = CommonLibrary.Extensions.PathCombineW(Settings.UserLauncherConfig.GameDirectory,Settings.NowProfile.ServerName, needFiles[i].Directory, needFiles[i].FileName); downloader.DownloadFile(url, path); Log.INFO("[Component] +[F] " + path); } Log.INFO("[Component] Download End"); Settings.UserClientVersion.ComponentVersion = remoteVersion.ToString(); Settings.UserClientVersion.ComponentDirectorys = dataPatchInformation.ComponentDirectorys; #endregion Coomponent Update } // 커스텀 폴더, Config #region CustomData // 삭제된 파일 찾기 string rootCustomPath = System.IO.Path.GetFullPath(CommonLibrary.Extensions.PathCombineW(Settings.CustomDataDirectory, Settings.NowProfile.ServerName)); if(!System.IO.Directory.Exists(CommonLibrary.Extensions.PathCombineW(rootCustomPath, "config"))) { System.IO.Directory.CreateDirectory(CommonLibrary.Extensions.PathCombineW(rootCustomPath, "config")); } if (!System.IO.Directory.Exists(CommonLibrary.Extensions.PathCombineW(rootCustomPath, "mods"))) { System.IO.Directory.CreateDirectory(CommonLibrary.Extensions.PathCombineW(rootCustomPath, "mods")); } List files = new List(); files.AddRange(System.IO.Directory.GetFiles(CommonLibrary.Extensions.PathCombineW(rootCustomPath, "config"))); files.AddRange(System.IO.Directory.GetFiles(CommonLibrary.Extensions.PathCombineW(rootCustomPath, "mods"))); for (int i = 0; i < files.Count; i++) { files[i] = files[i].Replace(rootCustomPath + '\\', string.Empty); } foreach (var file in files) { string sourcePath = CommonLibrary.Extensions.PathCombineW(rootCustomPath, file); string targetPath = CommonLibrary.Extensions.PathCombineW( Settings.UserLauncherConfig.GameDirectory, Settings.NowProfile.ServerName,file); if (System.IO.File.Exists(targetPath)) { System.IO.FileInfo sourceFile = new System.IO.FileInfo(sourcePath); System.IO.FileInfo targetFile = new System.IO.FileInfo(targetPath); if (sourceFile.GetFileHashCode() != targetFile.GetFileHashCode()) { System.IO.File.Copy(sourcePath, targetPath,true); Log.INFO("[CustomData] +[F] " + targetPath); } } else { System.IO.File.Copy(sourcePath, targetPath); Log.INFO("[CustomData] +[F] " + targetPath); } //Settings.UserLauncherConfig.CustomData = files; Settings.SaveUserLauncherConfig(); } #endregion CustomData GameUpdateManagerMessage(this, new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.First, 9, 9, "[9/9] Update Complete")); Log.INFO("GameUpdate All Success"); return GameUpdateStatus.Success; } private void Change(double value) { var e = new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.Second, (long)(value * 100), 100, string.Empty); GameUpdateManagerMessage?.Invoke(this, e); } private void Downloader_DownloaderProgressChangedEvent(object sender, DownloaderProgressChangedEventArgs downloaderProgressChangedEventArgs) { var e = new GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType.Second, downloaderProgressChangedEventArgs.ProcessedByte, downloaderProgressChangedEventArgs.FileSize, string.Empty); GameUpdateManagerMessage?.Invoke(this, e); } } public enum GameUpdateStatus { Success, Fail } public enum GameUpdateManagerMessageType { First, Second, Message } public class GameUpdateManagerMessageEventArgs : EventArgs { public GameUpdateManagerMessageType MessageType { get; set; } public long MinValue { get; set; } public long MaxValue { get; set; } public string Message { get; set; } public GameUpdateManagerMessageEventArgs(GameUpdateManagerMessageType messageType, long minValue, long maxValue, string message) { MessageType = messageType; MinValue = minValue; MaxValue = maxValue; Message = message; } } }