using System; using CommonUI.Display; using UnityEngine; using CommonLang.IO; using System.IO; using CommonLang.Property; using CommonUI_Unity3D.Platform; using CommonUI.Gemo; using System.Collections.Generic; using System.Threading; using MPQ.FileSystem; using MPQ; using MPQ.Updater; using CommonLang.Concurrent; using CommonLang.Log; namespace CommonUI_Unity3D.Impl { public class UnityDriver : Driver, IResourceLoader { public static bool IsDebug = false; private static UnityDriver sInstance; private static IUnityPlatform sPlatform = new DummyUnityPlatform(); public static IUnityPlatform Platform { get { return sPlatform; } } public static UnityDriver UnityInstance { get { if (sInstance == null) { sInstance = new UnityDriver(); } return sInstance; } } public static void SetDirver() { if (sInstance == null) { sInstance = new UnityDriver(); } if (IsWin32) { SetDirver("CommonUI_Unity3D_Win32.UnityPlatformWin32"); } else if (IsIOS) { SetDirver("CommonUI_Unity3D_IOS.UnityPlatformIOS"); } else if (IsAndroid) { SetDirver("CommonUI_Unity3D_Android.UnityPlatformAndroid"); } } public static void SetDirver(string platformDriver) { if (sPlatform is DummyUnityPlatform) { try { Type driver = ReflectionUtil.GetType(platformDriver); if (driver != null) { sPlatform = (IUnityPlatform)ReflectionUtil.CreateInstance(driver); Debug.Log("- Create Platform Driver : " + platformDriver); } else { Debug.LogError("- Can Not Create Platform Driver : " + platformDriver); } } catch (Exception err) { Debug.LogError(err.Message + "\n" + err.StackTrace); } } } public static void SetDirver(IUnityPlatform platform) { if (sPlatform is DummyUnityPlatform) { Debug.Log("- Set Platform Driver : " + platform); sPlatform = platform; } } private UnityDriver() { Resource.SetLoader(this); UnityShaders.InitShaders(); LoggerFactory.SetFactory(new UnityLoggerFactory()); } public override void Assert(bool cond, string msg) { if (!cond) { Debug.LogError("Assert: " + msg); UnityDriver.Platform.Assert("Assert: " + msg); } } // --------------------------------------------------------------------------------- #region PLATFORM_MACRO public static bool IsWin32 { get { return Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer; } } public static bool IsIOS { get { return Application.platform == RuntimePlatform.IPhonePlayer; } } public static bool IsAndroid { get { return Application.platform == RuntimePlatform.Android; } } #endregion // --------------------------------------------------------------------------------- #region Mono #endregion // --------------------------------------------------------------------------------- #region GFX public delegate string RedirectImagePath(string resource); public RedirectImagePath RedirectImage; public delegate Image GetDefaultImg(string resource); public GetDefaultImg OnGetDefaultImg; public override void ReloadImage(Image img) { try { UnityImage ret = img as UnityImage; if (ret != null && !string.IsNullOrEmpty(ret.ResourceStr)) { string resource = ret.ResourceStr; if (resource.StartsWith(PREFIX_MPQ)) { byte[] edata = mFileSystem.getData(resource.Substring(PREFIX_MPQ.Length)); if (edata != null) { ret.ResestTexture2D(edata, resource); } } else if (resource.StartsWith(PREFIX_RES)) { string res_path = resource.Substring(PREFIX_RES.Length); object obj = LoadObjectFromResources(res_path); if (obj is Texture2D) { ret.ResestTexture2D(obj as Texture2D, resource); } if (obj is TextAsset) { TextAsset ta = (obj as TextAsset); ret.ResestTexture2D(ta.bytes, resource); } } else if (resource.StartsWith(PREFIX_FILE)) { FileInfo finfo = new FileInfo(resource.Substring(PREFIX_FILE.Length)); if (finfo.Exists) { byte[] data = File.ReadAllBytes(finfo.FullName); ret.ResestTexture2D(data, resource); } } else { byte[] data = Resource.LoadData(resource); if (data != null) { ret.ResestTexture2D(data, resource); } else { Texture2D tex = LoadFromResources(resource); if (tex != null) { ret.ResestTexture2D(tex, resource); } } } } } catch (System.Exception e) { UnityEngine.Debug.LogException(e); } } public override Image createImage(string resource) { try { UnityImage ret = null; if (RedirectImage != null) { resource = RedirectImage(resource); } if (resource.StartsWith(PREFIX_MPQ)) { byte[] edata = mFileSystem.getData(resource.Substring(PREFIX_MPQ.Length)); if (edata != null) { ret = new UnityImage(edata, resource, resource); } } else if (resource.StartsWith(PREFIX_RES)) { string res_path = resource.Substring(PREFIX_RES.Length); object obj = LoadObjectFromResources(res_path); if (obj is Texture2D) { return new UnityImage(obj as Texture2D, resource, resource); } if (obj is TextAsset) { TextAsset ta = (obj as TextAsset); ret = new UnityImage(ta.bytes, resource, resource); } } else if (resource.StartsWith(PREFIX_FILE)) { FileInfo finfo = new FileInfo(resource.Substring(PREFIX_FILE.Length)); if (finfo.Exists) { byte[] data = File.ReadAllBytes(finfo.FullName); ret = new UnityImage(data, resource, resource); } } else { byte[] data = Resource.LoadData(resource); if (data != null) { ret = new UnityImage(data, resource, resource); } else { Texture2D tex = LoadFromResources(resource); if (tex != null) { ret = new UnityImage(tex, resource, resource); } } } return ret; } catch (System.Exception e) { UnityEngine.Debug.LogError(string.Format("Resource Read Error : {0}\n", resource, e.Message)); UnityEngine.Debug.LogException(e); } //Assert(false, string.Format("Resource Read Error : {0}\n", resource)); if (OnGetDefaultImg != null) { return OnGetDefaultImg(resource); } return null; } public override Image createImage(System.IO.Stream stream) { if (stream == null) { UnityEngine.Debug.Log("Invalid Param : create Image from stream"); return null; } try { // U3D Texture2D byte[] imageData = new byte[stream.Length]; IOUtil.ReadToEnd(stream, imageData, 0, imageData.Length); return new UnityImage(imageData, "createImage(stream)"); } catch (System.Exception e) { UnityEngine.Debug.LogError("Stream Read Error " + e.Message); UnityEngine.Debug.LogException(e); } return null; } public override Image createImage(byte[] imageData, int imageOffset, int imageLength) { try { if (imageLength == imageData.Length) { return new UnityImage(imageData, "createImage(byte[])"); } else { byte[] data = new byte[imageLength]; System.Array.Copy(imageData, imageOffset, data, 0, imageLength); // To UnityImage return new UnityImage(data, "createImage(byte[])"); } } catch (System.Exception e) { UnityEngine.Debug.LogError("ImageData Read Error " + e.Message); UnityEngine.Debug.LogException(e); } return null; } public override Image createRGBImage(uint[] rgba, int width, int height) { UnityEngine.Texture2D destTex = new UnityEngine.Texture2D(width, height, TextureFormat.ARGB32, false, true); int i = 0; UnityEngine.Color color = UnityEngine.Color.white; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++, i++) { CommonUI.Display.Color.toRGBAF(rgba[i], out color.r, out color.g, out color.b, out color.a); destTex.SetPixel(x, y, color); } } destTex.Apply(); return (Image)(new UnityImage(destTex, string.Format("createRGBImage({0},{1})", width, height))); } public override Image createRGBImage(int width, int height) { UnityEngine.Texture2D destTex = new UnityEngine.Texture2D(width, height, TextureFormat.ARGB32, false, true); UnityEngine.Color color = new UnityEngine.Color(0, 0, 0, 0); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { destTex.SetPixel(x, y, color); } } destTex.Apply(); return (Image)(new UnityImage(destTex, string.Format("createRGBImage({0},{1})", width, height))); } public override TextLayer createTextLayer(string text, float size, CommonUI.Display.FontStyle style) { return new UnityTextLayer(text, style, size); } public override bool testTextLineBreak(string text, float size, CommonUI.Display.FontStyle style, int borderTime, float testWidth, out float realWidth, out float realHeight) { return sPlatform.TestTextLineBreak(text, size, style, borderTime, testWidth, out realWidth, out realHeight); } public override VertexBuffer createVertexBuffer(int capacity) { return new UnityVertexBuffer(capacity); } #endregion // --------------------------------------------------------------------------------- #region Resource static private MPQFileSystem mFileSystem; static private string TestDataPath = String.Empty; static public void SetTestDataPath(string path) { TestDataPath = path; } static public void AddFileSystem(MPQFileSystem fs) { mFileSystem = fs; } private static T LoadFromResources(string path) where T : UnityEngine.Object { int index = path.LastIndexOf("."); if (index < 0) { return null; } // Unity TextAsset string assetpath = path.Substring(0, index); while (assetpath.StartsWith("/")) { assetpath = assetpath.Substring(1); } T ta = UnityEngine.Resources.Load(assetpath); //Debug.Log("LoadFromAsserts ==========> " + assetpath + " --- " + ta); return ta; } private static object LoadObjectFromResources(string path) { // Unity TextAsset string assetpath = path.Substring(0, path.LastIndexOf(".")); while (assetpath.StartsWith("/")) { assetpath = assetpath.Substring(1); } return UnityEngine.Resources.Load(assetpath); } //----------------------------------------------------------------------------------------------------------------- #region IResourceLoader #region load private bool TryLoadFromTest(string path, ref byte[] ret) { string fullpath = TestDataPath + "/" + path; try { fullpath = System.IO.Path.GetFullPath(fullpath); if (System.IO.File.Exists(fullpath)) { ret = File.ReadAllBytes(fullpath); if (ret != null) { if (IsDebug) { Debug.Log("Load Data From Test Path : " + fullpath + " -> " + ret.Length + " (bytes)"); } return true; } } } catch (Exception err) { Debug.LogError(err.Message); Debug.LogError("Load Data From Test Path : " + fullpath + " -> " + ret.Length + " (bytes)"); } return false; } private bool TryLoadFromFileSystem(string path, ref byte[] ret) { string fullpath = path; ret = File.ReadAllBytes(fullpath); if (ret != null) { if (IsDebug) { Debug.Log("Load Data From Path : " + fullpath + " -> " + ret.Length + " (bytes)"); } return true; } return false; } private bool TryLoadFromMPQ(string path, ref byte[] ret) { if (mFileSystem != null) { ret = mFileSystem.getData(path); if (ret != null) { if (IsDebug) { Debug.Log("Load Data From MPQ : " + path + " -> " + ret.Length + " (bytes)"); } return true; } } return false; } private bool TryLoadFromResources(string path, ref byte[] ret) { TextAsset data = LoadFromResources(path); if (data != null) { ret = data.bytes; if (IsDebug) { Debug.Log("Load Data From Unity Resources : " + path + " -> " + ret.Length + " (bytes)"); } return true; } return false; } private bool TryLoadFromJAR(string path, ref byte[] ret) { var data = CommonUI_Unity3D_Android.WWWHelper.getJavaData(path); //yield return data; if (data != null) { ret = data; if (IsDebug) { Debug.Log("Load Data From JAR : " + path + " -> " + ret.Length + " (bytes)"); } return true; } return false; } #endregion //------------------------------------------------------------------------------------------------------------------------ #region stream private bool TryOpenFromTest(string path, ref Stream ret) { string fullpath = TestDataPath + "/" + path; try { fullpath = System.IO.Path.GetFullPath(fullpath); if (System.IO.File.Exists(fullpath)) { ret = new FileStream(fullpath, FileMode.Open, FileAccess.Read, FileShare.Read);// File.ReadAllBytes(fullpath); if (ret != null) { if (IsDebug) { Debug.Log("Load Data From Test Path : " + fullpath + " -> " + ret.Length + " (bytes)"); } return true; } } } catch (Exception err) { Debug.LogError(err.Message); Debug.LogError("Load Data From Test Path : " + fullpath + " -> " + ret.Length + " (bytes)"); } return false; } private bool TryOpenFromFileSystem(string path, ref Stream ret) { string fullpath = path; ret = new FileStream(fullpath, FileMode.Open, FileAccess.Read, FileShare.Read); //File.ReadAllBytes(fullpath); if (ret != null) { if (IsDebug) { Debug.Log("Load Data From Path : " + fullpath + " -> " + ret.Length + " (bytes)"); } return true; } return false; } private bool TryOpenFromMPQ(string path, ref Stream ret) { if (mFileSystem != null) { ret = mFileSystem.openStream(path); if (ret != null) { if (IsDebug) { Debug.Log("Load Data From MPQ : " + path + " -> " + ret.Length + " (bytes)"); } return true; } } return false; } private bool TryOpenFromResources(string path, ref Stream ret) { return false; } private bool TryOpenFromJAR(string path, ref Stream ret) { return false; } #endregion //------------------------------------------------------------------------------------------------------------------------ #region exist private bool TryExistDataFromMPQ(string path) { if (mFileSystem != null) { if (mFileSystem.findEntry(path) != null) { return true; } } return false; } private bool TryExistDataFromFileSystem(string path) { if (File.Exists(path)) { return true; } return false; } private bool TryExistDataFromTestPath(string path) { if (Directory.Exists(TestDataPath)) { string fullpath = TestDataPath + "/" + path; try { fullpath = System.IO.Path.GetFullPath(fullpath); if (System.IO.File.Exists(fullpath)) { return true; } } catch (Exception err) { Assert(false, "ExitDataFromTestPath Error:" + err.ToString() + path.ToString()); } } return false; } private bool TryExistDataFromJAR(string path) { return CommonUI_Unity3D_Android.WWWHelper.isFileExists(path); } #endregion //------------------------------------------------------------------------------------------------------------------------ public const string PREFIX_FILE = "file://"; public const string PREFIX_MPQ = "mpq://"; public const string PREFIX_RES = "res://"; public const string PREFIX_JAR = "jar://"; //"jar:file://" + Application.dataPath + "!/assets/"; public bool ExistData(string path) { bool rlt = false; //From MPQ. if (path.StartsWith(PREFIX_MPQ)) { rlt = TryExistDataFromMPQ(path.Substring(PREFIX_MPQ.Length)); return rlt; } if (path.StartsWith(PREFIX_FILE)) { rlt = TryExistDataFromFileSystem(path.Substring(PREFIX_FILE.Length)); return rlt; } if (path.StartsWith(PREFIX_JAR)) { rlt = TryExistDataFromJAR(path.Substring(PREFIX_JAR.Length)); return rlt; } if (IsAndroid && path.StartsWith(Application.streamingAssetsPath)) { rlt = TryExistDataFromJAR(path.Substring(Application.streamingAssetsPath.Length)); return rlt; } //From MPQ. rlt = TryExistDataFromMPQ(path); if (rlt) { return rlt; } //From Test. rlt = TryExistDataFromTestPath(path); if (rlt) { return rlt; } //From File. rlt = TryExistDataFromFileSystem(path); if (rlt) { return rlt; } return rlt; } public byte[] LoadData(string path) { byte[] ret = null; // Specify Prefix. if (path.StartsWith(PREFIX_MPQ)) { TryLoadFromMPQ(path.Substring(PREFIX_MPQ.Length), ref ret); return ret; } if (path.StartsWith(PREFIX_FILE)) { TryLoadFromFileSystem(path.Substring(PREFIX_FILE.Length), ref ret); return ret; } if (path.StartsWith(PREFIX_RES)) { TryLoadFromResources(path.Substring(PREFIX_RES.Length), ref ret); return ret; } if (path.StartsWith(PREFIX_JAR)) { TryLoadFromJAR(path.Substring(PREFIX_JAR.Length), ref ret); return ret; } if (IsAndroid && path.StartsWith(Application.streamingAssetsPath)) { TryLoadFromJAR(path.Substring(Application.streamingAssetsPath.Length), ref ret); return ret; } // Just Test. if (Directory.Exists(TestDataPath) && TryLoadFromTest(path, ref ret)) { return ret; } // MPQ. if (mFileSystem != null && TryLoadFromMPQ(path, ref ret)) { return ret; } // File. if (File.Exists(path) && TryLoadFromFileSystem(path, ref ret)) { return ret; } // Applicateion Data Path. if (TryLoadFromResources(path, ref ret)) { return ret; } if (IsDebug) { Debug.LogWarning("Can Not Read Resource : " + path); } return ret; } public virtual Stream LoadDataAsStream(string path) { Stream ret = null; // Specify Prefix. if (path.StartsWith(PREFIX_MPQ)) { TryOpenFromMPQ(path.Substring(PREFIX_MPQ.Length), ref ret); return ret; } if (path.StartsWith(PREFIX_FILE)) { TryOpenFromFileSystem(path.Substring(PREFIX_FILE.Length), ref ret); return ret; } // Just Test. if (Directory.Exists(TestDataPath) && TryOpenFromTest(path, ref ret)) { return ret; } // MPQ. if (mFileSystem != null && TryOpenFromMPQ(path, ref ret)) { return ret; } // File. if (File.Exists(path) && TryOpenFromFileSystem(path, ref ret)) { return ret; } if (IsDebug) { Debug.LogWarning("Can Not Read Resource : " + path); } return ret; } public virtual string[] ListFiles(string path) { throw new NotImplementedException(); } #endregion //----------------------------------------------------------------------------------------------------------------- public AssetBundleCreateRequest LoadAssetBundle(string path, out int size) { size = 0; byte[] bin = LoadData(path); if (bin != null) { size = bin.Length; try { return AssetBundle.LoadFromMemoryAsync(bin); } catch (Exception err) { Assert(false, "LoadAssetBundle : Error " + path + "\n" + err.Message); } } return null; } public AssetBundleCreateRequest LoadAssetBundle(string path) { byte[] bin = LoadData(path); if (bin != null) { try { return AssetBundle.LoadFromMemoryAsync(bin); } catch (Exception err) { Assert(false, "LoadAssetBundle : Error " + path + "\n" + err.Message); } } return null; } public AssetBundle LoadAssetBundleImmediate(string path) { byte[] bin = LoadData(path); if (bin != null) { try { return AssetBundle.LoadFromMemory(bin); } catch (Exception err) { Assert(false, "LoadAssetBundleImmediate : Error " + path + "\n" + err.Message); } } return null; } #endregion // --------------------------------------------------------------------------------- #region TextInput #endregion // --------------------------------------------------------------------------------- #region MPQ public class MPQAdapter : MPQDirver { public override long GetAvaliableSpace(string path) { return sPlatform.GetAvaliableSpace(path); } public override long GetTotalSpace(string path) { return sPlatform.GetTotalSpace(path); } public override bool RunGetFileMD5(string fullname, out string md5) { return sPlatform.NativeGetFileMD5(fullname, out md5); } public override bool RunUnzipSingle(MPQUpdater updater, MPQUpdater.RemoteFileInfo zip, MPQUpdater.RemoteFileInfo mpq, AtomicLong process) { return sPlatform.NativeDecompressFile(updater, zip, mpq, process); } } public static MPQUpdater CreateMPQUpdater( Uri remote_version_url, string[] remote_version_prefix, string version_suffix, DirectoryInfo local_save_root, DirectoryInfo local_bundle_root, bool validate_md5, MPQUpdaterListener listener) { sPlatform.GetAvaliableSpace(local_save_root.FullName); sPlatform.GetTotalSpace(local_save_root.FullName); var ret = new MPQUpdater(new MPQAdapter()); ret.Init( remote_version_url, remote_version_prefix, version_suffix, local_save_root, local_bundle_root, "", validate_md5, listener); return ret; } public static MPQUpdater CreateMPQUpdater( string[] remote_version_prefix, string version_suffix, DirectoryInfo local_save_root, DirectoryInfo local_bundle_root, bool validate_md5, MPQUpdaterListener listener) { sPlatform.GetAvaliableSpace(local_save_root.FullName); sPlatform.GetTotalSpace(local_save_root.FullName); var ret = new MPQUpdater(new MPQAdapter()); ret.Init( new Uri(""), remote_version_prefix, version_suffix, local_save_root, local_bundle_root, "", validate_md5, listener); return ret; } #endregion // --------------------------------------------------------------------------------- public class DummyUnityPlatform : IUnityPlatform { public bool IsNativeUnzip { get { return false; } } public void Assert(string msg) { } public Texture2D SysFontTexture(string text, bool readable, CommonUI.Display.FontStyle style, int fontSize, uint fontColor, int borderTime, uint borderColor, Size2D expectSize, out int boundW, out int boundH) { boundW = 8; boundH = 8; return new Texture2D(8, 8, TextureFormat.ARGB32, false, true); } public bool TestTextLineBreak(string text, float size, CommonUI.Display.FontStyle style, int borderTime, float testWidth, out float realWidth, out float realHeight) { realWidth = 8; realHeight = 8; return false; } public void CopyPixels(Texture2D src, int sx, int sy, int sw, int sh, Texture2D dst, int dx, int dy) { } public long GetAvaliableSpace(string path) { return long.MaxValue; } public long GetTotalSpace(string path) { return long.MaxValue; } public bool NativeDecompressFile(MPQUpdater updater, MPQUpdater.RemoteFileInfo zip_file, MPQUpdater.RemoteFileInfo mpq_file, AtomicLong current_unzip_bytes) { throw new NotImplementedException(); } public bool NativeDecompressMemory(ArraySegment src, ArraySegment dst) { throw new NotImplementedException(); } public bool NativeGetFileMD5(string fullname, out string md5) { throw new NotImplementedException(); } } } }