From 74ba5790f901b94fdf128480824f9d3f42e905b0 Mon Sep 17 00:00:00 2001 From: lishuo Date: Thu, 18 May 2023 19:06:40 +0800 Subject: [PATCH] =?UTF-8?q?AR=E6=96=87=E4=BB=B6=E6=9B=B4=E6=96=B0=E6=B5=81?= =?UTF-8?q?=E7=A8=8B&AR=E7=BD=91=E7=BB=9C=E5=BB=B6=E6=97=B6=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/AR/ARDownloader.cs | 194 ++++++++++ Assets/AR/ARDownloader.cs.meta | 3 + Assets/AR/ARLaneGameObject.cs | 11 +- Assets/AR/ARLaneGameObjectsController.cs | 17 +- Assets/AR/ARRoute.cs | 17 +- Assets/AR/ARRouteData.cs | 3 +- Assets/AR/PlayerRenderer.cs | 25 -- Assets/Scripts/App.cs | 3 +- Assets/Scripts/Scenes/AR/UI/VideoLoading.cs | 182 +++++----- Assets/Scripts/Scenes/AR/UI/VideoUIManager.cs | 2 +- Assets/Scripts/Scenes/AR/VideoGameManager.cs | 70 ++-- .../Scenes/Ride/Model/RecorderDataModel.cs | 119 ++++--- Assets/Scripts/Scenes/Ride/Scripts/Helper.cs | 12 + .../UI/Prefab/GameRoom/GameRoomDownLoad.cs | 135 +++---- .../UI/Prefab/GameRoom/GameRoomMapItem.cs | 161 ++++++--- .../Prefab/Panel/GameRoomDetailController.cs | 331 ++++++++++-------- .../UI/Prefab/Panel/GameRoomListController.cs | 46 ++- Assets/Scripts/Utils/Loom.cs | 44 ++- 18 files changed, 867 insertions(+), 508 deletions(-) create mode 100644 Assets/AR/ARDownloader.cs create mode 100644 Assets/AR/ARDownloader.cs.meta diff --git a/Assets/AR/ARDownloader.cs b/Assets/AR/ARDownloader.cs new file mode 100644 index 00000000..e3664b66 --- /dev/null +++ b/Assets/AR/ARDownloader.cs @@ -0,0 +1,194 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Assets.Scenes.Ride.Scripts; +using Assets.Scripts.Apis.Models; +using Cysharp.Threading.Tasks; +using UnityEngine.Networking; + +namespace Assets.AR +{ + public class ARDownloader + { + private MapRoute _route; + + private readonly string _localARDataPath; + private readonly string _localARRoutePath; + private readonly string _localVideoPath; + private readonly string _serverARDataPath; + private readonly string _serverARRoutePath; + private readonly string _serverVideoPath; + + public bool IsVideoDownloaded { get; private set; } + public bool IsARDataDownloaded { get; private set; } + public bool IsARRouteDownloaded { get; private set; } + public float Total { get; private set; } = 0; + + public ARDownloader(MapRoute route) + { + this._route = route; + + var dataPath = $"{PFConstants.ARFolder}/{_route.Id}"; + var path = PFConstants.VideoFolder; + Helper.CreateDirectoryIfNotExsit(dataPath); + + _localARDataPath = $"{dataPath}/{_route.Id}.json"; + _localARRoutePath = $"{dataPath}/route-{_route.Id}.json"; + _localVideoPath = $"{path}/{_route.FileName}"; + + _serverARDataPath = _route.ARConfig; + _serverARRoutePath = _route.VideoRoute; + _serverVideoPath = _route.Url; + } + + public async UniTask DownLoadVideoAsync(IProgress progress = null, + CancellationTokenSource cancellation = default(CancellationTokenSource)) + { + return await DownloadToFileAsync(_serverVideoPath, _localVideoPath, progress, cancellation); + } + + public async UniTask DownLoadARRouteAsync(IProgress progress = null, + CancellationTokenSource cancellation = default(CancellationTokenSource)) + { + return await DownloadToFileAsync(_serverARRoutePath, _localARRoutePath, progress, cancellation); + } + + public async UniTask DownLoadARDataAsync(IProgress progress = null, + CancellationTokenSource cancellation = default(CancellationTokenSource)) + { + return await DownloadToFileAsync(_serverARDataPath, _localARDataPath, progress, cancellation); + } + + public async Task CheckAllAsync() + { + IsARRouteDownloaded = await CheckARRouteAsync(); + IsARDataDownloaded = await CheckARDataAsync(); + IsVideoDownloaded = await CheckVideoAsync(); + + if (IsVideoDownloaded) + Total += 1f; + if (IsARRouteDownloaded) + Total += 1f; + if (IsARDataDownloaded) + Total += 1f; + + return IsVideoDownloaded || IsARRouteDownloaded || IsARDataDownloaded; + } + + /// + /// return true if the video is needed to download + /// + /// + public async Task CheckVideoAsync() + { + try + { + if (!File.Exists(_localVideoPath)) return true; + var result = await HeadFileAsync(_serverVideoPath, _localVideoPath); + return result.responseCode != 304; + } + catch (Exception e) + { + return false; + } + } + + /// + /// return true if the video is needed to download + /// + /// + public async Task CheckARRouteAsync() + { + if (!File.Exists(_localARRoutePath)) return true; + var result = await HeadFileAsync(_serverARRoutePath, _localARRoutePath); + return result.responseCode != 304; + } + + /// + /// return true if the video is needed to download + /// + /// + public async Task CheckARDataAsync() + { + if (!File.Exists(_localARDataPath)) return true; + var result = await HeadFileAsync(_serverARDataPath, _localARDataPath); + return result.responseCode != 304; + } + + + /// + /// 下载文件到本地(持续存入磁盘减少内存占用) + /// + /// 文件连接 + /// 本地文件全路径 + /// 下载进度 + public static async UniTask DownloadToFileAsync(string downloadUrl, string fullPath, + IProgress progress = null, CancellationTokenSource cancellation = default(CancellationTokenSource)) + { + var dh = new DownloadHandlerFile(fullPath) + { + removeFileOnAbort = true + }; + + var request = UnityWebRequest.Get(downloadUrl); + request.downloadHandler = dh; + request.method = UnityWebRequest.kHttpVerbGET; + + var result = await request.SendWebRequest().ToUniTask(progress, PlayerLoopTiming.Update, + (cancellation?.Token ?? default(CancellationToken))); + + var etag = result.GetResponseHeader("ETag"); + var path = fullPath + ".etag"; + if (!File.Exists(path)) + { + File.Create(path); + } + File.WriteAllText(path, etag); + + return result; + } + + /// + /// head request for file meta info such as etag. + /// + /// download url + /// local path for storage + /// + public static async UniTask HeadFileAsync(string downloadUrl, string fullPath, + IProgress progress = null, CancellationTokenSource cancellation = default(CancellationTokenSource)) + { + try + { + var etagFile = fullPath + ".etag"; + var etag = string.Empty; + if (File.Exists(etagFile)) + { + etag = File.ReadAllText(etagFile); + } + + var request = UnityWebRequest.Head(downloadUrl); + if (!string.IsNullOrEmpty(etag)) + request.SetRequestHeader("If-None-Match", etag); + + var result = + await request + .SendWebRequest().ToUniTask(progress, PlayerLoopTiming.Update, + (cancellation?.Token ?? default(CancellationToken))); + + if (result.responseCode != 304) + { + etag = result.GetResponseHeader("ETag"); + File.WriteAllText(fullPath + ".etag", etag); + } + + return result; + + } + catch (Exception e) + { + return null; + } + } + } +} \ No newline at end of file diff --git a/Assets/AR/ARDownloader.cs.meta b/Assets/AR/ARDownloader.cs.meta new file mode 100644 index 00000000..e3baeccd --- /dev/null +++ b/Assets/AR/ARDownloader.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 84a219eba2114884a2e246578ade9ab9 +timeCreated: 1684373675 \ No newline at end of file diff --git a/Assets/AR/ARLaneGameObject.cs b/Assets/AR/ARLaneGameObject.cs index e6972f48..111a84df 100644 --- a/Assets/AR/ARLaneGameObject.cs +++ b/Assets/AR/ARLaneGameObject.cs @@ -39,13 +39,16 @@ namespace Assets.AR public int TestPower { get; set; } - public float ZOffset { get; set; } + protected void Start() + { + this.Lane = route.Lane;//轨迹上的距离 + } //重置碰撞检测参数 public void ResetCollisionDetectionParameters() { this.StartPosition = 0;//开始位置 - this.Lane = 0.0f;//轨迹上的距离 + this.Lane = route.Lane;//轨迹上的距离 this.DeltaLane = 0.0f;//差距 this.LaneWidth = 0.0f;//轨迹宽度 this.LaneCamera = 0.0f;//轨迹上摄像头的位置 @@ -59,10 +62,10 @@ namespace Assets.AR { PositionOffset = Vector3.up * route.CameraHeight * (-1); var cameraRotation = this.GetCameraRotation(this.frame - this.FrameIndexDistanceCorrection); - var normalizeCameraRotation = Quaternion.Euler(new Vector3(cameraRotation.eulerAngles.x, cameraRotation.eulerAngles.y, cameraRotation.eulerAngles.z+ZOffset)); + var normalizeCameraRotation = Quaternion.Euler(new Vector3(cameraRotation.eulerAngles.x+route.CameraRotationsOffset.x, cameraRotation.eulerAngles.y+route.CameraRotationsOffset.y, cameraRotation.eulerAngles.z+route.CameraRotationsOffset.z)); var filteredCameraPosition = this.GetFilteredCameraPosition(this.frame - this.FrameIndexDistanceCorrection); - var vector3 = Vector3.left * (this.route.LeftHanded ? -1f : 1f) * (this.LaneWidth * (this.Lane + this.LaneCamera) - this.BaseOffset); + var vector3 = Vector3.left * (this.route.LeftHanded ? -1f : 1f) * (this.LaneWidth * (this.Lane + this.LaneCamera + this.route.Lane) - this.BaseOffset); var targetPos = filteredCameraPosition + normalizeCameraRotation * (vector3 + this.PositionOffset); this.transform.position = targetPos; diff --git a/Assets/AR/ARLaneGameObjectsController.cs b/Assets/AR/ARLaneGameObjectsController.cs index 663b2bb6..e0be69f7 100644 --- a/Assets/AR/ARLaneGameObjectsController.cs +++ b/Assets/AR/ARLaneGameObjectsController.cs @@ -8,7 +8,7 @@ namespace Assets.AR { protected const float LaneWidth = 0.7f; protected const float StartRegionDistance = 200f; - private const float StartRowsGap = 2.2f; + private const float StartRowsGap = 1.0f; private const float StartRowsRandomDistance = 0.4f; private const float StartRowsRandomWidth = 0.15f; private const float MinCollisionDistance = 1.33f; @@ -34,7 +34,7 @@ namespace Assets.AR { var frame = 100f; this.StartRegionRouteWidth = this.GetRouteLeftOffset(frame) + this.GetRouteRightOffset(frame); - this.RiderCountInStartRow = Mathf.Max(2, Mathf.CeilToInt(this.StartRegionRouteWidth / 0.7f)); + this.RiderCountInStartRow = Mathf.Max(1, Mathf.CeilToInt(this.StartRegionRouteWidth / LaneWidth)); } protected override void UpdateGameObjects( @@ -96,9 +96,9 @@ namespace Assets.AR this.CalculateOvertakingParameters(); foreach (ARLaneGameObject collision in this.collisionList) { - collision.LaneWidth = 0.7f; + collision.LaneWidth = LaneWidth; var num6 = this.Route.LeftHanded ? this.GetRouteLeftOffset(collision.Frame) : this.GetRouteRightOffset(collision.Frame); - var num7 = Mathf.Lerp(this.GetStartOffset(collision.StartPosition).x, 0.0f, collision.Distance / 200f); + var num7 = Mathf.Lerp(this.GetStartOffset(collision.StartPosition).x, 0.0f, collision.Distance / StartRegionDistance); collision.BaseOffset = num6 + num7; } this.CalculateCameraAvoidance(cameraDistance); @@ -224,22 +224,19 @@ namespace Assets.AR Vector2 startOffset; if (this.randomizedStartOffsets.TryGetValue(atIndex, out startOffset)) return startOffset; - startOffset = new Vector2(UnityEngine.Random.Range(-0.15f, 0.15f), UnityEngine.Random.Range(-0.4f, 0.4f)); + startOffset = new Vector2(UnityEngine.Random.Range(-StartRowsRandomWidth, StartRowsRandomWidth), UnityEngine.Random.Range(-StartRowsRandomDistance,StartRowsRandomDistance)); this.randomizedStartOffsets.Add(atIndex, startOffset); return startOffset; } public float GetRouteDistance(int startPosition, float routeDistance) { - if (!this.AllowStartOrder || (double)routeDistance >= 200.0) + if (!this.AllowStartOrder || (double)routeDistance >= StartRegionDistance) return routeDistance; - var start = (float)((RiderCountInStartRow == 0 ? 0 : (startPosition - 1) / this.RiderCountInStartRow) * 2.2000000476837158 + 6.0) + this.GetStartOffset(startPosition).y; - var num = Mathf.Lerp(start , 0.0f, routeDistance / 200f); + float num = Mathf.Lerp((float) ((double) ((startPosition - 1) / this.RiderCountInStartRow) * StartRowsGap + 6.0) + this.GetStartOffset(startPosition).y, 0.0f, routeDistance / StartRegionDistance); return routeDistance + num; } - - //计算碰撞距离 protected static float GetCollisionParameter( float distSource, diff --git a/Assets/AR/ARRoute.cs b/Assets/AR/ARRoute.cs index 761e1454..044bdb88 100644 --- a/Assets/AR/ARRoute.cs +++ b/Assets/AR/ARRoute.cs @@ -59,8 +59,6 @@ namespace Assets.AR public int VideoFrameOffset { get; set; } public float CameraHeight { get; set; } - - public float ZOffset { get; set; } public float RiderScale { get; set; } = 1f; @@ -73,10 +71,15 @@ namespace Assets.AR public int FrameCount => this.CameraPositions.Length; public double Lenght => this.FrameDistances[this.FrameCount - 1]; + + public VectorData CameraRotationsOffset { get; set; } + + public float Lane { get; set; } private float DefaultLeftSideOffset => !this.LeftHanded ? 4f : 0.0f; private float DefaultRightSideOffset => !this.LeftHanded ? 0.0f : 4f; + public int GetVisibilityAt(int frame) { @@ -431,17 +434,9 @@ namespace Assets.AR public void LoadData(ARRouteData data) { - // //todo:修改rotation z - // foreach (var rotation in data.CameraRotations) - // { - // rotation.z += 4f; - // } - // - // var str = JsonConvert.SerializeObject(data); this.Visibility = data.Visibility; this.VideoFrameOffset = data.VideoFrameOffset; this.LeftHanded = data.LeftHanded; - this.ZOffset = data.Zoffset; this.SlamSegments = data.SlamSegments; this.CameraHeight = data.CameraHeight; this.RiderScale = (double)data.RiderScale != 0.0 ? data.RiderScale : 1f; @@ -454,6 +449,8 @@ namespace Assets.AR this.LeftSideOffsets = data.LeftSideOffsets; this.RightSideOffsetFrames = data.RightSideOffsetFrames; this.RightSideOffsets = data.RightSideOffsets; + this.CameraRotationsOffset = data.CameraRotationsOffset; + this.Lane = data.Lane; if (data.LightRotationFrames == null || data.LightRotationFrames.Length == 0) { this.LightRotationFrames = new float[0]; diff --git a/Assets/AR/ARRouteData.cs b/Assets/AR/ARRouteData.cs index 84c5bff1..163d72d2 100644 --- a/Assets/AR/ARRouteData.cs +++ b/Assets/AR/ARRouteData.cs @@ -248,11 +248,12 @@ namespace Assets.AR public int VideoFrameOffsetMac = -1; public float CameraHeight; public float RiderScale = 1f; - public float Zoffset = 0f; public int[] LeftSideOffsetFrames; public float[] LeftSideOffsets; public int[] RightSideOffsetFrames; public float[] RightSideOffsets; + public VectorData CameraRotationsOffset; + public float Lane; } public class VectorData { diff --git a/Assets/AR/PlayerRenderer.cs b/Assets/AR/PlayerRenderer.cs index 88c7e738..222dfd30 100644 --- a/Assets/AR/PlayerRenderer.cs +++ b/Assets/AR/PlayerRenderer.cs @@ -91,17 +91,10 @@ namespace Assets.AR } private string LastAnimatorState { get; set; } - protected override void Start() - { - base.Start(); - SetZOffset(); - } - protected override void Update() { if (this.route == null) return; - SetMainRiderLane(); base.Update(); var num = this.Speed; this.Paused = this.Speed == 0; @@ -168,24 +161,6 @@ namespace Assets.AR this.lastVisibilitylevel = this.VisibilityLevel; } - private void SetZOffset() - { - var manager = FindObjectOfType(); - var map = manager.GetMapRoute(); - this.ZOffset = map.Id == 6296 ? -4f : 0f; - } - - private void SetMainRiderLane() - { - if (IsMain) - { - var manager = FindObjectOfType(); - var map = manager.GetMapRoute(); - if(map.Id == 6296)//TODO:这里写死溧阳AR骑行 - Lane = -2f; - } - } - private void FixedUpdate() { //if (this.Paused || (double)this.Speed <= 0.0) diff --git a/Assets/Scripts/App.cs b/Assets/Scripts/App.cs index ba6d800f..f4588105 100644 --- a/Assets/Scripts/App.cs +++ b/Assets/Scripts/App.cs @@ -213,7 +213,8 @@ public static class App { InitLanguage(); #if !UNITY_EDITOR - Host = "http://pf.juze.pro/"; + Host = "http://192.168.0.98:6662/"; + //Host = "http://pf.juze.pro/"; UdpAddress = new IPEndPoint(IPAddress.Parse("47.97.84.8"), 21000); TcpAddress = new IPEndPoint(IPAddress.Parse("47.97.84.8"), 21001); //线上 diff --git a/Assets/Scripts/Scenes/AR/UI/VideoLoading.cs b/Assets/Scripts/Scenes/AR/UI/VideoLoading.cs index 60ef9c13..d0e3c5bb 100644 --- a/Assets/Scripts/Scenes/AR/UI/VideoLoading.cs +++ b/Assets/Scripts/Scenes/AR/UI/VideoLoading.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using UnityEngine; using UnityEngine.UI; using DG.Tweening; @@ -14,13 +13,12 @@ using Assets.Scenes.Ride.Scripts.Model; using Assets.AR; using System.Threading.Tasks; using System.Threading; +using Cysharp.Threading.Tasks; namespace Assets.Scripts.Scenes.VideoRide { - public class VideoLoading : MonoBehaviour, IProgress + public class VideoLoading : MonoBehaviour { - VideoGameManager manager { get; set; } - private Text mapName; private RawImage mapRouteImage; private CanvasGroup canvasGroup; @@ -35,26 +33,27 @@ namespace Assets.Scripts.Scenes.VideoRide private Text slope; private GameObject panel; private GameObject download; - private GameObject watch; - - protected GameObject loadingPanel { get; set; } - + private GameObject watch ; + protected GameObject loadingPanel; private Text level; private Text rideNum; private Text uploadByUserName; private RawImage head; private RawImage country; private RawImage mapCountry; - private RawImage altitudeGraph { get; set; } + private RawImage altitudeGraph; private Transform mapRanking; private Text mapId; - private Text downloadText { get; set; } + private Text downloadText; private Transform ui; - private MapRoute route; - - protected float process = 0;//0-100 % + private VideoGameManager manager { get; set; } + private MapRoute route; + private ARDownloader downloader; + private CancellationTokenSource cancelToken { get; set; } private bool startBtnLock = false; + private bool downloading = false; + private float total = 1f; private void Awake() { @@ -104,31 +103,12 @@ namespace Assets.Scripts.Scenes.VideoRide processText.text = $"{(f).ToString("#0")}%"; }); - download = transform.Find("Panel/Download").gameObject; watch = transform.Find("Panel/Watch").gameObject; UIManager.AddEvent(watch, UnityEngine.EventSystems.EventTriggerType.PointerClick, WatchHandler); canvasGroup = transform.GetComponent(); - - var fileName = route.FileName;// "12067924_720p.mp4"; - var url = route.Url; //@"http://192.168.0.97:6031/12067924_720p.mp4"; - var path = PFConstants.VideoFolder; - var filepath = path + "/" + fileName; - - if (File.Exists(filepath)) - { - watch.SetActive(true); - slider.value = 100; - download.gameObject.SetActive(false); - manager.SetMedia(filepath); - } - else - { - watch.SetActive(false); - //检查本地文件是否存在 如果存在直接设置mediaPlayer 否则显示下载按钮 - UIManager.AddEvent(download.gameObject, UnityEngine.EventSystems.EventTriggerType.PointerClick, DownloadAsync); - } + #region level = panel.transform.Find("level/Text").GetComponent(); rideNum = panel.transform.Find("RideNum").GetComponent(); @@ -177,9 +157,35 @@ namespace Assets.Scripts.Scenes.VideoRide { panel.transform.Find("RideTip").GetComponent().DOFade(0, 0.5f); }); + + UIManager.AddEvent(download.gameObject, EventTriggerType.PointerClick, DownloadAsync); #endregion downloadText = rideNow.GetComponentInChildren();//视频下载进度text + + CheckUpdate(); + } + + private async void CheckUpdate() + { + downloader = new ARDownloader(route); + var showDownload = await downloader.CheckAllAsync(); + var isContinue = App.routeResult != null; + + watch.SetActive(!showDownload && !isContinue); + download.gameObject.SetActive(showDownload); + + if (!showDownload) + { + InitializeVideo(); + } + } + + private void InitializeVideo() + { + var path = PFConstants.VideoFolder + "/" + route.FileName; + slider.value = 100; + manager.SetMedia(path); } protected void InitGameObjectData() @@ -267,18 +273,14 @@ namespace Assets.Scripts.Scenes.VideoRide },false,true); } - private bool downloading = false; - private CancellationTokenSource cancelToken; private async void DownloadAsync(BaseEventData baseEvent) { - if (downloading) - return; - - beforeDownload(); - await startDownloading(); + if (downloading) return; + ResetDownload(); + await StartDownloading(); } - private void beforeDownload() + private void ResetDownload() { downloading = true; download.SetActive(false); @@ -287,45 +289,47 @@ namespace Assets.Scripts.Scenes.VideoRide downloadText.text = "0%"; } - private async Task startDownloading() + private async Task StartDownloading() { - var route = manager.mapRoute; - var path = PFConstants.VideoFolder; + slider.maxValue = downloader.Total * 100; + if(downloader.IsVideoDownloaded) + await downloader.DownLoadVideoAsync(Progress.Create(HandleProgress)); + if(downloader.IsARRouteDownloaded) + await downloader.DownLoadARRouteAsync(Progress.Create(HandleProgress)); + if(downloader.IsARDataDownloaded) + await downloader.DownLoadARDataAsync(Progress.Create(HandleProgress)); - var localPath = PFConstants.ARFolder; - var arDataPath = route.ARConfig; - var videoRoute = route.VideoRoute; - var dataPath = $"{localPath}/{route.Id}"; - - Helper.CreateDirectoryIfNotExsit(dataPath); - Helper.CreateDirectoryIfNotExsit(dataPath); - - cancelToken = new CancellationTokenSource(); - - await Loom.DownloadToFileAsync(arDataPath, $"{dataPath}/{route.Id}.json"); - await Loom.DownloadToFileAsync(videoRoute, $"{dataPath}/route-{route.Id}.json"); - var res = await Loom.DownloadToFileAsync(route.Url, $"{path}/{route.FileName}",this,cancelToken); - if (res.isDone) - { - var filepath = $"{PFConstants.VideoFolder}/{route.FileName}"; - manager.SetMedia(filepath); - - rideNow.enabled = true; - rideNow.interactable = true; - - downloadText.text = App.GetLocalString("Ride Now"); - downloading = false; - } + //cancelToken = new CancellationTokenSource(); + //CompleteDownLoad(); } - public void Report(float value) + private void HandleProgress(float value) { - if (cancelToken.IsCancellationRequested) + if (cancelToken != null && cancelToken.IsCancellationRequested) return; + + slider.value += (float)Math.Round(value * 100, 0); + Debug.Log(value); - slider.value = value < 1 ? (float)Math.Round(value * 100, 0) : 100; - downloadText.text = slider.value.ToString(CultureInfo.InvariantCulture) + "%"; + var progress = slider.value / slider.maxValue * 100; + downloadText.text = progress.ToString(CultureInfo.InvariantCulture) + "%"; + + var isComplete = slider.value == slider.maxValue; + if (isComplete) + CompleteDownLoad(); } + + private void CompleteDownLoad() + { + var filepath = $"{PFConstants.VideoFolder}/{route.FileName}"; + manager.SetMedia(filepath); + watch.GetComponent