From 32cebcf8e28159ace19b3d4778edba04607930b4 Mon Sep 17 00:00:00 2001
From: yyl <yyl>
Date: 星期二, 20 五月 2025 18:54:09 +0800
Subject: [PATCH] 搬运流程

---
 Main/Core/GameEngine/Login.meta                            |    8 
 Main/Common/SevenZip/lzma.cs                               |  873 ++++++++++++++++++
 Main/Core/GameEngine/Launch/GetVersionInfoTask.cs.meta     |   11 
 Main/Core/GameEngine/Launch/InitSettingTask.cs             |   54 +
 Main/Core/GameEngine/Launch/DownLoadAssetTask.cs.meta      |   11 
 Main/Core/GameEngine/Launch/GetVersionInfoTask.cs          |   78 +
 Main/Common/SevenZip.meta                                  |    8 
 Main/Core/GameEngine/Launch/DownLoadAssetTask.cs           |  277 +++++
 Main/Core/GameEngine/Launch/RequestPermissionStart.cs.meta |   11 
 Main/Utility/ShaderUtility.cs.meta                         |   11 
 Main/Core/GameEngine/Launch/LaunchStage.cs.meta            |   11 
 Main/Core/GameEngine/Launch/SDKInitedTask.cs.meta          |   11 
 Main/Core/GameEngine/Launch/AssetDeCompressTask.cs         |  204 ++++
 Main/Core/GameEngine/Launch/CheckAssetValidTask.cs         |   73 +
 Main/Core/GameEngine/Launch.meta                           |    8 
 Main/Core/GameEngine/Launch/BuiltInAssetCopyTask.cs.meta   |   11 
 Main/Core/GameEngine/Launch/LaunchInHot.cs.meta            |   11 
 Main/Core/GameEngine/Launch/RequestPermissionStart.cs      |   38 
 Main/Core/GameEngine/Launch/CheckAssetValidTask.cs.meta    |   11 
 Main/Common/SevenZip/lzma.cs.meta                          |    8 
 Main/Manager/ResManager.cs                                 |   11 
 Main/Core/GameEngine/Launch/InitSettingTask.cs.meta        |   11 
 Main/Utility/SevenZipUtility.cs                            |   45 
 Main/Utility/SevenZipUtility.cs.meta                       |   11 
 Main/Core/GameEngine/Launch/LaunchProgressInfo.cs.meta     |   11 
 Main/Core/GameEngine/Launch/BuiltInAssetCopyTask.cs        |  249 +++++
 Main/Manager/StageManager.cs                               |   14 
 Main/Core/GameEngine/Launch/AssetCopyTask.cs               |  266 +++++
 Main/Core/GameEngine/Launch/AssetCopyTask.cs.meta          |   11 
 Main/Core/GameEngine/Launch/LaunchProgressInfo.cs          |   17 
 Main/Core/GameEngine/Launch/LaunchTask.cs                  |   34 
 Main/Core/GameEngine/Launch/LaunchTask.cs.meta             |   11 
 Main/ResModule/AssetBundle/AssetBundleUtility.cs           |   77 
 Main/Core/GameEngine/Launch/LaunchInHot.cs                 |  180 +++
 Main/Core/GameEngine/Launch/LaunchStage.cs                 |   14 
 Main/Core/GameEngine/Launch/SDKInitedTask.cs               |   58 +
 Main/Core/GameEngine/Launch/AssetDeCompressTask.cs.meta    |   11 
 Main/Utility/ShaderUtility.cs                              |   28 
 38 files changed, 2,738 insertions(+), 49 deletions(-)

diff --git a/Main/Common/SevenZip.meta b/Main/Common/SevenZip.meta
new file mode 100644
index 0000000..6249fdc
--- /dev/null
+++ b/Main/Common/SevenZip.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 00dea6db89fa7bf48906e1612fbf177e
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Common/SevenZip/lzma.cs b/Main/Common/SevenZip/lzma.cs
new file mode 100644
index 0000000..65ec84b
--- /dev/null
+++ b/Main/Common/SevenZip/lzma.cs
@@ -0,0 +1,873 @@
+#if !(UNITY_IOS || UNITY_IPHONE)
+using System;
+using System.Runtime.InteropServices;
+using UnityEngine;
+using System.Collections.Generic;
+using System.IO;
+
+
+#if (UNITY_WSA_8_1 || UNITY_WP_8_1 || UNITY_WINRT_8_1) && !UNITY_EDITOR
+ using File = UnityEngine.Windows.File;
+#else
+using File = System.IO.File;
+#endif
+
+#if NETFX_CORE
+#if UNITY_WSA_10_0
+		using System.IO.IsolatedStorage;
+		using static System.IO.Directory;
+		using static System.IO.File;
+		using static System.IO.FileStream;
+#endif
+#endif
+
+
+public class lzma
+{
+
+    //if you want to be able to call the functions: get7zinfo, get7zSize, decode2Buffer from a thread set this string before to the Application.persistentDataPath !
+    public static string persitentDataPath = "";
+
+#if !(UNITY_WSA || UNITY_WP_8_1) || UNITY_EDITOR
+
+    internal static int[] props = new int[7];
+    internal static bool defaultsSet = false;
+
+    //0 = level, /* 0 <= level <= 9, default = 5 */
+    //1 = dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */
+    //2 = lc, /* 0 <= lc <= 8, default = 3  */
+    //3 = lp, /* 0 <= lp <= 4, default = 0  */
+    //4 = pb, /* 0 <= pb <= 4, default = 2  */
+    //5 = fb,  /* 5 <= fb <= 273, default = 32 */
+    //6 = numThreads /* 1 or 2, default = 2 */
+
+    //A function that sets the compression properties for the lzma compressor. Will affect the lzma alone file and the lzma buffer compression.
+    //A simple usage of this function is to call it only with the 1st parameter that sets the compression level: setProps(9);
+    //
+    //Multithread safe advice: call this function before starting any thread operations !!!
+    public static void setProps(int level = 5, int dictSize = 16777216, int lc = 3, int lp = 0, int pb = 2, int fb = 32, int numThreads = 2)
+    {
+        defaultsSet = true;
+        props[0] = level;
+        props[1] = dictSize;
+        props[2] = lc;
+        props[3] = lp;
+        props[4] = pb;
+        props[5] = fb;
+        props[6] = numThreads;
+    }
+#endif
+
+
+#if (UNITY_WEBGL) && !UNITY_EDITOR
+
+#if (!UNITY_WEBGL)
+			[DllImport("__Internal")]
+			public static extern int lsetPermissions(string filePath, string _user, string _group, string _other);
+			[DllImport("__Internal")]
+			private static extern int decompress7zip(string filePath, string exctractionPath, bool fullPaths,  string entry, IntPtr progress, IntPtr FileBuffer, int FileBufferLength);
+#endif
+
+		[DllImport("__Internal")]
+		private static extern int decompress7zip2(string filePath, string exctractionPath, bool fullPaths, string entry, IntPtr progress, IntPtr FileBuffer, int FileBufferLength);
+		[DllImport("__Internal")]
+		private static extern int _getSize(string filePath, string tempPath, IntPtr FileBuffer, int FileBufferLength);
+		[DllImport("__Internal")]
+		internal static extern int lzmaUtil(bool encode, string inPath, string outPath, IntPtr Props);
+		[DllImport("__Internal")]
+		internal static extern int decode2Buf(string filePath, string entry,  IntPtr buffer, IntPtr FileBuffer, int FileBufferLength);
+		[DllImport("__Internal")]
+		internal static extern void _releaseBuffer(IntPtr buffer);	
+		[DllImport("__Internal")]
+		internal static extern IntPtr Lzma_Compress( IntPtr buffer, int bufferLength, bool makeHeader, ref int v, IntPtr Props);
+		[DllImport("__Internal")]
+		internal static extern int Lzma_Uncompress( IntPtr buffer, int bufferLength, int uncompressedSize,  IntPtr outbuffer,bool useHeader);
+#endif
+
+#if UNITY_5_4_OR_NEWER
+#if (UNITY_ANDROID || UNITY_STANDALONE_LINUX) && (!UNITY_EDITOR || UNITY_EDITOR_LINUX)
+		private const string libname = "lzma";
+#elif UNITY_EDITOR || UNITY_STANDALONE_WIN 
+    private const string libname = "liblzma";
+#endif
+#else
+#if (UNITY_ANDROID || UNITY_STANDALONE_LINUX) && !UNITY_EDITOR
+		private const string libname = "lzma";
+#endif
+#if UNITY_EDITOR || UNITY_STANDALONE_WIN 
+		private const string libname = "liblzma";
+#endif
+#endif
+
+#if UNITY_EDITOR || UNITY_STANDALONE_WIN ||  UNITY_ANDROID || UNITY_STANDALONE_LINUX
+#if ( UNITY_STANDALONE_LINUX || UNITY_ANDROID ||  UNITY_EDITOR_LINUX) && !UNITY_EDITOR_WIN
+			//set permissions of a file in user, group, other. Each string should contain any or all chars of "rwx".
+			//returns 0 on success
+			[DllImport(libname, EntryPoint = "lsetPermissions")]
+			internal static extern int lsetPermissions(string filePath, string _user, string _group, string _other);
+#endif
+    [DllImport(libname, EntryPoint = "decompress7zip")]
+    internal static extern int decompress7zip(string filePath, string exctractionPath, bool fullPaths, string entry, IntPtr progress, IntPtr FileBuffer, int FileBufferLength);
+    [DllImport(libname, EntryPoint = "decompress7zip2")]
+    internal static extern int decompress7zip2(string filePath, string exctractionPath, bool fullPaths, string entry, IntPtr progress, IntPtr FileBuffer, int FileBufferLength);
+    [DllImport(libname, EntryPoint = "_getSize")]
+    internal static extern int _getSize(string filePath, string tempPath, IntPtr FileBuffer, int FileBufferLength);
+    [DllImport(libname, EntryPoint = "lzmaUtil")]
+    internal static extern int lzmaUtil(bool encode, string inPath, string outPath, IntPtr Props);
+    [DllImport(libname, EntryPoint = "decode2Buf")]
+    internal static extern int decode2Buf(string filePath, string entry, IntPtr buffer, IntPtr FileBuffer, int FileBufferLength);
+    [DllImport(libname, EntryPoint = "_releaseBuffer")]
+    internal static extern void _releaseBuffer(IntPtr buffer);
+    [DllImport(libname, EntryPoint = "Lzma_Compress")]
+    internal static extern IntPtr Lzma_Compress(IntPtr buffer, int bufferLength, bool makeHeader, ref int v, IntPtr Props);
+    [DllImport(libname, EntryPoint = "Lzma_Uncompress")]
+    internal static extern int Lzma_Uncompress(IntPtr buffer, int bufferLength, int uncompressedSize, IntPtr outbuffer, bool useHeader);
+#endif
+
+#if (UNITY_WP_8_1 || UNITY_WSA) && !UNITY_EDITOR
+#if UNITY_WSA_10_0
+            [DllImport("liblzma", EntryPoint = "decompress7zip")]
+			internal static extern int decompress7zip(string filePath, string exctractionPath, bool fullPaths,  string entry, IntPtr progress, IntPtr FileBuffer, int FileBufferLength);
+#endif
+		[DllImport("liblzma", EntryPoint = "decompress7zip2")]
+		internal static extern int decompress7zip2(string filePath, string exctractionPath, bool fullPaths, string entry, IntPtr progress, IntPtr FileBuffer, int FileBufferLength);
+		[DllImport("liblzma", EntryPoint = "_getSize")]
+		internal static extern int _getSize(string filePath, string tempPath, IntPtr FileBuffer, int FileBufferLength);
+		[DllImport("liblzma", EntryPoint = "decode2Buf")]
+		internal static extern int decode2Buf(string filePath, string entry,  IntPtr buffer, IntPtr FileBuffer, int FileBufferLength);
+		[DllImport("liblzma", EntryPoint = "Lzma_Uncompress")]
+		internal static extern int Lzma_Uncompress( IntPtr buffer, int bufferLength, int uncompressedSize, IntPtr outbuffer,bool useHeader);
+#endif
+
+
+    // set permissions of a file in user, group, other.
+    // Each string should contain any or all chars of "rwx".
+    // returns 0 on success
+    public static int setFilePermissions(string filePath, string _user, string _group, string _other)
+    {
+#if (UNITY_STANDALONE_LINUX || UNITY_ANDROID ||  UNITY_EDITOR_LINUX) && !UNITY_EDITOR_WIN
+			return lsetPermissions(filePath, _user, _group, _other);
+#else
+        return -1;
+#endif
+    }
+
+    // An integer variable to store the total number of files in a 7z archive, excluding the folders.
+    public static int trueTotalFiles = 0;
+
+    //ERROR CODES:
+    //  1 : OK
+    //	2 : Could not find requested file in archive
+    // -1 : Could not open input(7z) file
+    // -2 : Decoder doesn't support this archive
+    // -3 : Can not allocate memory
+    // -4 : CRC error of 7z file
+    // -5 : Unknown error
+    // -6 : Can not open output file (usually when the path to write to, is invalid)
+    // -7 : Can not write output file
+    // -8 : Can not close output file
+
+    //The most common use of this library is to download a 7z file in your Application.persistentDataPath directory
+    //and decompress it in a folder that you want.
+
+    //int lz=lzma.doDecompress7zip(Application.persistentDataPath+"/myCompresedFile.7z",Application.persistentDataPath+"/myUncompressedFiles/");
+
+    //WSA8.1 does not support large files.
+
+    //filePath			: the full path to the archive, including the archives name. (/myPath/myArchive.7z)
+    //exctractionPath	: the path in where you want your files to be extracted
+    //progress          : a single item integer array to get the progress of the extracted files (use this function when calling from a separate thread, otherwise call the 2nd implementation)
+    //                  : (for ios this integer is not properly updated. So we use the lzma.getProgressCount() function to get the progress. See example.)
+    //largeFiles		: set this to true if you are extracting files larger then 30-40 Mb. It is slower though but prevents crashing your app when extracting large files!
+    //fullPaths			: set this to true if you want to keep the folder structure of the 7z file.
+    //entry				: set the name of a single file file you want to extract from your archive. If the file resides in a folder, the full path should be added.
+    //					   (for example  game/meshes/small/table.mesh )
+    //FileBuffer		: A buffer that holds a 7zip file. When assigned the function will decompress from this buffer and will ignore the filePath. (Linux, iOS, Android, MacOSX)
+    //use this function from a separate thread to get the progress  of the extracted files in the referenced 'progress' integer.
+    //
+    public static int doDecompress7zip(string filePath, string exctractionPath, int[] progress, bool largeFiles = false, bool fullPaths = false, string entry = null, byte[] FileBuffer = null)
+    {
+
+        int res = 0;
+        GCHandle ibuf = GCHandle.Alloc(progress, GCHandleType.Pinned);
+
+#if (UNITY_ANDROID || UNITY_STANDALONE_LINUX || UNITY_EDITOR) && !UNITY_EDITOR_WIN
+
+		if(FileBuffer != null) {
+			GCHandle fbuf = GCHandle.Alloc(FileBuffer, GCHandleType.Pinned);
+			
+				
+			if (largeFiles){
+				res = decompress7zip(null, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject() , fbuf.AddrOfPinnedObject(), FileBuffer.Length);
+			}else{
+				res =  decompress7zip2(null, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject() , fbuf.AddrOfPinnedObject(), FileBuffer.Length);
+			}
+				fbuf.Free(); ibuf.Free(); return res;
+		} else {
+			if (largeFiles){
+				res = decompress7zip(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject() , IntPtr.Zero, 0);
+				ibuf.Free(); return res;
+			}else{
+				res = decompress7zip2(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject() , IntPtr.Zero, 0);
+				ibuf.Free(); return res;
+			}
+		}
+		
+#endif
+
+#if (!UNITY_WSA && !UNITY_WEBGL && !UNITY_STANDALONE_LINUX && !UNITY_ANDROID) || UNITY_EDITOR_WIN || UNITY_WSA_10_0
+        if (largeFiles)
+        {
+            res = decompress7zip(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+            ibuf.Free(); return res;
+        }
+        else
+        {
+            res = decompress7zip2(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+            ibuf.Free(); return res;
+        }
+#endif
+
+#if (UNITY_WSA_8_1 || UNITY_WP_8_1 || UNITY_WINRT_8_1 || UNITY_WEBGL) && !UNITY_EDITOR
+			res = decompress7zip2(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+			ibuf.Free(); return res;
+#endif
+    }
+
+    //same as above only the progress integer is a local variable.
+    //use this when you don't want to get the progress of the extracted files and when not calling the function from a separate thread.
+    public static int doDecompress7zip(string filePath, string exctractionPath, bool largeFiles = false, bool fullPaths = false, string entry = null, byte[] FileBuffer = null)
+    {
+        //make a check if the last '/' exists at the end of the exctractionPath and add it if it is missing
+        if (@exctractionPath.Substring(@exctractionPath.Length - 1, 1) != "/") { @exctractionPath += "/"; }
+
+        int[] progress = new int[1];
+        GCHandle ibuf = GCHandle.Alloc(progress, GCHandleType.Pinned);
+        int res = 0;
+
+#if (UNITY_ANDROID || UNITY_STANDALONE_LINUX || UNITY_EDITOR) && !UNITY_EDITOR_WIN
+		if(FileBuffer != null) {
+			GCHandle fbuf = GCHandle.Alloc(FileBuffer, GCHandleType.Pinned);
+			
+			
+			if (largeFiles){
+				res = decompress7zip(null, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), fbuf.AddrOfPinnedObject(), FileBuffer.Length);
+			}else{
+				res = decompress7zip2(null, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), fbuf.AddrOfPinnedObject(), FileBuffer.Length);
+			}
+				fbuf.Free(); ibuf.Free(); return res;
+		} else {
+			if (largeFiles){
+				res = decompress7zip(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+				ibuf.Free(); return res;
+			}else{
+				res = decompress7zip2(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+				ibuf.Free(); return res;
+			}
+		}
+#endif
+
+#if (!UNITY_WSA && !UNITY_WEBGL && !UNITY_STANDALONE_LINUX && !UNITY_ANDROID) || UNITY_EDITOR_WIN || UNITY_WSA_10_0
+        if (largeFiles)
+        {
+            res = decompress7zip(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+            ibuf.Free(); return res;
+        }
+        else
+        {
+            res = decompress7zip2(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+            ibuf.Free(); return res;
+        }
+#endif
+
+#if (UNITY_WSA_8_1 || UNITY_WP_8_1 || UNITY_WINRT_8_1 || UNITY_WEBGL) && !UNITY_EDITOR
+			res = decompress7zip2(@filePath, @exctractionPath, fullPaths, entry, ibuf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+			ibuf.Free(); return res;
+#endif
+    }
+
+
+#if !(UNITY_WSA || UNITY_WP_8_1) || UNITY_EDITOR
+    //ERROR CODES (for both encode/decode LzmaUtil functions):
+    //   1 : OK
+    // -10 : Can not read input file
+    // -11 : Can not write output file
+    // -12 : Can not allocate memory
+    // -13 : Data error
+
+    //This function encodes a single archive in lzma alone format.
+    //inPath	: the file to be encoded. (use full path + file name)
+    //outPath	: the .lzma file that will be produced. (use full path + file name)
+    //
+    //You can set the compression properties by calling the setProps function before.
+    //setProps(9) for example will set compression evel to highest level.
+    public static int LzmaUtilEncode(string inPath, string outPath)
+    {
+        if (!defaultsSet) setProps();
+        GCHandle prps = GCHandle.Alloc(props, GCHandleType.Pinned);
+        int res = lzmaUtil(true, @inPath, @outPath, prps.AddrOfPinnedObject());
+        prps.Free();
+        return res;
+    }
+
+
+    //This function decodes a single archive in lzma alone format.
+    //inPath	: the .lzma file that will be decoded. (use full path + file name)
+    //outPath	: the decoded file. (use full path + file name)
+    public static int LzmaUtilDecode(string inPath, string outPath)
+    {
+        return lzmaUtil(false, @inPath, @outPath, IntPtr.Zero);
+    }
+
+#endif
+
+    //Lists get filled with filenames (including path if the file is in a folder) and uncompressed file sizes
+    public static List<string> ninfo = new List<string>();//filenames
+    public static List<long> sinfo = new List<long>();//file sizes
+
+    //this function fills the ArrayLists with the filenames and file sizes that are in the 7zip file
+    //returns			: the total size in bytes of the files in the 7z archive 
+    //
+    //filePath			: the full path to the archive, including the archives name. (/myPath/myArchive.7z)
+    //tempPath			: (optional) a temp path that will be used to write the files info (otherwise the path of the 7z archive will be used)
+    //					: this is useful when your 7z archive resides in a read only location.
+    //					: the tempPath should be in this form: 'dir/dir/myTempLog' with no slash in the end. The last name will be used as the log's filename.
+    //FileBuffer		: A buffer that holds a 7zip file. When assigned the function will read from this buffer and will ignore the filePath. (Linux, iOS, Android, MacOSX)
+    //
+    //trueTotalFiles is an integer variable to store the total number of files in a 7z archive, excluding the folders.
+    public static long get7zInfo(string filePath, string tempPath = null, byte[] FileBuffer = null)
+    {
+
+        ninfo.Clear(); sinfo.Clear();
+        trueTotalFiles = 0;
+        int res = -1;
+        string logPath = "";
+
+#if !NETFX_CORE
+        if (@tempPath == null)
+        {
+            if (persitentDataPath.Length > 0) logPath = @persitentDataPath + "/sevenZip.log"; else logPath = @Application.persistentDataPath + "/sevenZip.log";
+        }
+        else { logPath = @tempPath; }
+#endif
+        //for WSA, logPath should always be: Application.persistentDataPath + "/sevenZip.log"; 
+#if NETFX_CORE
+#if UNITY_WSA_10_0
+				if(persitentDataPath.Length>0) logPath = @persitentDataPath + "/sevenZip.log"; else  logPath = @Application.persistentDataPath + "/sevenZip.log";
+#endif
+#if UNITY_WSA_8_1 || UNITY_WP_8_1 || UNITY_WINRT_8_1
+				if(persitentDataPath.Length>0) logPath = @persitentDataPath + "/sevenZip.log"; else  logPath = @UnityEngine.Windows.Directory.localFolder + "/sevenZip.log";
+#endif
+#endif
+
+        if (File.Exists(logPath + ".txt")) File.Delete(logPath + ".txt");
+
+#if (UNITY_ANDROID || UNITY_STANDALONE_LINUX || UNITY_EDITOR) && !UNITY_EDITOR_WIN
+          if(FileBuffer != null) {
+                GCHandle fbuf = GCHandle.Alloc(FileBuffer, GCHandleType.Pinned);
+                res = _getSize(null, logPath,  fbuf.AddrOfPinnedObject(), FileBuffer.Length);
+                fbuf.Free();
+            }else {
+                res = _getSize(@filePath, logPath,  IntPtr.Zero, 0);
+            }
+#else
+        res = _getSize(@filePath, logPath, IntPtr.Zero, 0);
+#endif
+
+        if (res == -1) { /*Debug.Log("Input file not found.");*/ return -1; }
+
+        if (!File.Exists(logPath + ".txt")) {/* Debug.Log("Info file not found.");*/ return -3; }
+
+#if !NETFX_CORE
+        StreamReader r = new StreamReader(logPath + ".txt");
+#endif
+#if NETFX_CORE
+#if UNITY_WSA_10_0
+			IsolatedStorageFile ipath = IsolatedStorageFile.GetUserStoreForApplication();
+			StreamReader r = new StreamReader(new IsolatedStorageFileStream("sevenZip.log.txt", FileMode.Open, ipath));
+#endif
+#if UNITY_WSA_8_1 || UNITY_WP_8_1 || UNITY_WINRT_8_1
+			var data = UnityEngine.Windows.File.ReadAllBytes(logPath + ".txt");
+			string ss = System.Text.Encoding.UTF8.GetString(data,0,data.Length);
+			StringReader r = new StringReader(ss);
+#endif
+#endif
+
+        string line;
+        string[] rtt;
+        long t = 0, sum = 0;
+
+        while ((line = r.ReadLine()) != null)
+        {
+            rtt = line.Split('|');
+            ninfo.Add(rtt[0]);
+            long.TryParse(rtt[1], out t);
+            sum += t;
+            sinfo.Add(t);
+            if (t > 0) trueTotalFiles++;
+        }
+
+#if !NETFX_CORE
+        r.Close();
+#endif
+        r.Dispose();
+        File.Delete(logPath + ".txt");
+
+        return sum;
+    }
+
+
+    //this function returns the uncompressed file size of a given file in the 7z archive if specified,
+    //otherwise it will return the total uncompressed size of all the files in the archive.
+    //
+    //If you don't fill the filePath parameter it will assume that the get7zInfo function has already been called.
+    //
+    //
+    //filePath			: the full path to the archive, including the archives name. (/myPath/myArchive.7z)
+    // 					: if you call the function with filePath as null, it will try to find file sizes from the last call.
+    //fileName 			: the file name we want to get the file size (if it resides in a folder add the folder path also)
+    //tempPath			: (optional) a temp path that will be used to write the files info (otherwise the path of the 7z archive will be used)
+    //					: this is useful when your 7z archive resides in a read only location.
+    //					: the tempPath should be in this form: 'dir/dir/myTempLog' with no slash in the end. The last name will be used as the log's filename.
+    //FileBuffer		: A buffer that holds a 7zip file. When assigned the function will read from this buffer and will ignore the filePath. (Linux, iOS, Android, MacOSX)
+    public static long get7zSize(string filePath = null, string fileName = null, string tempPath = null, byte[] FileBuffer = null)
+    {
+
+        if (filePath != null)
+        {
+            if (get7zInfo(@filePath, @tempPath, FileBuffer) < 0) { return -1; }
+        }
+
+        if (ninfo == null)
+        {
+            if (ninfo.Count == 0) { return -1; }
+        }
+
+        long sum = 0;
+
+        if (fileName != null)
+        {
+            for (int i = 0; i < ninfo.Count; i++)
+            {
+                if (ninfo[i].ToString() == fileName)
+                {
+                    return (long)sinfo[i];
+                }
+            }
+        }
+        else
+        {
+            for (int i = 0; i < ninfo.Count; i++)
+            {
+                sum += (long)sinfo[i];
+            }
+            return sum;
+        }
+        return -1;//nothing was found
+    }
+
+
+
+    //A function to decode a specific archive in a 7z archive to a byte buffer
+    //
+    //filePath		: the full path to the 7z archive 
+    //entry			: the file name to decode to a buffer. If the file resides in a folder, the full path should be used.
+    //tempPath		: (optional) a temp path that will be used to write the files info (otherwise the path of the 7z archive will be used)
+    //				: this is useful when your 7z archive resides in a read only location.
+    //				: the tempPath should be in this form: 'dir/dir/myTempLog' with no slash in the end. The last name will be used as the log's filename.
+    //FileBuffer	: A buffer that holds a 7zip file. When assigned the function will read from this buffer and will ignore the filePath. (Linux, iOS, Android, MacOSX)
+    public static byte[] decode2Buffer(string filePath, string entry, string tempPath = null, byte[] FileBuffer = null)
+    {
+        int bufs = (int)get7zSize(@filePath, entry, @tempPath, FileBuffer);
+        if (bufs <= 0) return null;//entry error or it does not exist
+        byte[] nb = new byte[bufs];
+        int res = 0;
+
+        GCHandle dec2buf = GCHandle.Alloc(nb, GCHandleType.Pinned);
+
+#if (UNITY_ANDROID || UNITY_STANDALONE_LINUX || UNITY_EDITOR) && !UNITY_EDITOR_WIN
+          if(FileBuffer != null) {
+                GCHandle fbuf = GCHandle.Alloc(FileBuffer, GCHandleType.Pinned);
+                res = decode2Buf(null, entry, dec2buf.AddrOfPinnedObject(), fbuf.AddrOfPinnedObject(), FileBuffer.Length);
+                fbuf.Free();
+            }else {
+                res = decode2Buf(@filePath, entry, dec2buf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+            }
+#else
+        res = decode2Buf(@filePath, entry, dec2buf.AddrOfPinnedObject(), IntPtr.Zero, 0);
+#endif
+
+        dec2buf.Free();
+        if (res == 1) { return nb; }
+        else { nb = null; return null; }
+
+    }
+
+#if !(UNITY_WSA || UNITY_WP_8_1) || UNITY_EDITOR
+
+    //This function encodes inBuffer to lzma alone format into the outBuffer provided.
+    //The buffer can be saved also into a file and can be opened by applications that opens the lzma alone format.
+    //This buffer can be uncompressed by the decompressBuffer function.
+    //Returns true if success
+    //if makeHeader==false then the lzma 13 bytes header will not be added to the buffer.
+    //
+    //You can set the compression properties by calling the setProps function before.
+    //setProps(9) for example will set compression level to the highest level.
+    //
+    public static bool compressBuffer(byte[] inBuffer, ref byte[] outBuffer, bool makeHeader = true)
+    {
+
+        if (!defaultsSet) setProps();
+        GCHandle prps = GCHandle.Alloc(props, GCHandleType.Pinned);
+
+        GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+        IntPtr ptr;
+
+        int res = 0;
+
+        ptr = Lzma_Compress(cbuf.AddrOfPinnedObject(), inBuffer.Length, makeHeader, ref res, prps.AddrOfPinnedObject());
+
+        cbuf.Free(); prps.Free();
+
+        if (res == 0 || ptr == IntPtr.Zero) { _releaseBuffer(ptr); return false; }
+
+        Array.Resize(ref outBuffer, res);
+        Marshal.Copy(ptr, outBuffer, 0, res);
+
+        _releaseBuffer(ptr);
+
+        return true;
+    }
+
+
+    //same as the above function, only it compresses a part of the input buffer.
+    //
+    //inBufferPartialLength: the size of the input buffer that should be compressed
+    //inBufferPartialIndex:  the offset of the input buffer from where the compression will start
+    //
+    public static bool compressBufferPartial(byte[] inBuffer, int inBufferPartialIndex, int inBufferPartialLength, ref byte[] outBuffer, bool makeHeader = true)
+    {
+        if (inBufferPartialIndex + inBufferPartialLength > inBuffer.Length) return false;
+
+        if (!defaultsSet) setProps();
+        GCHandle prps = GCHandle.Alloc(props, GCHandleType.Pinned);
+        GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+
+        IntPtr ptr;
+        IntPtr ptrPartial;
+
+        int res = 0;
+
+        ptrPartial = new IntPtr(cbuf.AddrOfPinnedObject().ToInt64() + inBufferPartialIndex);
+
+        ptr = Lzma_Compress(ptrPartial, inBufferPartialLength, makeHeader, ref res, prps.AddrOfPinnedObject());
+
+        cbuf.Free();
+
+        if (res == 0 || ptr == IntPtr.Zero) { _releaseBuffer(ptr); return false; }
+
+        Array.Resize(ref outBuffer, res);
+        Marshal.Copy(ptr, outBuffer, 0, res);
+
+        _releaseBuffer(ptr);
+
+        return true;
+    }
+
+
+    //same as compressBufferPartial, only this function will compress the data into a fixed size buffer
+    //the compressed size is returned so you can manipulate it at will.
+    public static int compressBufferPartialFixed(byte[] inBuffer, int inBufferPartialIndex, int inBufferPartialLength, ref byte[] outBuffer, bool safe = true, bool makeHeader = true)
+    {
+        if (inBufferPartialIndex + inBufferPartialLength > inBuffer.Length) return 0;
+
+        if (!defaultsSet) setProps();
+        GCHandle prps = GCHandle.Alloc(props, GCHandleType.Pinned);
+        GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+
+        IntPtr ptr;
+        IntPtr ptrPartial;
+
+        int res = 0;
+
+        ptrPartial = new IntPtr(cbuf.AddrOfPinnedObject().ToInt64() + inBufferPartialIndex);
+
+        ptr = Lzma_Compress(ptrPartial, inBufferPartialLength, makeHeader, ref res, prps.AddrOfPinnedObject());
+
+        cbuf.Free();
+
+        if (res == 0 || ptr == IntPtr.Zero) { _releaseBuffer(ptr); return 0; }
+
+        //if the compressed buffer is larger then the fixed size buffer we use:
+        //1. then write only the data that fit in it.
+        //2. or we return 0. 
+        //It depends on if we set the safe flag to true or not.
+        if (res > outBuffer.Length)
+        {
+            if (safe) { _releaseBuffer(ptr); return 0; } else { res = outBuffer.Length; }
+        }
+
+        Marshal.Copy(ptr, outBuffer, 0, res);
+
+        _releaseBuffer(ptr);
+
+        return res;
+    }
+
+
+    //same as the compressBuffer function, only this function will put the result in a fixed size buffer to avoid memory allocations.
+    //the compressed size is returned so you can manipulate it at will.
+    public static int compressBufferFixed(byte[] inBuffer, ref byte[] outBuffer, bool safe = true, bool makeHeader = true)
+    {
+
+        if (!defaultsSet) setProps();
+        GCHandle prps = GCHandle.Alloc(props, GCHandleType.Pinned);
+
+        GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+        IntPtr ptr;
+
+        int res = 0;
+
+        ptr = Lzma_Compress(cbuf.AddrOfPinnedObject(), inBuffer.Length, makeHeader, ref res, prps.AddrOfPinnedObject());
+
+        cbuf.Free(); prps.Free();
+        if (res == 0 || ptr == IntPtr.Zero) { _releaseBuffer(ptr); return 0; }
+
+        //if the compressed buffer is larger then the fixed size buffer we use:
+        //1. then write only the data that fit in it.
+        //2. or we return 0. 
+        //It depends on if we set the safe flag to true or not.
+        if (res > outBuffer.Length)
+        {
+            if (safe) { _releaseBuffer(ptr); return 0; } else { res = outBuffer.Length; }
+        }
+
+        Marshal.Copy(ptr, outBuffer, 0, res);
+
+        _releaseBuffer(ptr);
+
+        return res;
+    }
+
+#endif
+
+
+
+
+
+    //This function will decompress a compressed asset bundle.
+    //It finds the magic number of the lzma format and extracts from there.
+    //
+    //inBuffer:		the buffer that stores a compressed asset bundle.
+    //outBuffer:	a referenced buffer where the asset bundle will be uncompressed.
+    //The error codes
+    /*
+        OK 0
+		
+        ERROR_DATA 1
+        ERROR_MEM 2
+        ERROR_UNSUPPORTED 4
+        ERROR_PARAM 5
+        ERROR_INPUT_EOF 6
+        ERROR_OUTPUT_EOF 7
+        ERROR_FAIL 11
+        ERROR_THREAD 12
+    */
+    public static int decompressAssetBundle(byte[] inBuffer, ref byte[] outbuffer)
+    {
+
+        int offset = 0;
+
+        for (int i = 0; i < inBuffer.Length; i++)
+        {
+            if (i > 1024) break;
+            if (inBuffer[i] == 0x5d)
+            {
+                if (inBuffer[i + 1] == 0x00)
+                {
+                    if (inBuffer[i + 2] == 0x00)
+                    {
+                        if (inBuffer[i + 3] == 0x08)
+                        {
+                            offset = i; break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (offset == 0 || offset > 1024) return 4;
+
+        GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+        IntPtr ptrBundle = new IntPtr(cbuf.AddrOfPinnedObject().ToInt64() + offset);
+        int uncompressedSize = (int)BitConverter.ToUInt64(inBuffer, offset + 5);
+        if (uncompressedSize < 0) { cbuf.Free(); return 4; }
+        Array.Resize(ref outbuffer, uncompressedSize);
+        GCHandle obuf = GCHandle.Alloc(outbuffer, GCHandleType.Pinned);
+
+        int res = Lzma_Uncompress(ptrBundle, inBuffer.Length - offset, uncompressedSize, obuf.AddrOfPinnedObject(), true);
+
+        cbuf.Free();
+        obuf.Free();
+
+        //if(res!=0){/*Debug.Log("ERROR: "+res.ToString());*/ return res; }
+
+        return res;
+    }
+
+
+    /*
+	//this will decompress an lzma alone format file.
+	public static  int decompressLzmaAlone(string inFile,  string outFile){
+
+		if(File.Exists(inFile)) {
+			var inBuffer = File.ReadAllBytes(inFile);
+
+			int offset = 0;
+		
+			for(int i=0; i<inBuffer.Length; i++) {
+				if(i>16) break;
+				if(inBuffer[i] == 0x5d) {
+					if(inBuffer[i+1] == 0x00) {
+						if(inBuffer[i+2] == 0x00) {
+							if(inBuffer[i+3] == 0x00) {
+								offset = i;  break; 
+							}
+						}
+					}
+				}
+			}
+		
+			if(offset>16) {  inBuffer=null; return 4; }
+
+			GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+			IntPtr ptrBundle = new IntPtr(cbuf.AddrOfPinnedObject().ToInt64() + offset);
+			int uncompressedSize = (int)BitConverter.ToUInt64(inBuffer,offset+5);
+			if(uncompressedSize<0) { cbuf.Free(); return 4; }
+			byte[] outBuffer = new byte[uncompressedSize];
+			GCHandle obuf = GCHandle.Alloc(outBuffer, GCHandleType.Pinned);
+		
+			int res = Lzma_Uncompress(ptrBundle, inBuffer.Length-offset, uncompressedSize, obuf.AddrOfPinnedObject(), true);
+
+			cbuf.Free();
+			obuf.Free();
+
+			File.WriteAllBytes(outFile, outBuffer);
+
+			Array.Resize(ref outBuffer, 0);
+			Array.Resize(ref inBuffer, 0);
+
+			outBuffer = null;
+			inBuffer = null;
+
+			GC.Collect();
+
+			return res;	
+		} else {
+			return -1;
+		}	
+	}
+	*/
+
+
+    //This function decompresses an lzma compressed byte buffer.
+    //If the useHeader flag is false you have to provide the uncompressed size of the buffer via the customLength integer.
+    //if res==0 operation was successful
+    //The error codes
+    /*
+        OK 0
+		
+        ERROR_DATA 1
+        ERROR_MEM 2
+        ERROR_UNSUPPORTED 4
+        ERROR_PARAM 5
+        ERROR_INPUT_EOF 6
+        ERROR_OUTPUT_EOF 7
+        ERROR_FAIL 11
+        ERROR_THREAD 12
+        */
+    public static int decompressBuffer(byte[] inBuffer, ref byte[] outbuffer, bool useHeader = true, int customLength = 0)
+    {
+
+        GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+        int uncompressedSize = 0;
+
+        //if the lzma header will be used to extract the uncompressed size of the buffer. If the buffer does not have a header 
+        //provide the known uncompressed size through the customLength integer.
+        if (useHeader) uncompressedSize = (int)BitConverter.ToUInt64(inBuffer, 5); else uncompressedSize = customLength;
+
+        Array.Resize(ref outbuffer, uncompressedSize);
+
+        GCHandle obuf = GCHandle.Alloc(outbuffer, GCHandleType.Pinned);
+
+        int res = Lzma_Uncompress(cbuf.AddrOfPinnedObject(), inBuffer.Length, uncompressedSize, obuf.AddrOfPinnedObject(), useHeader);
+
+        cbuf.Free();
+        obuf.Free();
+
+        //if(res!=0){/*Debug.Log("ERROR: "+res.ToString());*/ return res; }
+
+        return res;
+    }
+
+    public static byte[] decompressBuffer(byte[] inBuffer, bool useHeader = true, int customLength = 0)
+    {
+
+        GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+        int uncompressedSize = 0;
+
+        //if the lzma header will be used to extract the uncompressed size of the buffer. If the buffer does not have a header 
+        //provide the known uncompressed size through the customLength integer.
+        if (useHeader) uncompressedSize = (int)BitConverter.ToUInt64(inBuffer, 5); else uncompressedSize = customLength;
+
+        byte[] outbuffer = new byte[uncompressedSize];
+
+        GCHandle obuf = GCHandle.Alloc(outbuffer, GCHandleType.Pinned);
+
+        int res = Lzma_Uncompress(cbuf.AddrOfPinnedObject(), inBuffer.Length, uncompressedSize, obuf.AddrOfPinnedObject(), useHeader);
+
+        cbuf.Free();
+        obuf.Free();
+
+        if (res != 0) {/*Debug.Log("ERROR: "+res.ToString());*/ return null; }
+
+        return outbuffer;
+    }
+
+
+    //same as above function. Only this one outputs to a buffer of fixed which size isn't resized to avoid memory allocations.
+    //The fixed buffer should have a size that will be able to hold the incoming decompressed data.
+    //returns the uncompressed size.
+    public static int decompressBufferFixed(byte[] inBuffer, ref byte[] outbuffer, bool safe = true, bool useHeader = true, int customLength = 0)
+    {
+
+        int uncompressedSize = 0;
+
+        //if the lzma header will be used to extract the uncompressed size of the buffer. If the buffer does not have a header 
+        //provide the known uncompressed size through the customLength integer.
+        if (useHeader) uncompressedSize = (int)BitConverter.ToUInt64(inBuffer, 5); else uncompressedSize = customLength;
+
+        //Check if the uncompressed size is bigger then the size of the fixed buffer. Then:
+        //1. write only the data that fit in it.
+        //2. or return a negative number. 
+        //It depends on if we set the safe flag to true or not.
+        if (uncompressedSize > outbuffer.Length)
+        {
+            if (safe) return -101; else uncompressedSize = outbuffer.Length;
+        }
+
+        GCHandle cbuf = GCHandle.Alloc(inBuffer, GCHandleType.Pinned);
+        GCHandle obuf = GCHandle.Alloc(outbuffer, GCHandleType.Pinned);
+
+        int res = Lzma_Uncompress(cbuf.AddrOfPinnedObject(), inBuffer.Length, uncompressedSize, obuf.AddrOfPinnedObject(), useHeader);
+
+        cbuf.Free();
+        obuf.Free();
+
+        if (res != 0) {/*Debug.Log("ERROR: "+res.ToString());*/ return -res; }
+
+        return uncompressedSize;
+    }
+
+}
+#endif
diff --git a/Main/Common/SevenZip/lzma.cs.meta b/Main/Common/SevenZip/lzma.cs.meta
new file mode 100644
index 0000000..f273e36
--- /dev/null
+++ b/Main/Common/SevenZip/lzma.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 13c1c59b80961f74e9c2c894f0961517
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
diff --git a/Main/Core/GameEngine/Launch.meta b/Main/Core/GameEngine/Launch.meta
new file mode 100644
index 0000000..f5da2b4
--- /dev/null
+++ b/Main/Core/GameEngine/Launch.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1a1192b48924f274e8e3ce3c265331a8
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/AssetCopyTask.cs b/Main/Core/GameEngine/Launch/AssetCopyTask.cs
new file mode 100644
index 0000000..61ba736
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/AssetCopyTask.cs
@@ -0,0 +1,266 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using UnityEngine;
+
+
+public class AssetCopyTask : LaunchTask
+{
+    int completedCount = 0;
+    int totalCount = -1;
+    List<FileInfo> copyTasks = new List<FileInfo>();
+
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("AssetCopyTask_ExpectTime", 70f); }
+        protected set { LocalSave.SetFloat("AssetCopyTask_ExpectTime", value); }
+    }
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.AssetCopy;
+        duration = Mathf.Max(0.5f, expectTime);
+        outTime = 50f;
+
+        if (Application.isEditor)
+        {
+            done = true;
+        }
+        else
+        {
+            switch (Application.platform)
+            {
+                case RuntimePlatform.Android:
+                    AndroidCopyAsset();
+                    break;
+                case RuntimePlatform.IPhonePlayer:
+                    IOSCopyAsset();
+                    break;
+                case RuntimePlatform.WindowsPlayer:
+                    StandaloneCopyAsset();
+                    break;
+            }
+        }
+    }
+
+    public override void End()
+    {
+        expectTime = timer;
+        Debug.LogFormat("{0}鎵ц鏃堕暱锛歿1}锛�", this.GetType().Name, timer);
+
+        if (!Application.isEditor)
+        {
+            switch (Application.platform)
+            {
+                case RuntimePlatform.Android:
+                    AndroidProcessCopyComplete();
+                    break;
+                case RuntimePlatform.IPhonePlayer:
+                    IOSProcessCopyComplete();
+                    break;
+            }
+        }
+
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        timer += Time.deltaTime;
+
+        if (!Application.isEditor)
+        {
+            switch (Application.platform)
+            {
+                case RuntimePlatform.Android:
+                    AndroidWaitCopyAssetComplete();
+                    break;
+                case RuntimePlatform.IPhonePlayer:
+                case RuntimePlatform.WindowsPlayer:
+                    IOSorStandaloneWaitCopyAssetComplete();
+                    break;
+            }
+        }
+
+        ExceptionReport();
+    }
+
+    private void AndroidCopyAsset()
+    {
+        switch (VersionConfig.Get().assetAccess)
+        {
+            case InstalledAsset.FullAsset:
+            case InstalledAsset.HalfAsset:
+            case InstalledAsset.IngoreDownLoad:
+                if (!SDKUtils.Instance.AssetCopyFinished)
+                {
+                    SDKUtils.Instance.CopyAsset();
+                    done = false;
+                    progress = 0f;
+                }
+                else
+                {
+                    done = true;
+                }
+                break;
+            case InstalledAsset.NullAsset:
+                done = true;
+                break;
+        }
+    }
+
+    private void IOSCopyAsset()
+    {
+        if (VersionUtility.Instance.versionInfo != null && VersionUtility.Instance.versionInfo.downAsset == 1)
+        {
+            switch (VersionConfig.Get().assetAccess)
+            {
+                case InstalledAsset.FullAsset:
+                case InstalledAsset.HalfAsset:
+                case InstalledAsset.IngoreDownLoad:
+                    if (!SDKUtils.Instance.AssetCopyFinished)
+                    {
+                        copyTasks = new List<FileInfo>();
+                        FileExtersion.GetAllDirectoryFileInfos(ResourcesPath.Instance.StreamingAssetPath, copyTasks);
+
+                        for (var i = copyTasks.Count - 1; i >= 0; i--)
+                        {
+                            var fileInfo = copyTasks[i];
+                            var destPath = fileInfo.FullName.Replace(ResourcesPath.Instance.StreamingAssetPath, ResourcesPath.Instance.ExternalStorePath);
+                            if (File.Exists(destPath))
+                            {
+                                copyTasks.RemoveAt(i);
+                            }
+                        }
+
+                        completedCount = 0;
+                        totalCount = copyTasks.Count;
+                    }
+
+                    if (totalCount > 0)
+                    {
+                        done = false;
+                        progress = 0f;
+                    }
+                    else
+                    {
+                        done = true;
+                    }
+                    break;
+                case InstalledAsset.NullAsset:
+                    done = true;
+                    break;
+            }
+        }
+        else
+        {
+            done = true;
+        }
+    }
+
+    private void StandaloneCopyAsset()
+    {
+        if (VersionUtility.Instance.versionInfo != null && VersionUtility.Instance.versionInfo.downAsset == 1)
+        {
+            switch (VersionConfig.Get().assetAccess)
+            {
+                case InstalledAsset.FullAsset:
+                case InstalledAsset.HalfAsset:
+                case InstalledAsset.IngoreDownLoad:
+                    copyTasks = new List<FileInfo>();
+                    FileExtersion.GetAllDirectoryFileInfos(ResourcesPath.Instance.StreamingAssetPath, copyTasks);
+
+                    for (var i = copyTasks.Count - 1; i >= 0; i--)
+                    {
+                        var fileInfo = copyTasks[i];
+                        var destPath = fileInfo.FullName.Replace(ResourcesPath.Instance.StreamingAssetPath, ResourcesPath.Instance.ExternalStorePath);
+                        if (File.Exists(destPath))
+                        {
+                            copyTasks.RemoveAt(i);
+                        }
+                    }
+
+                    completedCount = 0;
+                    totalCount = copyTasks.Count;
+
+                    if (totalCount > 0)
+                    {
+                        done = false;
+                        progress = 0f;
+                    }
+                    else
+                    {
+                        done = true;
+                    }
+                    break;
+                case InstalledAsset.NullAsset:
+                    done = true;
+                    break;
+            }
+        }
+        else
+        {
+            done = true;
+        }
+    }
+
+    private void AndroidWaitCopyAssetComplete()
+    {
+        if (!SDKUtils.Instance.AssetCopyFinished)
+        {
+            done = false;
+            progress = timer / duration;
+        }
+        else
+        {
+            done = true;
+        }
+    }
+
+    private void IOSorStandaloneWaitCopyAssetComplete()
+    {
+        if (totalCount > 0)
+        {
+            if (completedCount < totalCount)
+            {
+                var fileInfo = copyTasks[0];
+                var destPath = fileInfo.FullName.Replace(ResourcesPath.Instance.StreamingAssetPath, ResourcesPath.Instance.ExternalStorePath);
+                var destDirectoryName = Path.GetDirectoryName(destPath);
+                if (!Directory.Exists(destDirectoryName))
+                {
+                    Directory.CreateDirectory(destDirectoryName);
+                }
+
+                Debug.LogFormat("鎷疯礉鏂囦欢锛歿0}", fileInfo.Name);
+                File.Copy(fileInfo.FullName, destPath, true);
+                copyTasks.RemoveAt(0);
+                completedCount++;
+
+                done = false;
+                progress = (float)completedCount / totalCount;
+            }
+            else
+            {
+                done = true;
+            }
+        }
+        else
+        {
+            done = true;
+        }
+    }
+
+    private void AndroidProcessCopyComplete()
+    {
+    }
+
+    private void IOSProcessCopyComplete()
+    {
+        LocalSave.SetString("AssetCopyCompleted_IOSorStandalone", VersionConfig.Get().version);
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/AssetCopyTask.cs.meta b/Main/Core/GameEngine/Launch/AssetCopyTask.cs.meta
new file mode 100644
index 0000000..20dc543
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/AssetCopyTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 64943b900511811419130066733f1396
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/AssetDeCompressTask.cs b/Main/Core/GameEngine/Launch/AssetDeCompressTask.cs
new file mode 100644
index 0000000..6e1b378
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/AssetDeCompressTask.cs
@@ -0,0 +1,204 @@
+锘縰sing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.IO;
+using System.Threading;
+
+public class AssetDeCompressTask
+{
+
+
+    public static string assetDeCompressVersion
+    {
+        get
+        {
+            return LocalSave.GetString("AssetDeCompressVersion");
+        }
+        set
+        {
+            LocalSave.SetString("AssetDeCompressVersion", value);
+        }
+    }
+
+    public static bool assetDeCompressCompleted
+    {
+        get
+        {
+            if (string.IsNullOrEmpty(assetDeCompressVersion))
+            {
+                return false;
+            }
+            else
+            {
+                return assetDeCompressVersion == VersionConfig.Get().version;
+            }
+        }
+    }
+
+    public static void Decompress(string path)
+    {
+        var files = new List<FileInfo>();
+        FileExtersion.GetAllDirectoryFileInfos(path, files);
+        foreach (var item in files)
+        {
+            var fullName = item.FullName;
+            if (fullName.EndsWith(".7z"))
+            {
+                SevenZipUtility.DeCompress(fullName, Path.GetDirectoryName(fullName));
+            }
+        }
+    }
+
+    public static DecompressProgress DecompressAync(string path)
+    {
+        var progress = new DecompressProgress();
+        var files = new List<FileInfo>();
+        FileExtersion.GetAllDirectoryFileInfos(path, files);
+
+        for (var i = files.Count - 1; i >= 0; i--)
+        {
+            var fullName = files[i].FullName;
+            if (!fullName.EndsWith(".7z"))
+            {
+                files.RemoveAt(i);
+            }
+        }
+
+        var total = files.Count;
+        if (total == 0)
+        {
+            progress.progress = 1f;
+            progress.done = true;
+            return progress;
+        }
+
+        ThreadPool.QueueUserWorkItem((object a) =>
+        {
+            var index = 0;
+            foreach (var item in files)
+            {
+                var fullName = item.FullName;
+                if (fullName.EndsWith(".7z"))
+                {
+                    SevenZipUtility.DeCompress(fullName, Path.GetDirectoryName(fullName));
+                    index++;
+                    progress.progress = index / (float)total;
+                }
+            }
+
+            progress.done = true;
+        });
+
+        return progress;
+    }
+
+    public static void Delete7zFiles(string path)
+    {
+        var files = new List<FileInfo>();
+        FileExtersion.GetAllDirectoryFileInfos(path, files);
+
+        for (var i = files.Count - 1; i >= 0; i--)
+        {
+            var fullName = files[i].FullName;
+            if (fullName.EndsWith(".7z"))
+            {
+                files[i].Delete();
+            }
+        }
+    }
+
+    public class DecompressProgress
+    {
+        object progressLock = new object();
+        float m_Progress = 0f;
+        public float progress
+        {
+            get
+            {
+                return m_Progress;
+            }
+            set
+            {
+                lock (progressLock)
+                {
+                    m_Progress = value;
+                }
+            }
+        }
+
+        object doneLock = new object();
+        bool m_Done = false;
+        public bool done
+        {
+            get
+            {
+                return m_Done;
+            }
+            set
+            {
+                lock (doneLock)
+                {
+                    m_Done = value;
+                }
+            }
+        }
+
+    }
+
+}
+
+
+
+public class AssetDecompressTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("AssetDecompressTask_ExpectTime", 5f); }
+        protected set { LocalSave.SetFloat("AssetDecompressTask_ExpectTime", value); }
+    }
+
+    AssetDeCompressTask.DecompressProgress deCompressProgress = null;
+    float waitTimer = 0f;
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.AssetDecompress;
+        duration = Mathf.Max(0.5f, expectTime);
+
+        if (!AssetDeCompressTask.assetDeCompressCompleted)
+        {
+            deCompressProgress = AssetDeCompressTask.DecompressAync(ResourcesPath.Instance.ExternalStorePath);
+            done = false;
+        }
+        else
+        {
+            done = true;
+        }
+    }
+
+    public override void End()
+    {
+        AssetDeCompressTask.assetDeCompressVersion = VersionConfig.Get().version;
+        AssetDeCompressTask.Delete7zFiles(ResourcesPath.Instance.ExternalStorePath);
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        timer += Time.deltaTime;
+        progress = timer / duration;
+        if (deCompressProgress == null || deCompressProgress.done)
+        {
+            waitTimer += Time.deltaTime;
+            if (waitTimer > 2f)
+            {
+                done = true;
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/AssetDeCompressTask.cs.meta b/Main/Core/GameEngine/Launch/AssetDeCompressTask.cs.meta
new file mode 100644
index 0000000..93dca33
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/AssetDeCompressTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7ff0a94221f3cda4689ea3b7882f2562
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/BuiltInAssetCopyTask.cs b/Main/Core/GameEngine/Launch/BuiltInAssetCopyTask.cs
new file mode 100644
index 0000000..8a8468b
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/BuiltInAssetCopyTask.cs
@@ -0,0 +1,249 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.IO;
+using System;
+
+
+public class BuiltInAssetCopyTask : LaunchTask
+{
+    bool firstLaunch = false;
+
+    public override void Begin()
+    {
+        duration = Mathf.Max(0.2f, expectTime);  //闈炲畨鍗撳钩鍙扮殑鏃堕棿锛屽畨鍗撶敱sdk鎷疯礉瀹屾垚鍥炶皟
+
+        if (Application.isEditor)
+        {
+            EditorCopyAsset();
+        }
+        else
+        {
+            //瀹夊崜姣忔鐢眘dk鍥炶皟鎷疯礉鎴愬姛锛屽叾浠栧钩鍙扮敱unity鑷繁瀛樺偍鏍囪
+            switch (Application.platform)
+            {
+                case RuntimePlatform.Android:
+                    AndroidCopyAsset();
+                    break;
+                case RuntimePlatform.IPhonePlayer:
+                    IosCopyAsset();
+                    break;
+                case RuntimePlatform.WindowsPlayer:
+                    StandaloneCopyAsset();
+                    break;
+            }
+        }
+
+        if (!firstLaunch)
+        {
+            done = true;
+        }
+    }
+
+    public override void End()
+    {
+        if (!AssetSource.builtInFromEditor)
+        {
+            AssetBundleUtility.Instance.InitBuiltInAsset();
+        }
+        // TODO YYL
+        // ConfigInitiator.SyncInit();
+        // WindowCenter.Instance.DestoryWinsByStage(WindowCenter.WindowStage.Launch);
+        // WindowCenter.Instance.OpenFromLocal<LaunchWin>();
+        Language.InitDefaultLanguage();
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+        if (!Application.isEditor)
+        {
+            //瀹夊崜姣忔鐢眘dk鍥炶皟鎷疯礉鎴愬姛锛屽叾浠栧钩鍙扮敱unity鑷繁瀛樺偍鏍囪
+            if (Application.platform == RuntimePlatform.Android)
+            {
+                AndroidWaitCopyAssetComplete();
+            }
+            else
+            {
+                if (timer > duration)
+                {
+                    done = true;
+                }
+                else
+                {
+                    done = false;
+                    progress = timer / duration;
+                }
+            }
+        }
+
+
+        timer += Time.deltaTime;
+    }
+
+
+    private void AndroidWaitCopyAssetComplete()
+    {
+        if (!SDKUtils.Instance.AssetCopyFinished)
+        {
+            done = false;
+            progress = timer / duration;
+        }
+        else
+        {
+            done = true;
+        }
+    }
+
+
+    private void AndroidCopyAsset()
+    {
+        if (!SDKUtils.Instance.AssetCopyFinished)
+        {
+            //姣忔鐢眘dk鍥炶皟鎷疯礉鎴愬姛
+            firstLaunch = true;
+            UnityEngine.Debug.Log("寮�濮嬫嫹璐漛uiltin璧勬簮");
+            SDKUtils.Instance.CopyAsset(1);
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin_assetbundle");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin_assetbundle.manifest");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/musics");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/musics.manifest");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/prefabs");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/prefabs.manifest");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/sprites");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/sprites.manifest");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/animationclips");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/animationclips.manifest");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/materials");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/materials.manifest");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/scriptableobjects");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/scriptableobjects.manifest");
+
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/font");
+            //ynmbxxjUtil.Instance.CopyOneAsset("builtin/font.manifest");
+
+            //foreach (var config in ConfigInitiator.builtinConfig)
+            //{
+            //    ynmbxxjUtil.Instance.CopyOneAsset("config/" + config);
+            //}
+
+            //AssetDeCompressTask.Decompress(ResourcesPath.Instance.ExternalStorePath);
+            //LocalSave.SetString("BuiltInAssetCopyCompleted_Android", VersionConfig.Get().version);
+        }
+        else
+            UnityEngine.Debug.Log("builtin璧勬簮宸茬粡鎷疯礉杩囦簡");
+    }
+
+    private void IosCopyAsset()
+    {
+        if (!VersionUtility.Instance.InIosAuditTime())
+        {
+            if (!SDKUtils.builtinAssetCopyFinished)
+            {
+                firstLaunch = true;
+                var targetDirectory = ResourcesPath.Instance.ExternalStorePath;
+                if (!Directory.Exists(targetDirectory))
+                {
+                    Directory.CreateDirectory(targetDirectory);
+                }
+
+                var fileNames = new List<string>();
+                //var files = new List<FileInfo>();
+                //FileExtersion.GetAllDirectoryFileInfos(StringUtility.Contact(ResourcesPath.Instance.StreamingAssetPath, "builtin"), files);
+                //foreach (var file in files)
+                //{
+                //    var name = Path.GetFileName(file.FullName);
+                //    fileNames.Add(StringUtility.Contact("builtin", Path.DirectorySeparatorChar, name));
+                //}
+
+                //fileNames.Add("builtin_assetbundle");
+                //fileNames.Add("builtin_assetbundle.manifest");
+
+                var configFiles = new List<FileInfo>();
+                FileExtersion.GetAllDirectoryFileInfos(StringUtility.Contact(ResourcesPath.Instance.StreamingAssetPath, "config"), configFiles);
+                foreach (var file in configFiles)
+                {
+                    var name = Path.GetFileName(file.FullName);
+                    fileNames.Add(StringUtility.Contact("config", Path.DirectorySeparatorChar, name));
+                }
+
+                foreach (var item in fileNames)
+                {
+                    var fromPath = StringUtility.Contact(ResourcesPath.Instance.StreamingAssetPath, item);
+                    var toPath = StringUtility.Contact(targetDirectory, item);
+
+                    var destDirectoryName = Path.GetDirectoryName(toPath);
+                    if (!Directory.Exists(destDirectoryName))
+                    {
+                        Directory.CreateDirectory(destDirectoryName);
+                    }
+
+                    File.Copy(fromPath, toPath, true);
+                }
+
+                LocalSave.SetString("BuiltInAssetCopyCompleted_IOSorStandalone", VersionConfig.Get().version);
+            }
+        }
+    }
+
+    private void StandaloneCopyAsset()
+    {
+        var targetDirectory = ResourcesPath.Instance.ExternalStorePath;
+        if (!Directory.Exists(targetDirectory))
+        {
+            Directory.CreateDirectory(targetDirectory);
+        }
+
+        var fileNames = new List<string>();
+        //var files = new List<FileInfo>();
+        //FileExtersion.GetAllDirectoryFileInfos(StringUtility.Contact(ResourcesPath.Instance.StreamingAssetPath, "builtin"), files);
+        //foreach (var file in files)
+        //{
+        //    var name = Path.GetFileName(file.FullName);
+        //    fileNames.Add(StringUtility.Contact("builtin", Path.DirectorySeparatorChar, name));
+        //}
+
+        //fileNames.Add("builtin_assetbundle");
+        //fileNames.Add("builtin_assetbundle.manifest");
+
+        var configFiles = new List<FileInfo>();
+        FileExtersion.GetAllDirectoryFileInfos(StringUtility.Contact(ResourcesPath.Instance.StreamingAssetPath, "config"), configFiles);
+        foreach (var file in configFiles)
+        {
+            var name = Path.GetFileName(file.FullName);
+            fileNames.Add(StringUtility.Contact("config", Path.DirectorySeparatorChar, name));
+        }
+
+        foreach (var item in fileNames)
+        {
+            var fromPath = StringUtility.Contact(ResourcesPath.Instance.StreamingAssetPath, item);
+            var toPath = StringUtility.Contact(targetDirectory, item);
+
+            if (File.Exists(toPath))
+            {
+                continue;
+            }
+
+            var destDirectoryName = Path.GetDirectoryName(toPath);
+            if (!Directory.Exists(destDirectoryName))
+            {
+                Directory.CreateDirectory(destDirectoryName);
+            }
+
+            File.Copy(fromPath, toPath, true);
+        }
+    }
+
+    private void EditorCopyAsset()
+    {
+        if (!AssetSource.allFromEditor)
+        {
+            // FileExtersion.DirectoryCopy(ResourcesPath.CONFIG_FODLER, ResourcesPath.Instance.StreamingAssetPath + "config");
+            // FileExtersion.DirectoryCopy(ResourcesPath.ResourcesOutPath + "BuiltIn", ResourcesPath.Instance.StreamingAssetPath + "builtin");
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/BuiltInAssetCopyTask.cs.meta b/Main/Core/GameEngine/Launch/BuiltInAssetCopyTask.cs.meta
new file mode 100644
index 0000000..fa7b3d6
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/BuiltInAssetCopyTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1761a3254ef37ba4fbd60b602c1c786d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/CheckAssetValidTask.cs b/Main/Core/GameEngine/Launch/CheckAssetValidTask.cs
new file mode 100644
index 0000000..fc9de6f
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/CheckAssetValidTask.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using UnityEngine;
+
+public class CheckAssetValidTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("CheckAssetValidTask_ExpectTime", 3f); }
+        protected set { LocalSave.SetFloat("CheckAssetValidTask_ExpectTime", value); }
+    }
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.CheckAsset;
+        duration = Mathf.Max(0.5f, expectTime);
+
+        ServerListCenter.Instance.RequestJumpUrl();
+
+        // TODO YYL
+        // OperationLogCollect.Instance.RecordLauchEvent(2);
+        // OperationLogCollect.Instance.RecordEvent(2);
+
+        if (VersionUtility.Instance.NeedDownAsset())
+        {
+            var remoteURL = StringUtility.Contact(VersionUtility.Instance.versionInfo.GetResourcesURL(VersionConfig.Get().branch), Language.fixPath, "/config/PriorBundle.txt");
+            var localURL = StringUtility.Contact(ResourcesPath.Instance.ExternalStorePath, "config/PriorBundle.txt");
+            var downloadTask = new DownloadTask(remoteURL, localURL);
+            downloadTask.BeginDownload(AssetVersionUtility.OnDownLoadPriorBundle);
+
+            //AssetVersionUtility.GetAssetVersionFile();
+            done = false;
+            progress = 0f;
+        }
+        else
+        {
+            //if (Application.isEditor)
+            //    PatchLoader.InitLocalPatchAsset();
+            done = true;
+        }
+    }
+
+    public override void End()
+    {
+        expectTime = timer;
+        Debug.LogFormat("{0}鎵ц鏃堕暱锛歿1}锛�", this.GetType().Name, timer);
+
+        //  TODO YYL
+        // GameNotice.OpenGameNotice();
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        timer += Time.deltaTime;
+        if (!AssetVersionUtility.checkAssetCompleted)
+        {
+            done = false;
+            progress = timer / expectTime;
+        }
+        else
+        {
+            done = true;
+        }
+
+        ExceptionReport();
+    }
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/CheckAssetValidTask.cs.meta b/Main/Core/GameEngine/Launch/CheckAssetValidTask.cs.meta
new file mode 100644
index 0000000..5b78e11
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/CheckAssetValidTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8a5baa7ec7f114141b60eae7f1ed95b6
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/DownLoadAssetTask.cs b/Main/Core/GameEngine/Launch/DownLoadAssetTask.cs
new file mode 100644
index 0000000..569ff1a
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/DownLoadAssetTask.cs
@@ -0,0 +1,277 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using UnityEngine;
+
+
+public class DownLoadAssetTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("DownLoadAssetTask_ExpectTime", 3f); }
+        protected set { LocalSave.SetFloat("DownLoadAssetTask_ExpectTime", value); }
+    }
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.DownLoad;
+        outTime = 9999f;
+        duration = Mathf.Max(0.5f, expectTime);
+        if (VersionUtility.Instance.NeedDownAsset())
+        {
+            if (!AssetVersionUtility.priorAssetDownLoadDone)
+            {
+                AssetVersionUtility.BeginDownLoadTask(true);
+                done = false;
+                progress = 0f;
+            }
+            else
+            {
+                done = true;
+            }
+
+        }
+        else
+        {
+            done = true;
+        }
+    }
+
+    public override void End()
+    {
+        expectTime = timer;
+        Debug.LogFormat("{0}鎵ц鏃堕暱锛歿1}锛�", this.GetType().Name, timer);
+        if (!AssetVersionUtility.unPriorAssetDownLoadDone)
+        {
+            AssetVersionUtility.BeginDownLoadTask(false);
+        }
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        timer += Time.deltaTime;
+        if (!AssetVersionUtility.priorAssetDownLoadDone)
+        {
+            done = false;
+            progress = 0f;
+        }
+        else
+        {
+            done = true;
+        }
+
+        ExceptionReport();
+    }
+
+}
+
+public class AssetBundleInitTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("AssetBundleInitTask_ExpectTime", 1f); }
+        protected set { LocalSave.SetFloat("AssetBundleInitTask_ExpectTime", value); }
+    }
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.AssetBundleInit;
+
+        duration = Mathf.Max(0.5f, expectTime);
+        if (!AssetSource.allFromEditor)
+        {
+            AssetBundleUtility.Instance.Initialize();
+            done = false;
+            progress = 0f;
+        }
+        else
+        {
+            done = true;
+        }
+    }
+
+    public override void End()
+    {
+        expectTime = timer; 
+        //  TODO YYL
+        // UILoader.LoadWindowAsync("LaunchBackGroundWin", null);
+        Debug.LogFormat("{0}鎵ц鏃堕暱锛歿1}锛�", this.GetType().Name, timer);
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        if (AssetBundleUtility.Instance.initialized && AssetBundleUtility.Instance.initializedUIAssetBundle)
+        {
+            done = true;
+        }
+        else
+        {
+            done = false;
+            progress = timer / duration;
+        }
+
+        ExceptionReport();
+    }
+}
+
+public class ConfigInitTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("ConfigInitTask_ExpectTime", 10f); }
+        protected set { LocalSave.SetFloat("ConfigInitTask_ExpectTime", value); }
+    }
+
+    float threshold = 1f;
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.ConfigInit;
+        duration = Mathf.Max(0.5f, expectTime);
+        threshold = Application.platform == RuntimePlatform.WindowsEditor ? 1f : 0.9f;
+
+        // LaunchPostProcess.Instance.Begin();
+        // InitialFunctionConfig.Init(true);   //鏈夋洿鏂板啀鍒濆鍖栦竴娆�
+    }
+
+    public override void End()
+    {
+        expectTime = timer;
+        Debug.LogFormat("{0}鎵ц鏃堕暱锛歿1}锛�", this.GetType().Name, timer);
+        
+        // TODO YYL
+        // OperationLogCollect.Instance.RecordLauchEvent(3);
+        // OperationLogCollect.Instance.RecordEvent(3);
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        timer += Time.deltaTime;
+        // if (!ConfigInitiator.IsLoginConfigInited)\
+        // TODO YYL
+        // if (!ConfigInitiator.done)
+        // {
+        //     done = false;
+        //     progress = timer / duration;
+        // }
+        // else
+        {
+            done = true;
+        }
+
+        ExceptionReport();
+    }
+
+}
+
+public class LaunchFadeOutTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("LaunchFadeOutTask_ExpectTime", 1f); }
+        protected set { LocalSave.SetFloat("LaunchFadeOutTask_ExpectTime", value); }
+    }
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.Complete;
+        duration = 0.5f;
+
+        ShaderUtility.WarmUpAll();
+        //SpeechTranslate.Instance.RequestGetToken();
+        //  TODO CYL
+        // WindowCenter.Instance.Open<LaunchBackGroundWin>(true);
+
+        // var launchWin = WindowCenter.Instance.Get<LaunchWin>();
+        // if (launchWin != null)
+        // {
+        //     launchWin.FadeOut();
+        // }
+
+        // try
+        // {
+        //     LogicLauncher.LaunchStart();
+        // }
+        // catch (Exception e)
+        // {
+        //     UnityEngine.Debug.LogError(e);
+        // }
+    }
+
+    public override void End()
+    {
+        expectTime = timer;
+        Debug.LogFormat("{0}鎵ц鏃堕暱锛歿1}锛�", this.GetType().Name, timer);
+
+
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+        timer += Time.deltaTime;
+
+        if (timer >= 0.5f)//&& ILLauncherProxy.Instance.started)
+        {
+            done = true;
+        }
+        else
+        {
+            done = false;
+            progress = Mathf.Clamp01(timer / expectTime);
+        }
+
+        ExceptionReport();
+    }
+
+}
+
+public class WaitTask : LaunchTask
+{
+    public WaitTask(float seconds)
+    {
+        expectTime = Mathf.Max(0.1f, seconds);
+    }
+
+    public override void Begin()
+    {
+    }
+
+    public override void End()
+    {
+    }
+
+    public override void Update()
+    {
+        timer += Time.deltaTime;
+
+        if (timer >= expectTime)
+        {
+            done = true;
+        }
+        else
+        {
+            done = false;
+            progress = Mathf.Clamp01(timer / expectTime);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/DownLoadAssetTask.cs.meta b/Main/Core/GameEngine/Launch/DownLoadAssetTask.cs.meta
new file mode 100644
index 0000000..5718158
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/DownLoadAssetTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 16185d13cc99c3443bb2e65696e1f1ce
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/GetVersionInfoTask.cs b/Main/Core/GameEngine/Launch/GetVersionInfoTask.cs
new file mode 100644
index 0000000..0a60fb8
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/GetVersionInfoTask.cs
@@ -0,0 +1,78 @@
+
+
+using UnityEngine;
+using System.Collections;
+using vnxbqy.UI;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+public class GetVersionInfoTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("GetVersionInfoTask_ExpectTime", 1f); }
+        protected set { LocalSave.SetFloat("GetVersionInfoTask_ExpectTime", value); }
+    }
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.ClientVersion;
+        duration = Mathf.Max(0.5f, expectTime);
+
+        if (Application.isEditor)
+        {
+            if (InGameDownTestUtility.enable)
+            {
+                VersionUtility.Instance.RequestVersionCheck();
+                done = false;
+                progress = 0f;
+            }
+            else
+            {
+                done = true;
+            }
+        }
+        else
+        {
+            if (!VersionUtility.Instance.InIosAuditTime())
+            {
+                VersionUtility.Instance.RequestVersionCheck();
+                done = false;
+                progress = 0f;
+            }
+            else
+            {
+                done = true;
+            }
+        }
+
+    }
+
+    public override void End()
+    {
+        expectTime = timer;
+        Debug.LogFormat("{0}鎵ц鏃堕暱锛歿1}锛�", this.GetType().Name, timer);
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        timer += Time.deltaTime;
+        if (!VersionUtility.Instance.completed)
+        {
+            done = false;
+            progress = timer / expectTime;
+        }
+        else
+        {
+            done = true;
+        }
+
+        ExceptionReport();
+    }
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/GetVersionInfoTask.cs.meta b/Main/Core/GameEngine/Launch/GetVersionInfoTask.cs.meta
new file mode 100644
index 0000000..dabb747
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/GetVersionInfoTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e97b6f5762db50844882605678e5798d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/InitSettingTask.cs b/Main/Core/GameEngine/Launch/InitSettingTask.cs
new file mode 100644
index 0000000..c784eaf
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/InitSettingTask.cs
@@ -0,0 +1,54 @@
+
+
+using UnityEngine;
+
+public class InitSettingTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("InitSettingTask_ExpectTime", 1f); }
+        protected set { LocalSave.SetFloat("InitSettingTask_ExpectTime", value); }
+    }
+
+    public override void Begin()
+    {
+        ShaderUtility.InitGlobalParams();
+        SoundPlayer.CreateSoundPlayer();
+        SoundPlayer.Instance.PlayLoginMusic();
+
+        SystemSetting.Instance.SetSoundVolume(SystemSetting.Instance.GetSoundVolume());
+        SystemSetting.Instance.SetSoundEffect(SystemSetting.Instance.GetSoundEffect());
+        SystemSetting.Instance.SetGameFps(SystemSetting.Instance.GetGameFps());
+        SystemSetting.Instance.LetFPSUnLimit();
+
+        DebugUtility.Instance.Init();
+        DebugUtility.Instance.CreateDebugRoot();
+
+        GameObjectPoolManager.Instance.gameObject.name = "GameObjectPool";
+        GameObjectPoolManager.Instance.Initialize();
+
+        //ExceptionCatcher.Init();
+        //ExceptionCatcher.Catch();
+
+        GlobalTimeEvent.Instance.Begin();
+        PackageRegedit.Init();
+        Clock.Init();
+
+        // TODO YYL
+        // if (VersionConfig.Get().appId.Equals("test"))
+        // {
+        //     SnxxzGame.Instance.gameObject.AddComponent<PocoManager>();
+        // }
+        done = true;
+    }
+
+    public override void End()
+    {
+        expectTime = timer;
+    }
+
+    public override void Update()
+    {
+        timer += Time.deltaTime;
+    }
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/InitSettingTask.cs.meta b/Main/Core/GameEngine/Launch/InitSettingTask.cs.meta
new file mode 100644
index 0000000..c329071
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/InitSettingTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ff71585fde92d814d97586fe3c01aa6d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/LaunchInHot.cs b/Main/Core/GameEngine/Launch/LaunchInHot.cs
new file mode 100644
index 0000000..0ccf886
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/LaunchInHot.cs
@@ -0,0 +1,180 @@
+using UnityEngine;
+using System.Collections;
+using vnxbqy.UI;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+public class LaunchInHot : MonoBehaviour
+{
+    static int step = 0;
+    public static LaunchStage m_CurrentStage = LaunchStage.None;
+    public static LaunchProgressInfo progressInfo { get; private set; }
+
+    float timer = 0f;
+    Queue<LaunchTask> tasks = new Queue<LaunchTask>();
+    LaunchTask currentTask = null;
+    bool launchComplete = false;
+    float surplusProgress = 0f;
+    float surplusTime = 0f;
+
+    void Start()
+    {
+        System.Net.ServicePointManager.DefaultConnectionLimit = 100;//璁剧疆http鏈�澶ц繛鎺ユ暟
+        Application.backgroundLoadingPriority = ThreadPriority.High;
+        Screen.sleepTimeout = SleepTimeout.NeverSleep;
+        SDKUtils.Instance.Init();  //鍘焥dk鎺ュ彛
+
+        var builtInAssetCopyTask = new BuiltInAssetCopyTask();
+        var requestPermissionStart = new RequestPermissionStart();
+        var initSettingTask = new InitSettingTask();
+        var sdkInitedTask = new SDKInitedTask();
+        //var assetCopyTask = new AssetCopyTask();
+        //var assetDecompressTask = new AssetDecompressTask();
+        var getVersionInfoTask = new GetVersionInfoTask();
+        var checkAssetValidTask = new CheckAssetValidTask();
+        var downLoadAssetTask = new DownLoadAssetTask();
+        var assetBundleInitTask = new AssetBundleInitTask();
+        var configInitTask = new ConfigInitTask();
+        var launchFadeOutTask = new LaunchFadeOutTask();
+
+        tasks.Enqueue(builtInAssetCopyTask);
+        tasks.Enqueue(requestPermissionStart);
+        tasks.Enqueue(initSettingTask);
+
+
+        if (!Application.isEditor)
+        {
+            tasks.Enqueue(sdkInitedTask);
+        }
+
+        switch (Application.platform)
+        {
+            case RuntimePlatform.OSXEditor:
+            case RuntimePlatform.WindowsEditor:
+                tasks.Enqueue(getVersionInfoTask);
+                break;
+            case RuntimePlatform.Android:
+                tasks.Enqueue(getVersionInfoTask);
+                //tasks.Enqueue(assetCopyTask);
+                //tasks.Enqueue(assetDecompressTask);
+                break;
+            case RuntimePlatform.IPhonePlayer:
+                tasks.Enqueue(getVersionInfoTask);
+                //tasks.Enqueue(assetCopyTask);
+                break;
+            case RuntimePlatform.WindowsPlayer:
+                //tasks.Enqueue(assetCopyTask);
+                tasks.Enqueue(getVersionInfoTask);
+                break;
+        }
+
+        tasks.Enqueue(checkAssetValidTask);
+        tasks.Enqueue(downLoadAssetTask);
+        tasks.Enqueue(assetBundleInitTask);
+        tasks.Enqueue(configInitTask);
+        tasks.Enqueue(launchFadeOutTask);
+
+        CalculateExpectTotalTime();
+
+    }
+
+    void Update()
+    {
+        if (!launchComplete)
+        {
+            if (currentTask == null)
+            {
+                if (tasks.Count > 0)
+                {
+                    currentTask = tasks.Dequeue();
+                    currentTask.Begin();
+                }
+                else
+                {
+                    launchComplete = true;
+                }
+            }
+
+            if (currentTask != null)
+            {
+                currentTask.Update();
+            }
+
+            if (currentTask != null && currentTask.done)
+            {
+                currentTask.End();
+                CalculateExpectTotalTime();
+                currentTask = null;
+            }
+
+            if (m_CurrentStage == LaunchStage.DownLoad)
+            {
+                progressInfo = new LaunchProgressInfo(m_CurrentStage, 1, progressInfo.totalProgress, 0f);
+            }
+            else
+            {
+                timer += Time.deltaTime;
+                var progress = progressInfo.totalProgress + surplusProgress * (Time.deltaTime / surplusTime);
+                progress = Mathf.Clamp(progress, 0, 0.98f);
+
+                var partProgress = 0f;
+                if (currentTask == null)
+                {
+                    partProgress = 0f;
+                }
+                else
+                {
+                    var temp = currentTask.timer / Mathf.Min(2f, currentTask.duration);
+                    step = (int)temp + 1;
+                    partProgress = temp - (int)temp;
+                }
+
+                progressInfo = new LaunchProgressInfo(m_CurrentStage, step, Mathf.Clamp01(progress), partProgress);
+            }
+        }
+
+        if (launchComplete)
+        {
+            UnityEngine.Debug.LogFormat("鍚姩鑰楁椂锛歿0}", timer);
+            progressInfo = new LaunchProgressInfo(m_CurrentStage, 1, 1f, 1f);
+            this.enabled = false;
+
+            // 鍚姩娴佺▼缁撴潫 瑕佸幓鍝噷 TODO YYL
+
+            // StageLoad.Instance.PushSceneLoadCommand(new StageLoad.StageLoadCommand()
+            // {
+            //     toMapId = 1,
+            //     toLineId = 0,
+            //     needEmpty = false,
+            //     needLoadResource = true,
+            //     serverType = ServerType.Main,
+            //     isClientLoadMap = true
+            // });
+        }
+    }
+
+    public static int GetLaunchStage()
+    {
+        return (int)m_CurrentStage;
+    }
+
+    /// <summary>
+    /// 璁$畻鎬荤殑棰勬湡鏃堕棿
+    /// </summary>
+    void CalculateExpectTotalTime()
+    {
+        surplusTime = 0f;
+        foreach (var item in tasks)
+        {
+            surplusTime += item.expectTime;
+        }
+
+        surplusProgress = 1 - progressInfo.totalProgress;
+    }
+
+
+
+
+}
+
diff --git a/Main/Core/GameEngine/Launch/LaunchInHot.cs.meta b/Main/Core/GameEngine/Launch/LaunchInHot.cs.meta
new file mode 100644
index 0000000..cd61ebf
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/LaunchInHot.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 906ac694e0545124cbf74afe1c69b703
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/LaunchProgressInfo.cs b/Main/Core/GameEngine/Launch/LaunchProgressInfo.cs
new file mode 100644
index 0000000..78a50d4
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/LaunchProgressInfo.cs
@@ -0,0 +1,17 @@
+
+public struct LaunchProgressInfo
+{
+    public LaunchStage stage;
+    public int step;
+    public float totalProgress;
+    public float partProgress;
+
+    public LaunchProgressInfo(LaunchStage stage, int step, float totalProgress, float partProgress)
+    {
+        this.stage = stage;
+        this.step = step;
+        this.totalProgress = totalProgress;
+        this.partProgress = partProgress;
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/LaunchProgressInfo.cs.meta b/Main/Core/GameEngine/Launch/LaunchProgressInfo.cs.meta
new file mode 100644
index 0000000..e51abcb
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/LaunchProgressInfo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4ab1175bb98c09842bf2bb1026a8d7cb
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/LaunchStage.cs b/Main/Core/GameEngine/Launch/LaunchStage.cs
new file mode 100644
index 0000000..052a260
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/LaunchStage.cs
@@ -0,0 +1,14 @@
+
+public enum LaunchStage
+{
+    None = 0,
+    SDKInit = 1,
+    AssetCopy = 2,
+    AssetDecompress = 3,
+    ClientVersion = 4,
+    CheckAsset = 5,
+    DownLoad = 6,
+    AssetBundleInit = 7,
+    ConfigInit = 8,
+    Complete = 9,
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/LaunchStage.cs.meta b/Main/Core/GameEngine/Launch/LaunchStage.cs.meta
new file mode 100644
index 0000000..f74aa55
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/LaunchStage.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f3341cae2e8b8e64fba6fedb5d37723a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/LaunchTask.cs b/Main/Core/GameEngine/Launch/LaunchTask.cs
new file mode 100644
index 0000000..09faf70
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/LaunchTask.cs
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+using UnityEngine;
+
+public abstract class LaunchTask
+{
+    public float timer { get; protected set; }
+    public float duration { get; protected set; }
+    bool exceptionReported = false;
+
+    public bool done { get; protected set; }
+    public float progress { get; protected set; }
+    public virtual float expectTime { get; protected set; }
+
+    protected float outTime = 15f;
+
+    public abstract void Begin();
+    public abstract void Update();
+    public abstract void End();
+
+    public void ExceptionReport()
+    {
+        if (!exceptionReported && timer > outTime && !done)
+        {
+            var content = string.Format("浠诲姟锛歿0};缃戠粶鐘舵�侊細{1}", this.GetType().Name, Application.internetReachability);
+            exceptionReported = true;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/LaunchTask.cs.meta b/Main/Core/GameEngine/Launch/LaunchTask.cs.meta
new file mode 100644
index 0000000..5396a01
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/LaunchTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8f8006ef67733114da2ae2e8e0679323
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/RequestPermissionStart.cs b/Main/Core/GameEngine/Launch/RequestPermissionStart.cs
new file mode 100644
index 0000000..009a104
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/RequestPermissionStart.cs
@@ -0,0 +1,38 @@
+
+//鍚屾剰闅愮鏉冮檺鍚庢墠鍙互鐢宠鏉冮檺
+public class RequestPermissionStart : LaunchTask
+{
+
+    public override void Begin()
+    {
+        if (LocalSave.GetBool("secretToggleStart5"))
+        {
+            SDKUtils.Instance.IsAgreeSecret = true;
+            SDKUtils.Instance.RequestAndroidPermissionStart();
+        }
+        else
+        {
+            //鍏堝脊闅愮鏀跨瓥锛屽悓鎰忎箣鍚庢墠鍙互鐢宠鏉冮檺 缁х画娓告垙
+            // YYL TODO
+            // WindowCenter.Instance.OpenFromLocal<RequestSecretWin>();
+        }
+    }
+
+    public override void End()
+    {
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        if  (SDKUtils.Instance.IsAgreeSecret)
+        {
+            done = true;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/RequestPermissionStart.cs.meta b/Main/Core/GameEngine/Launch/RequestPermissionStart.cs.meta
new file mode 100644
index 0000000..caee690
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/RequestPermissionStart.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d683f8dc80b4bf24b93f9be3077bd724
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Launch/SDKInitedTask.cs b/Main/Core/GameEngine/Launch/SDKInitedTask.cs
new file mode 100644
index 0000000..a76b3ff
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/SDKInitedTask.cs
@@ -0,0 +1,58 @@
+
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.IO;
+using System;
+
+public class SDKInitedTask : LaunchTask
+{
+    public override float expectTime
+    {
+        get { return LocalSave.GetFloat("SDKInitedTask_ExpectTime", 1f); }
+        protected set { LocalSave.SetFloat("SDKInitedTask_ExpectTime", value); }
+    }
+
+    public override void Begin()
+    {
+        LaunchInHot.m_CurrentStage = LaunchStage.SDKInit;
+        duration = Mathf.Max(0.1f, expectTime);
+    }
+
+    public override void End()
+    {
+        expectTime = timer;
+        Debug.LogFormat("{0}鎵ц鏃堕暱锛歿1}锛�", this.GetType().Name, timer);
+
+        // TODO YYL
+        // OperationLogCollect.Instance.RecordLauchEvent(1);
+        // OperationLogCollect.Instance.RecordEvent(1);
+
+        var cpu = 2;
+        var memory = 2048;
+        DeviceUtility.GetCpuAndMemory(out cpu, out memory);
+        Debug.LogFormat("鑾峰緱鏈哄櫒淇℃伅锛歝pu {0}----鍐呭瓨 {1}", cpu, memory);
+
+    }
+
+    public override void Update()
+    {
+        if (done)
+        {
+            return;
+        }
+
+        timer += Time.deltaTime;
+        if (SDKUtils.Instance.InitFinished)
+        {
+            done = true;
+        }
+        else
+        {
+            done = false;
+            progress = timer / duration;
+        }
+
+        ExceptionReport();
+    }
+}
\ No newline at end of file
diff --git a/Main/Core/GameEngine/Launch/SDKInitedTask.cs.meta b/Main/Core/GameEngine/Launch/SDKInitedTask.cs.meta
new file mode 100644
index 0000000..0610be4
--- /dev/null
+++ b/Main/Core/GameEngine/Launch/SDKInitedTask.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6bf40baa355319f45b1de7b03576713a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/GameEngine/Login.meta b/Main/Core/GameEngine/Login.meta
new file mode 100644
index 0000000..e99982a
--- /dev/null
+++ b/Main/Core/GameEngine/Login.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8eda8f1b1cda90b408dd25bd730b25ab
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Manager/ResManager.cs b/Main/Manager/ResManager.cs
index d9bddf8..4fc65df 100644
--- a/Main/Manager/ResManager.cs
+++ b/Main/Manager/ResManager.cs
@@ -128,7 +128,16 @@
         
     }
 
-    
+    public string GetAssetFilePath(string _assetKey)
+    {
+        var path = Path.Combine(ExternalStorePath, _assetKey);
+        if (!File.Exists(path))
+        {
+            path = Path.Combine(StreamingAssetPath, _assetKey);
+        }
+
+        return path;
+    }
 
 
 }
\ No newline at end of file
diff --git a/Main/Manager/StageManager.cs b/Main/Manager/StageManager.cs
index 04ddcc0..9451f58 100644
--- a/Main/Manager/StageManager.cs
+++ b/Main/Manager/StageManager.cs
@@ -13,9 +13,9 @@
 {
     public StageName currentStage;
 
-    public Action AfterEnterGame;
+    public Action AfterLoadingGameScene;
 
-    public Action BeforeEnterGame;
+    public Action BeforeLoadingGameScene;
 
     // public Action OnSwitchAccount;
 
@@ -26,8 +26,8 @@
 
     public void Release()
     {
-        AfterEnterGame = null;
-        BeforeEnterGame = null;
+        AfterLoadingGameScene = null;
+        BeforeLoadingGameScene = null;
     }
 
     public async UniTaskVoid ToLoginScene()
@@ -70,8 +70,8 @@
     public async UniTaskVoid ToGameScene()
     {
         UIManager.Instance.DestroyAllUI();
-
-        AfterEnterGame?.Invoke();
+        
+        BeforeLoadingGameScene?.Invoke();
 
         // ResManager.Instance.PrewarmResources();
 
@@ -82,7 +82,7 @@
         //  鍔犺浇鍒濆鍖栨暟鎹畬鎴�
         currentStage = StageName.Game;
 
-        BeforeEnterGame?.Invoke();
+        AfterLoadingGameScene?.Invoke();
 
         UIManager.Instance.OpenWindow<MainWin>();
     }
diff --git a/Main/ResModule/AssetBundle/AssetBundleUtility.cs b/Main/ResModule/AssetBundle/AssetBundleUtility.cs
index abc9bc8..0337822 100644
--- a/Main/ResModule/AssetBundle/AssetBundleUtility.cs
+++ b/Main/ResModule/AssetBundle/AssetBundleUtility.cs
@@ -3,7 +3,7 @@
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
-
+using Cysharp.Threading.Tasks;
 
 public class AssetBundleUtility : SingletonMonobehaviour<AssetBundleUtility>
 {
@@ -97,23 +97,23 @@
         assetBundle = null;
     }
 
-    public IEnumerator Initialize()
+    public async UniTask Initialize()
     {
-        yield return StartCoroutine(Co_LoadMainfestFile("audio"));
-        yield return StartCoroutine(Co_LoadMainfestFile("video"));
-        yield return StartCoroutine(Co_LoadMainfestFile("mobeffectshader"));
-        yield return StartCoroutine(Co_LoadMainfestFile("config"));
-        yield return StartCoroutine(Co_LoadMainfestFile("maps"));
-        yield return StartCoroutine(Co_LoadMainfestFile("ui"));
+        await Co_LoadMainfestFile("audio");
+        await Co_LoadMainfestFile("video");
+        await Co_LoadMainfestFile("mobeffectshader");
+        await Co_LoadMainfestFile("config");
+        await Co_LoadMainfestFile("maps");
+        await Co_LoadMainfestFile("ui");
 
-        yield return StartCoroutine(Co_LoadAssetBundle(ResourcesPath.windowFileBundleName));
-        yield return StartCoroutine(Co_LoadAssetBundle(ResourcesPath.uiprefabFileBundleName));
+        await Co_LoadAssetBundle(ResourcesPath.windowFileBundleName);
+        await Co_LoadAssetBundle(ResourcesPath.uiprefabFileBundleName);
 
         initializedUIAssetBundle = true;
         initialized = true;
     }
 
-    private IEnumerator Co_LoadMainfestFile(string _category)
+    private async UniTask Co_LoadMainfestFile(string _category)
     {
         var path = AssetVersionUtility.GetAssetFilePath(StringUtility.Contact(AssetVersionUtility.EncodeFileName(_category), "_assetbundle"), false);
         var _assetBundle = AssetBundle.LoadFromFile(path);
@@ -121,14 +121,14 @@
         if (_assetBundle == null)
         {
             Debug.LogErrorFormat("AssetBundleManifest鐨勫寘鏂囦欢涓虹┖鎴栬�呭姞杞藉嚭閿�.  Path:{0}", path);
-            yield break;
+            return;
         }
 
         AssetBundleManifest _assetBundleManifest = _assetBundle.LoadAsset<AssetBundleManifest>(ResourcesPath.AssetDependentFileAssetName);
         if (_assetBundleManifest == null)
         {
             Debug.LogErrorFormat("AssetBundleManifest鐨勫寘鏂囦欢涓虹┖鎴栬�呭姞杞藉嚭閿�.  Path:{0}", path);
-            yield break;
+            return;
         }
 
         string[] _assetBundleNames = _assetBundleManifest.GetAllAssetBundles();
@@ -172,10 +172,10 @@
             return;
         }
 
-        StartCoroutine(Co_DoLoadAsset(assetBundleName, assetName, callBack));
+        Co_DoLoadAsset(assetBundleName, assetName, callBack).Forget();
     }
 
-    private IEnumerator Co_LoadAssetBundle(string assetBundleName)
+    private async UniTask<AssetBundle> Co_LoadAssetBundle(string assetBundleName)
     {
 #if UNITY_5||UNITY_5_3_OR_NEWER
         assetBundleName = assetBundleName.ToLower();
@@ -183,7 +183,7 @@
 
         if (JudgeExistAssetBundle(assetBundleName))
         {
-            yield break;
+            return m_AssetBundleDict[assetBundleName];
         }
 
         if (m_LoadingAssetBundleList.Contains(assetBundleName))
@@ -191,9 +191,9 @@
             while (!m_AssetBundleDict.ContainsKey(assetBundleName))
             {
                 // Debug.Log(Time.frameCount + " ] 姝e湪鍔犺浇AssetBundle: " + assetBundleName + ", 璇风瓑寰�...");
-                yield return null;
+                await UniTask.Yield();
             }
-            yield break;
+            return m_AssetBundleDict[assetBundleName];
         }
 
         m_LoadingAssetBundleList.Add(assetBundleName);
@@ -202,12 +202,13 @@
         if (_assetBundleInfo == null)
         {
             Debug.LogErrorFormat("Co_LoadAssetBundle(): {0}鍑虹幇閿欒 => 涓嶅瓨鍦ˋssetBundleInfo. ", assetBundleName);
-            yield break;
+            m_LoadingAssetBundleList.Remove(assetBundleName);
+            return null;
         }
 
         if (_assetBundleInfo.dependentBundles.Length > 0)
         {
-            yield return Co_LoadAssetBundleDependenice(_assetBundleInfo);
+            await Co_LoadAssetBundleDependenice(_assetBundleInfo);
         }
 
         var isBuiltin = assetBundleName.Contains("builtin");
@@ -216,44 +217,41 @@
         Debug.LogFormat("Co_LoadAssetBundle(): 灏嗚鍔犺浇鐨刟ssetBundle鍖呰矾寰� => {0}", filePath);
 
         var _request = AssetBundle.LoadFromFileAsync(filePath);
-        while (!_request.isDone)
-        {
-            yield return null;
-        }
+        await _request;
 
         CacheAssetBundle(assetBundleName, _request.assetBundle);
 
         m_LoadingAssetBundleList.Remove(assetBundleName);
+        return _request.assetBundle;
     }
 
-    private IEnumerator Co_LoadAssetBundleDependenice(AssetBundleInfo assetBundleInfo)
+    private async UniTask Co_LoadAssetBundleDependenice(AssetBundleInfo assetBundleInfo)
     {
         AssetBundle _assetBundle = null;
 
         if (assetBundleInfo.dependentBundles == null
          || assetBundleInfo.dependentBundles.Length == 0)
         {
-            yield break;
+            return;
         }
 
         for (int i = 0; i < assetBundleInfo.dependentBundles.Length; ++i)
         {
-
             if (m_AssetBundleDict.TryGetValue(assetBundleInfo.dependentBundles[i], out _assetBundle) == false)
             {
-                yield return Co_LoadAssetBundle(assetBundleInfo.dependentBundles[i]);
+                await Co_LoadAssetBundle(assetBundleInfo.dependentBundles[i]);
             }
             else
             {
                 if (_assetBundle == null)
                 {
-                    yield return Co_LoadAssetBundle(assetBundleInfo.dependentBundles[i]);
+                    await Co_LoadAssetBundle(assetBundleInfo.dependentBundles[i]);
                 }
             }
         }
     }
 
-    private IEnumerator Co_DoLoadAsset(string assetBundleName, string assetName, Action<bool, UnityEngine.Object> callBack = null)
+    private async UniTask Co_DoLoadAsset(string assetBundleName, string assetName, Action<bool, UnityEngine.Object> callBack = null)
     {
 #if UNITY_5||UNITY_5_3_OR_NEWER
         assetBundleName = assetBundleName.ToLower();
@@ -263,7 +261,7 @@
         RunTimeABLoadLog.AddLog(assetBundleName, assetName, UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
 #endif
 
-        yield return Co_LoadAssetBundle(assetBundleName);
+        await Co_LoadAssetBundle(assetBundleName);
 
         if (!m_AssetBundleDict.ContainsKey(assetBundleName))
         {
@@ -271,7 +269,7 @@
             {
                 callBack(false, null);
             }
-            yield break;
+            return;
         }
 
         string _checkTag = assetBundleName + "@" + assetName;
@@ -281,7 +279,7 @@
                 || !m_AssetDict[assetBundleName].ContainsKey(assetName))
             {
                 //                Debug.Log(Time.frameCount + " ] 姝e湪鍔犺浇Asset: " + _checkTag + ", 璇风瓑寰�...");
-                yield return null;
+                await UniTask.Yield();
             }
 
             if (callBack != null)
@@ -289,16 +287,13 @@
                 callBack(true, m_AssetDict[assetBundleName][assetName]);
             }
 
-            yield break;
+            return;
         }
 
         m_LoadingAssetList.Add(_checkTag);
 
         var request = m_AssetBundleDict[assetBundleName].LoadAssetAsync(assetName);
-        while (!request.isDone)
-        {
-            yield return null;
-        }
+        await request;
 
         if (request.asset != null)
         {
@@ -319,14 +314,14 @@
         m_LoadingAssetList.Remove(_checkTag);
     }
 
-    private IEnumerator Co_DoLoadAsset(AssetInfo assetInfo, Action<bool, UnityEngine.Object> callBack = null)
+    private async UniTask Co_DoLoadAsset(AssetInfo assetInfo, Action<bool, UnityEngine.Object> callBack = null)
     {
         if (assetInfo == null)
         {
             Debug.LogErrorFormat("Co_DoLoadAsset(): {0}, 鍑虹幇閿欒 => 瀛樺叆鐨凙ssetInfo涓簄ull. ", assetInfo);
-            yield break;
+            return;
         }
-        yield return Co_DoLoadAsset(assetInfo.assetBundleName, assetInfo.name, callBack);
+        await Co_DoLoadAsset(assetInfo.assetBundleName, assetInfo.name, callBack);
     }
 
     #endregion
diff --git a/Main/Utility/SevenZipUtility.cs b/Main/Utility/SevenZipUtility.cs
new file mode 100644
index 0000000..c9b10d1
--- /dev/null
+++ b/Main/Utility/SevenZipUtility.cs
@@ -0,0 +1,45 @@
+锘縰sing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.IO;
+
+public class SevenZipUtility
+{
+    static string m_SevenZipToolPath = string.Empty;
+    static string sevenZipToolPath {
+        get {
+            if (string.IsNullOrEmpty(m_SevenZipToolPath))
+            {
+                if (Directory.Exists("C:/Program Files/7-Zip"))
+                {
+                    m_SevenZipToolPath = "C:/Program Files/7-Zip";
+                }
+                else
+                {
+                    m_SevenZipToolPath = "C:/Program Files (x86)/7-Zip";
+                }
+            }
+
+            return m_SevenZipToolPath;
+        }
+    }
+
+    public static void Compress(string from, string to)
+    {
+        if (File.Exists(to))
+        {
+            File.Delete(to);
+        }
+
+        var cmd = string.Format("\"{0}\\7z\" a {1} {2} -mx9", sevenZipToolPath, to, from);
+        SystemCMD.RunCmd(cmd);
+    }
+
+    public static void DeCompress(string from, string to)
+    {
+#if !(UNITY_IOS || UNITY_IPHONE)
+        lzma.doDecompress7zip(from, to, false, true);
+#endif
+    }
+
+}
diff --git a/Main/Utility/SevenZipUtility.cs.meta b/Main/Utility/SevenZipUtility.cs.meta
new file mode 100644
index 0000000..616b376
--- /dev/null
+++ b/Main/Utility/SevenZipUtility.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b621d727b43cf804d96bdadc965bc774
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Utility/ShaderUtility.cs b/Main/Utility/ShaderUtility.cs
new file mode 100644
index 0000000..648fcd9
--- /dev/null
+++ b/Main/Utility/ShaderUtility.cs
@@ -0,0 +1,28 @@
+锘縰sing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class ShaderUtility
+{
+
+    public static void InitGlobalParams()
+    {
+        Shader.SetGlobalColor("_Gbl_Lgt", new Color(0.8f, 0.8f, 0.8f, 1));
+        Shader.SetGlobalColor("_Gbl_Pnt", new Color(1, 1, 1, 1));
+        Shader.SetGlobalColor("_Gbl_Amb", new Color(1, 1, 1, 1));
+        Shader.SetGlobalColor("_Gbl_Spc", new Color(0.8f, 0.8f, 0.8f, 1));
+        Shader.SetGlobalColor("_Gbl_Rim", new Color(1, 1, 1, 1));
+        Shader.SetGlobalColor("_Gbl_Wat", new Color(1, 1, 1, 1));
+    }
+
+    public static void WarmUpAll()
+    {
+        if (!AssetSource.shaderFromEditor)
+        {
+            AssetBundleUtility.Instance.Sync_LoadAllAssets("graphic/shader");
+            Shader.WarmupAllShaders();
+        }
+    }
+
+
+}
diff --git a/Main/Utility/ShaderUtility.cs.meta b/Main/Utility/ShaderUtility.cs.meta
new file mode 100644
index 0000000..f1e9062
--- /dev/null
+++ b/Main/Utility/ShaderUtility.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 474969e2043f6864aad54234f84d18c3
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

--
Gitblit v1.8.0