From ca893f86879de0035804cff16b8c2f878732b62a Mon Sep 17 00:00:00 2001 From: Denis Denisov Date: Thu, 27 May 2021 23:59:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BA=D1=8D=D1=88=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D1=81=D0=BA=D0=B5=D0=B9=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=BA=D0=B0=D1=80=D1=82=D0=B8=D0=BD=D0=BE?= =?UTF-8?q?=D0=BA,=20=D1=87=D1=82=D0=BE=D0=B1=D1=8B=20=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D1=85=D0=BE=D0=B4=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=8C=D1=88=D0=B5=20=D0=B1=D0=B0=D1=82=D0=B0=D1=80=D0=B5?= =?UTF-8?q?=D0=B9=D0=BA=D0=B8=20=D0=B8=20=D1=81=D0=B5=D1=82=D0=B5=D0=B2?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=82=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assembly-CSharp.csproj | 2 + Assets/Scripts/Cache.cs | 160 ++++++++++++++++++++++++ Assets/Scripts/Cache.cs.meta | 11 ++ Assets/Scripts/CacheDescription.cs | 15 +++ Assets/Scripts/CacheDescription.cs.meta | 11 ++ Assets/Scripts/PhotoFrame.cs | 49 +++++--- ProjectSettings/ProjectSettings.asset | 2 +- 7 files changed, 231 insertions(+), 19 deletions(-) create mode 100644 Assets/Scripts/Cache.cs create mode 100644 Assets/Scripts/Cache.cs.meta create mode 100644 Assets/Scripts/CacheDescription.cs create mode 100644 Assets/Scripts/CacheDescription.cs.meta diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index 6bdf21b..60be8cf 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -64,6 +64,8 @@ + + diff --git a/Assets/Scripts/Cache.cs b/Assets/Scripts/Cache.cs new file mode 100644 index 0000000..c93794b --- /dev/null +++ b/Assets/Scripts/Cache.cs @@ -0,0 +1,160 @@ +using System; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; + +public class Cache +{ + const int MAX_ELEMENTS = 1000; + const string CACHE_DESCRIPTION_FILE = "files.dat"; + const string CACHE_DATA_DIR = "data"; + + private string rootPath; + private CacheDescription description; + + public Cache(string path) + { + rootPath = path; + if (!Directory.Exists(GetDataPath())) + { + Directory.CreateDirectory(GetDataPath()); + } + LoadDescription(); + CleanupDataDirectory(); + } + + private string GetDataPath() + { + return rootPath + "/" + CACHE_DATA_DIR; + } + + private void CleanupDataDirectory() + { + var directory = GetDataPath(); + var di = new DirectoryInfo(directory); + var files = di.GetFiles(); + foreach (var f in files) + { + if (!description.path.ContainsKey(f.Name)) + { + File.Delete(directory + "/" + f.Name); + } + } + } + + private string RandomName() + { + string result = ""; + for (int i = 0; i < 30; i++) + { + int t = UnityEngine.Random.Range(0, 36); + if (t < 10) result += (char)(t + '0'); + else result += (char)(t - 10 + 'a'); + } + return result; + } + + private void LoadDescription() + { + var path = rootPath + "/" + CACHE_DESCRIPTION_FILE; + try + { + if (File.Exists(path)) + { + Stream openFileStream = File.OpenRead(path); + BinaryFormatter deserializer = new BinaryFormatter(); + description = (CacheDescription)deserializer.Deserialize(openFileStream); + openFileStream.Close(); + } + else + { + description = new CacheDescription(); + } + } + catch (Exception) + { + description = new CacheDescription(); + } + } + + public void Add(string path, byte[] data) + { + if (!description.path.ContainsKey(path)) + { + while (true) + { + var fileName = RandomName(); + if (!File.Exists(GetDataPath() + "/" + fileName)) + { + description.path[path] = fileName; + break; + } + } + } + var filePath = GetDataPath() + "/" + description.path[path]; + File.WriteAllBytes(filePath, data); + description.lastUse[path] = DateTime.Now; + PurgeCache(); + SaveDescription(); + } + + private void SaveDescription() + { + var path = rootPath + "/" + CACHE_DESCRIPTION_FILE; + try + { + BinaryFormatter serializer = new BinaryFormatter(); + Stream openFileStream = File.OpenWrite(path); + serializer.Serialize(openFileStream, description); + openFileStream.Close(); + } + catch (Exception) + { + description = new CacheDescription(); + } + } + + private void PurgeCache() + { + // throw away excess elements + // for now will use slow implementation + while (description.path.Count >= MAX_ELEMENTS) + { + DateTime min = DateTime.MaxValue; + string mpath = null; + foreach (var kv in description.lastUse) + { + if (kv.Value < min) + { + min = kv.Value; + mpath = kv.Key; + } + } + // not found? + if (mpath == null) break; + try + { + File.Delete(GetDataPath() + "/" + description.path[mpath]); + } + catch (IOException) { } + description.path.Remove(mpath); + description.lastUse.Remove(mpath); + } + } + + public byte[] Get(string path) + { + if (!description.path.ContainsKey(path)) + { + return null; + } + try + { + description.lastUse[path] = DateTime.Now; + return File.ReadAllBytes(GetDataPath() + "/" + description.path[path]); + } + catch (IOException) + { + return null; + } + } +} diff --git a/Assets/Scripts/Cache.cs.meta b/Assets/Scripts/Cache.cs.meta new file mode 100644 index 0000000..daed10c --- /dev/null +++ b/Assets/Scripts/Cache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab7ecde33614955458f63144323618b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/CacheDescription.cs b/Assets/Scripts/CacheDescription.cs new file mode 100644 index 0000000..6500ade --- /dev/null +++ b/Assets/Scripts/CacheDescription.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +[Serializable] +public class CacheDescription +{ + public Dictionary path; + public Dictionary lastUse; + + public CacheDescription() + { + path = new Dictionary(); + lastUse = new Dictionary(); + } +} diff --git a/Assets/Scripts/CacheDescription.cs.meta b/Assets/Scripts/CacheDescription.cs.meta new file mode 100644 index 0000000..af454c7 --- /dev/null +++ b/Assets/Scripts/CacheDescription.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0520a1857b831224aac90f9eac2c5772 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PhotoFrame.cs b/Assets/Scripts/PhotoFrame.cs index e4dfd32..2188bf3 100644 --- a/Assets/Scripts/PhotoFrame.cs +++ b/Assets/Scripts/PhotoFrame.cs @@ -20,6 +20,7 @@ public class PhotoFrame : MonoBehaviour InputField url; private int currentImage; + private Cache cache; private Image CurrentImage { @@ -33,6 +34,7 @@ public class PhotoFrame : MonoBehaviour public void Start() { + cache = new Cache(Application.persistentDataPath); Screen.sleepTimeout = SleepTimeout.NeverSleep; currentImage = 0; ActivateUI(true); @@ -89,29 +91,40 @@ public class PhotoFrame : MonoBehaviour int imageIndex = Random.Range(0, loader.images.Count); string imageUrl = loader.images[imageIndex]; - var request = UnityWebRequest.Get(imageUrl); - request.downloadHandler = new DownloadHandlerTexture(true); - yield return request.SendWebRequest(); - - if (request.isNetworkError || request.isHttpError) + var bytes = cache.Get(imageUrl); + if (bytes != null) { - yield return new WaitForSeconds(1f); - continue; + var tex = new Texture2D(2, 2); + tex.LoadImage(bytes); + SetImageTexture(NextImage, tex); } - - var downloadTime = Time.realtimeSinceStartup - startTime; - if (PHOTO_INTERVAL > downloadTime) + else { - yield return new WaitForSeconds(PHOTO_INTERVAL - downloadTime); + var request = UnityWebRequest.Get(imageUrl); + request.downloadHandler = new DownloadHandlerTexture(true); + yield return request.SendWebRequest(); + + if (request.isNetworkError || request.isHttpError) + { + yield return new WaitForSeconds(1f); + continue; + } + + var downloadTime = Time.realtimeSinceStartup - startTime; + if (PHOTO_INTERVAL > downloadTime) + { + yield return new WaitForSeconds(PHOTO_INTERVAL - downloadTime); + } + + var dh = request.downloadHandler as DownloadHandlerTexture; + var tex = dh.texture; + + SetImageTexture(NextImage, tex); + dh.Dispose(); + request.Dispose(); + cache.Add(imageUrl, tex.EncodeToJPG()); } - var dh = request.downloadHandler as DownloadHandlerTexture; - var tex = dh.texture; - - SetImageTexture(NextImage, tex); - dh.Dispose(); - request.Dispose(); - float currentStart = CurrentImage.color.a; float currentFinish = transparent.a; float nextStart = NextImage.color.a; diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index ab06fb2..7a5a4f0 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -118,7 +118,7 @@ PlayerSettings: 16:10: 1 16:9: 1 Others: 1 - bundleVersion: 0.1 + bundleVersion: 0.2 preloadedAssets: [] metroInputSource: 0 wsaTransparentSwapchain: 0