795{
796 float now = Time.realtimeSinceStartup;
797 List<WorkshopDownload> queue = (from p in packages
798 where p.item is WorkshopItem workshopItem && (!p.installed || workshopItem.IsNeedsUpdate)
799 select new WorkshopDownload(p, now)).ToList();
800 if (queue.Count == 0)
801 {
802 yield break;
803 }
804 WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
805 Text status = _loading.Log(
$"Downloading {queue.Count} mods...");
806 Dictionary<ulong, EResult> results = new Dictionary<ulong, EResult>();
807 int total = queue.Count;
808 int completed = 0;
809 float lastActivity = now;
810 float nextStatus = 0f;
811 UserGeneratedContent.Client.EventItemDownloaded.AddListener(OnItemDownloaded);
812 try
813 {
814 while (queue.Count > 0)
815 {
816 now = Time.realtimeSinceStartup;
817 for (int num = queue.Count - 1; num >= 0; num--)
818 {
819 WorkshopDownload workshopDownload = queue[num];
820 WorkshopItem
item = workshopDownload.item;
821 ulong publishedFileId =
item.FileId.m_PublishedFileId;
822 string path = null;
823 string reason = null;
824 bool flag = false;
825 EResult value;
826 if (!workshopDownload.package.downloadStarted)
827 {
828 workshopDownload.package.downloadStarted = true;
829 workshopDownload.lastChange = now;
830 if (
item.DownloadItem(highPriority:
true))
831 {
832 Debug.Log(
"Start downloading: " + workshopDownload.Title +
" | " +
$"Installed={item.IsInstalled}, " +
$"Update={item.IsNeedsUpdate}, " +
$"Downloading={item.IsDownloading}, " +
$"Pending={item.IsDownloadPending}");
833 continue;
834 }
835 reason = "cannot start the download";
836 }
837 else if (results.TryGetValue(publishedFileId, out value) && value != EResult.k_EResultOK)
838 {
839 reason =
$"download failed ({value})";
840 }
841 else if (IsItemReady(
item, out path))
842 {
843 flag = true;
844 }
845 else
846 {
847 if (
item.IsDownloadPending)
848 {
849 workshopDownload.lastChange = now;
850 continue;
851 }
852 if (
item.IsDownloading)
853 {
854 float downloadCompletion =
item.DownloadCompletion;
855 if (downloadCompletion > workshopDownload.progress)
856 {
857 workshopDownload.progress = downloadCompletion;
858 float lastChange;
859 lastActivity = (lastChange = now);
860 workshopDownload.lastChange = lastChange;
861 }
862 continue;
863 }
864 if (!(now - workshopDownload.lastChange > 20f))
865 {
866 continue;
867 }
868 reason = "cannot start the download";
869 }
870 queue.RemoveAt(num);
871 lastActivity = now;
872 if (flag)
873 {
874 completed++;
875 InstallWorkshopPackage(workshopDownload, path);
876 }
877 else
878 {
879 FailWorkshopPackage(workshopDownload, reason);
880 }
881 }
882 if (queue.Count == 0)
883 {
884 break;
885 }
886 if (IsCancelRequested())
887 {
888 AbortDownloads(queue, "cancelled");
889 break;
890 }
891 if (now - lastActivity > 90f)
892 {
893 AbortDownloads(queue, "not responding");
894 break;
895 }
896 if (now >= nextStatus)
897 {
898 nextStatus = now + 0.5f;
899 WorkshopDownload workshopDownload2 = queue.Find((WorkshopDownload d) => d.item.IsDownloading) ?? queue[0];
900 SetStatus(status,
$"Downloading mods {completed}/{total}: " +
$"{workshopDownload2.Title} {Mathf.FloorToInt(workshopDownload2.progress * 100f)}%...(Hit ESC to cancel)");
901 }
902 yield return awaiter;
903 }
904 }
905 finally
906 {
907 UserGeneratedContent.Client.EventItemDownloaded.RemoveListener(OnItemDownloaded);
908 }
909 SetStatus(status,
$"Downloaded {completed}/{total} mods");
911 void OnItemDownloaded(DownloadItemResult_t result)
912 {
913 results[result.m_nPublishedFileId.m_PublishedFileId] = result.m_eResult;
914 }
915 }
916
917 public void LoadCachedWorkshopPackages()
918 {
919 HashSet<string> hashSet = packages.Select((
BaseModPackage p) => p.
dirInfo.FullName).ToHashSet(StringComparer.OrdinalIgnoreCase);
920 DirectoryInfo[] directories = dirWorkshop.GetDirectories();
921 foreach (DirectoryInfo directoryInfo in directories)
922 {
923 ulong result;
924 bool flag = ulong.TryParse(directoryInfo.Name, out result);
925 if ((!flag || !_blockedItems.Contains(result)) && (_subscribedItems == null || (flag && _subscribedItems.Contains(result))) && !hashSet.Contains(new DirectoryInfo(directoryInfo.FullName.NormalizePath()).FullName))
926 {
927 ModPackage modPackage = AddPackage(directoryInfo);
928 if (flag)
929 {
930 modPackage.workshopId = directoryInfo.Name;
931 }
932 }
933 }
934 }
935
936 private void InstallWorkshopPackage(WorkshopDownload download, string path)
937 {
939 package.installed = true;
940 package.dirInfo = new DirectoryInfo(path.NormalizePath());
942 {
943 modPackage.Mapping = new FileMapping(package.dirInfo);
944 }
945 Debug.Log(
"Downloaded: " + download.Title +
" -> " + package.dirInfo.FullName);
946 }
947
948 private void FailWorkshopPackage(WorkshopDownload download, string reason)
949 {
950 if (download.isUpdate)
951 {
952 Debug.LogWarning(
"Workshop update failed: " + download.Title +
", " + reason);
953 return;
954 }
955 _missingContent++;
956 Debug.LogWarning(
"Workshop download failed: " + download.Title +
", " + reason);
957 }
958
959 private void AbortDownloads(List<WorkshopDownload> queue, string reason)
960 {
961 foreach (WorkshopDownload
item in queue)
962 {
963 FailWorkshopPackage(
item, reason);
964 }
965 queue.Clear();
966 }
967
968 private static bool IsItemReady(WorkshopItem
item, out
string path)
969 {
970 path = null;
971 if (!
item.IsInstalled ||
item.IsNeedsUpdate ||
item.IsDownloading ||
item.IsDownloadPending)
972 {
973 return false;
974 }
975 if (UserGeneratedContent.Client.GetItemInstallInfo(
item.FileId, out var _, out path, out var _) && !path.IsEmpty())
976 {
977 return Directory.Exists(path);
978 }
979 return false;
980 }
981
982 private static bool IsCancelRequested()
983 {
984 return UnityEngine.Input.GetKey(KeyCode.Escape);
985 }
986
987 private static void SetStatus(Text status, string message)
988 {
989 if ((bool)status)
990 {
991 status.text = message;
992 }
993 }
994
995 public override void ParseExtra(DirectoryInfo dir,
BaseModPackage package)
996 {
998 switch (dir.Name.ToLower())
999 {
1000 case "talktext":
1002 break;
1003 case "map":
1005 {
1007 }
1008 break;
1009 case "map piece":
1011 {
1013 }
1014 break;
1015 case "texture replace":
1017 break;
1018 case "texture":
1020 break;
1021 case "portrait":
1023 break;
1024 case "langmod":
1026 break;
1027 case "sound":
1029 break;
1030 case "lang":
1032 break;
1033 }
1034 }
1035}
IReadOnlyList< FileInfo > ParseTalkText(DirectoryInfo dir)
void ParseLangMod(DirectoryInfo dir)
IReadOnlyList< FileInfo > ParseTexture(DirectoryInfo dir)
void AddOrUpdateLang(DirectoryInfo dir)
IReadOnlyList< FileInfo > ParseMapPiece(DirectoryInfo dir, bool addToList=true)
IReadOnlyList< FileInfo > ParseTextureReplace(DirectoryInfo dir)
IReadOnlyList< FileInfo > ParsePortrait(DirectoryInfo dir)
IReadOnlyList< FileInfo > ParseMap(DirectoryInfo dir, bool addToList=true)
IReadOnlyList< FileInfo > ParseSound(DirectoryInfo dir)