using System; using System.Collections; using System.Collections.Generic; using System.IO; using Newtonsoft.Json; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; public class ModList : MonoBehaviour { [SerializeField] private string JSONPath; [SerializeField] private DownloadMod DM; [SerializeField] private OnlineAccountHandler OAH; private List modList = new(); [Header("\tMod Prefabs")] [SerializeField] private GameObject ModPrefab; [SerializeField] private Transform ModPrefabContainer; [SerializeField] public List ModPrefabList; [SerializeField] private TMP_InputField SearchText; public bool AZOrder = true; public bool DateOrder = true; // Start is called before the first frame update public void StartList() { foreach (GameObject prefab in ModPrefabList) { DestroyImmediate(prefab); } ModPrefabList.Clear(); JSONPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)+@"\Schaken-ModsĀ®\Singularity\Mods\"; if (!Directory.Exists(JSONPath)) { Directory.CreateDirectory(JSONPath); } string[] jsonFiles2 = Directory.GetFiles(JSONPath, "*.json");// Update from 1.1 to 1.11 foreach (string WrongFile in jsonFiles2) { string newFilePath = Path.ChangeExtension(WrongFile, ".sing"); if (File.Exists(newFilePath)) { File.Delete(newFilePath); } File.Move(WrongFile, newFilePath); // Rename the file } string[] jsonFiles = Directory.GetFiles(JSONPath, "*.sing"); foreach (string jsonFile in jsonFiles) { if (Path.GetFileName(jsonFile) == "0.sing" || Path.GetFileName(jsonFile) == "NM0.sing") { File.Delete(jsonFile); } else { try { string jsonContent = File.ReadAllText(jsonFile); jsonContent = "{ \"download\": " + jsonContent + " }"; SchakenMods mod = JsonConvert.DeserializeObject(jsonContent); modList.Add(mod); } catch (JsonReaderException ex) { Debug.LogError($"Error deserializing JSON from file {jsonFile}: {ex.Message}"); DM.Con.Alert("Schaken-Mods", $"Error deserializing JSON from file {jsonFile}: {ex.Message}"); Debug.LogError($"Content of {jsonFile}: {File.ReadAllText(jsonFile)}"); } } } for (int i = 0; i < modList.Count; i++) { AddMod(modList[i]); } ResetOrder(); } public void ResetOrder() { if (AZOrder) { OrderAZ(); OAH.Setting.ModListOrder = 0; OAH.SaveSettings(); return; } if (DateOrder) { OrderDate(); OAH.Setting.ModListOrder = 1; OAH.SaveSettings(); return; } } public ModListPrefab AddMod(SchakenMods modJSON) { bool found = false; ModListPrefab MasterPrefab = new(); for (int i = 0; i < ModPrefabList.Count; i++) { SchakenMods.Download TempMod = ModPrefabList[i].GetComponent().Mod.Mod; if ((TempMod.Id == modJSON.Mod.Id) && (TempMod.ModAuthor.Name == modJSON.Mod.ModAuthor.Name)) { found = true; MasterPrefab = ModPrefabList[i].GetComponent(); } } if (found == false) { GameObject NewMod = Instantiate(ModPrefab, ModPrefabContainer); ModPrefabList.Add(NewMod); NewMod.name = modJSON.Mod.Title; string Website = modJSON.Mod.Url; if (modJSON.Mod.Url.Contains("/schaken-mods.com")) { Website = "Schaken-Mods"; } else if (modJSON.Mod.Url.Contains("/www.nexusmods.com/")) { Website = "NexusMods"; } RawImage A = NewMod.GetComponent().FillMe(Website, modJSON, DM); if (Website == "Schaken-Mods") { if (modJSON.Mod.PrimaryScreenshotThumb != null) { if (modJSON.Mod.PrimaryScreenshotThumb.Url != null) { StartCoroutine(DownloadImage(modJSON.Mod.PrimaryScreenshotThumb.Url, A)); } else { Debug.LogError($"{modJSON.Mod.Id} is missing its PrimaryScreenshot"); } } else { Debug.LogError($"{modJSON.Mod.Id} is missing its PrimaryScreenshot"); } } else if (Website == "NexusMods") { StartCoroutine(LoadWebP(modJSON.Mod.PrimaryScreenshotThumb.Url, A)); } return NewMod.GetComponent(); } else { return MasterPrefab; } } public void CheckAllForUpdates() { for (int i = 0; i < ModPrefabList.Count; i++) { ModListPrefab TempML = ModPrefabList[i].GetComponent(); SchakenMods TempSM = ModPrefabList[i].GetComponent().Mod; TempML.Spin(); StartCoroutine(CheckForModUpdatesA(TempSM, TempML)); } } public void CheckForModUpdates(SchakenMods SM, ModListPrefab MLPrefab) { StartCoroutine(CheckForModUpdatesA(SM, MLPrefab)); } IEnumerator CheckForModUpdatesA(SchakenMods SM, ModListPrefab MLPrefab) { bool UpToDate = true; if (SM.Mod.Url.ToLower().Contains("schaken-mods.com")) { using (UnityWebRequest uwr = UnityWebRequest.Get($"https://schaken-mods.com/api/downloads/files/{SM.Mod.Id}")) { uwr.SetRequestHeader("Authorization", "Bearer " + DM.OAH.BearerID); yield return uwr.SendWebRequest(); if (uwr.result == UnityWebRequest.Result.ConnectionError) { Debug.LogError("Error While Sending TEST: " + uwr.error); DM.Con.Alert("Schaken-Mods", $"Error While Sending: {uwr.error}"); } else { SchakenMods.Download mod = JsonConvert.DeserializeObject(uwr.downloadHandler.text); if (SM.Mod.Downloaded < mod.Updated) { UpToDate = false; } } } } else if (SM.Mod.Url.ToLower().Contains("nexusmods.com")) { using (UnityWebRequest uwr = UnityWebRequest.Get($"https://api.nexusmods.com/v1/games/{SM.Mod.ModCategory.Name}/mods/{SM.Mod.Id}.sing")) { uwr.SetRequestHeader("Content-Type", "application/json"); uwr.SetRequestHeader("apikey", DM.OAH.NMKey); yield return uwr.SendWebRequest(); if (uwr.result == UnityWebRequest.Result.ConnectionError) { Debug.LogError("Error While Sending TEST: " + uwr.error); DM.Con.Alert("NexusMods", $"Error While Sending: {uwr.error}"); } else { // Debug.Log($"Full Report of ({SM.Mod.Id}): {uwr.downloadHandler.text}"); if (uwr.downloadHandler.text.Contains("\"status\":\"wastebinned\"")) { Debug.LogError($"Mod at {SM.Mod.Id} was removed by Author"); DM.Con.Alert("NexusMods", $"Mod at {SM.Mod.Id} was removed by Author"); yield break; } else if (uwr.downloadHandler.text.Contains("\"status\":\"hidden\"")) { Debug.LogError($"Mod at {SM.Mod.Id} was hidden by Author"); DM.Con.Alert("NexusMods", $"Mod at {SM.Mod.Id} was hidden."); yield break; } else { NexusMods.Mod JSON = JsonConvert.DeserializeObject(uwr.downloadHandler.text); if (SM.Mod.Downloaded < JSON.UpdatedTime) { UpToDate = false; } } } } } // if (!UpToDate) { MLPrefab.OutOfDate(UpToDate); // } MLPrefab.Spin(); } IEnumerator DownloadImage(string imageUrl, RawImage A, int maxRetries = 3) { int retryCount = 0; while (retryCount < maxRetries) { using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(imageUrl)) { yield return www.SendWebRequest(); if (www.result != UnityWebRequest.Result.ConnectionError) { A.texture = DownloadHandlerTexture.GetContent(www); A.SetNativeSize(); A.SizeToParent(); retryCount = 99; yield break; // Exit the coroutine if the download is successful } else { Debug.LogError("Error downloading image: " + www.error, A.gameObject); retryCount++; if (retryCount < maxRetries) { yield return new WaitForSeconds(1f); // Wait for 1 second before retrying } } } } Debug.LogError("Failed to download image after " + maxRetries + " attempts."); A.gameObject.GetComponent().FailedImage.SetActive(true); } private IEnumerator LoadWebP(string url, RawImage rawImage, int maxRetries = 3) { int retryCount = 0; while (retryCount < maxRetries) { using (UnityWebRequest www = UnityWebRequest.Get(url)) { yield return www.SendWebRequest(); if (www.result != UnityWebRequest.Result.Success) { Debug.LogError($"Error downloading image ({url}): {www.error}"); retryCount++; if (retryCount < maxRetries) { yield return new WaitForSeconds(1f); // Wait for 1 second before retrying } } else { byte[] webPData = www.downloadHandler.data; if (webPData == null || webPData.Length == 0) { Debug.LogError("No WebP data received."); yield break; } WebpImporter.ByteWebpTexture2D(webPData, (texture) => { rawImage.texture = texture; }); rawImage.SetNativeSize(); rawImage.SizeToParent(); retryCount = 99; yield break; // Exit the coroutine if the download is successful } } } Debug.LogError("Failed to download image after " + maxRetries + " attempts."); } public void ShowSites(int A) { if (A == 0) { // ALL for (int i = 0; i < ModPrefabList.Count; i++) { ModPrefabList[i].SetActive(true); } } else if (A == 1) { // Schaken-Mods for (int i = 0; i < ModPrefabList.Count; i++) { ModPrefabList[i].SetActive(ModPrefabList[i].GetComponent().Website.text.Contains("Schaken")); } } else if (A == 2) { // NexusMods for (int i = 0; i < ModPrefabList.Count; i++) { ModPrefabList[i].SetActive(ModPrefabList[i].GetComponent().Website.text.Contains("Nexus")); } } } public void OrderAZ() { ModPrefabList.Sort((a, b) => { string A = a.name; string B = b.name; return string.Compare(A, B); }); ReOrder(ModPrefabList, AZOrder); AZOrder = !AZOrder; DateOrder = true; OAH.Setting.ModListOrder = 0; OAH.SaveSettings(); } public void OrderDate() { ModPrefabList.Sort((a, b) => { ModListPrefab modInfoA = a.GetComponent(); ModListPrefab modInfoB = b.GetComponent(); // Extract the date part of the string string dateStringA = modInfoA.Downloaded.text.Split(S("Downloaded:"))[1].Trim(); string dateStringB = modInfoB.Downloaded.text.Split(S("Downloaded:"))[1].Trim(); // Parse the string into DateTime objects DateTime dateA = DateTime.Parse(dateStringA); DateTime dateB = DateTime.Parse(dateStringB); // Compare the DateTime objects return DateTime.Compare(dateB, dateA); // Sort from newest to oldest }); ReOrder(ModPrefabList, DateOrder); DateOrder = !DateOrder; AZOrder = true; OAH.Setting.ModListOrder = 1; OAH.SaveSettings(); } public void Search() { StartCoroutine(SearchA()); } IEnumerator SearchA() { string SavedText = SearchText.text; SearchText.text = "Searching....."; yield return new WaitForSeconds(0.1f); for (int i = 0; i < ModPrefabList.Count; i++) { ModPrefabList[i].SetActive(ModPrefabList[i].name.ToLower().Contains(SavedText.ToLower())); } SearchText.text = SavedText; } public void CloseSearch() { for (int i = 0; i < ModPrefabList.Count; i++) { ModPrefabList[i].SetActive(true); } SearchText.text = ""; } private string S(string A) { return A; } private void ReOrder(List list, bool order = true) { if (order) { for (int i = 0; i < list.Count; i++) { list[i].transform.SetSiblingIndex(i); } } else { list[0].transform.SetSiblingIndex(list.Count - 1); for (int i = 0; i < list.Count; i++) { list[i].transform.SetSiblingIndex(list.Count-i-1); } } } }