From 911fe9d918da9fbb88fd27af809e9fb65dc2342d Mon Sep 17 00:00:00 2001 From: gmBlahaj Date: Tue, 13 Oct 2026 17:48:59 +0200 Subject: [PATCH 1/6] Tags now get saved in mods.json yay --- api/ModDeclare.cs | 14 ++++++++---- resources/commit | 2 +- services/ModWorkshopServiceUnix.cs | 2 +- services/ModWorkshopServiceWindows.cs | 2 +- ui/ModUploadWindow.cs | 31 +++++++++++++++++++++++++-- 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/api/ModDeclare.cs b/api/ModDeclare.cs index b4ecfab..89aecf7 100644 --- a/api/ModDeclare.cs +++ b/api/ModDeclare.cs @@ -127,6 +127,7 @@ public ModDeclare(string pFilePath) AICheckTranslation = modDeclare.AICheckTranslation; AICheckAudio = modDeclare.AICheckAudio; Tags = modDeclare.Tags ?? new List(); + SteamId = modDeclare.SteamId; Dependencies ??= Array.Empty(); OptionalDependencies ??= Array.Empty(); @@ -154,6 +155,10 @@ public ModDeclare(string pFilePath) Regex regex = new(@"^\d+$"); if (!regex.IsMatch(pathSegments[++currentSearchIndex])) return; IsWorkshopLoaded = true; + if (SteamId == 0 && ulong.TryParse(pathSegments[currentSearchIndex], out ulong parsedId)) + { + SteamId = parsedId; + } } /// @@ -345,6 +350,9 @@ public string GetAIAttributionDisplay() }; } + [JsonProperty("steam_id")] + public ulong SteamId { get; internal set; } + private List _tags = new(); [JsonProperty("tags")] @@ -375,11 +383,9 @@ public void Save() { try { + if (string.IsNullOrEmpty(FolderPath) || !Directory.Exists(FolderPath)) return; string jsonPath = Path.Combine(FolderPath, "mod.json"); - if (File.Exists(jsonPath)) - { - File.WriteAllText(jsonPath, JsonConvert.SerializeObject(this, Formatting.Indented)); - } + File.WriteAllText(jsonPath, JsonConvert.SerializeObject(this, Formatting.Indented)); } catch (Exception e) { diff --git a/resources/commit b/resources/commit index e38f0b0..6753a3c 100644 --- a/resources/commit +++ b/resources/commit @@ -1 +1 @@ -4bb2ea1fa3af3aa45c8ebb7aefcf096a5bc3b2f0 +53569134f16dce4804655b3c1edf696475f06dd5 diff --git a/services/ModWorkshopServiceUnix.cs b/services/ModWorkshopServiceUnix.cs index 01e3f16..df0e230 100644 --- a/services/ModWorkshopServiceUnix.cs +++ b/services/ModWorkshopServiceUnix.cs @@ -177,7 +177,7 @@ public Promise EditMod(ulong fileID, string previewImagePath, string workshopPat return; } - // result.FileId; + ModUploadingProgressWindow.Instance.fileId = fileID; promise.Resolve(); }, TaskScheduler.FromCurrentSynchronizationContext()); return promise; diff --git a/services/ModWorkshopServiceWindows.cs b/services/ModWorkshopServiceWindows.cs index bb8e119..7a82c58 100644 --- a/services/ModWorkshopServiceWindows.cs +++ b/services/ModWorkshopServiceWindows.cs @@ -177,7 +177,7 @@ public Promise EditMod(ulong fileID, string previewImagePath, string workshopPat return; } - // result.FileId; + ModUploadingProgressWindow.Instance.fileId = fileID; promise.Resolve(); }, TaskScheduler.FromCurrentSynchronizationContext()); return promise; diff --git a/ui/ModUploadWindow.cs b/ui/ModUploadWindow.cs index 6b8363a..d2dc508 100644 --- a/ui/ModUploadWindow.cs +++ b/ui/ModUploadWindow.cs @@ -41,6 +41,15 @@ public static void ShowWindow(IMod mod) Instance.mod_version_text.text = mod_decl.Version; Instance.mod_description_text.text = mod_decl.Description; + if (mod_decl.SteamId > 0) + { + Instance.mod_fileid_text.text = mod_decl.SteamId.ToString(); + } + else + { + Instance.mod_fileid_text.text = ""; + } + Instance.updateTagButtonsUI(); ScrollWindow.showWindow(WindowId); @@ -319,14 +328,32 @@ private void executeUpload() { ModUploadAuthenticationService.Authenticate().Then( () => ModWorkshopService.UploadMod(selected_mod, changelog_text.text, - ModUploadAuthenticationService.Authed)).Then(ModUploadingProgressWindow.FinishUpload, + ModUploadAuthenticationService.Authed)).Then(() => + { + if (selected_mod != null && ModUploadingProgressWindow.Instance.fileId > 0) + { + var decl = selected_mod.GetDeclaration(); + decl.SteamId = ModUploadingProgressWindow.Instance.fileId; + decl.Save(); + } + ModUploadingProgressWindow.FinishUpload(); + }, ModUploadingProgressWindow.ErrorUpload); return; } ulong fileIdLong = ulong.Parse(fileId); ModWorkshopService.TryEditMod(fileIdLong, selected_mod, changelog_text.text) - .Then(ModUploadingProgressWindow.FinishUpload, ModUploadingProgressWindow.ErrorUpload).Done(); + .Then(() => + { + if (selected_mod != null) + { + var decl = selected_mod.GetDeclaration(); + decl.SteamId = fileIdLong; + decl.Save(); + } + ModUploadingProgressWindow.FinishUpload(); + }, ModUploadingProgressWindow.ErrorUpload).Done(); } private void updateTagButtonsUI() From 348c9d218f20671d44da7afef5e1f593cf05a08c Mon Sep 17 00:00:00 2001 From: gmBlahaj Date: Tue, 13 Oct 2026 21:36:32 +0200 Subject: [PATCH 2/6] Added new update system thats less weird than the one before --- resources/commit | 2 +- resources/locales/ch.json | 4 + resources/locales/cz.json | 4 + resources/locales/en.json | 4 + .../IPlatformSpecificModWorkshopService.cs | 3 +- services/ModWorkshopService.cs | 47 ++- services/ModWorkshopServiceUnix.cs | 109 ++++--- services/ModWorkshopServiceWindows.cs | 109 ++++--- ui/AIConfirmWindow.cs | 25 +- ui/AIDisclosureWindow.cs | 3 +- ui/ModListWindow.cs | 2 +- ui/ModUploadModeWindow.cs | 304 ++++++++++++++++++ ui/ModUploadWindow.cs | 123 +++++-- ui/UIManager.cs | 1 + utils/ModInfoUtils.cs | 18 +- 15 files changed, 628 insertions(+), 130 deletions(-) create mode 100644 ui/ModUploadModeWindow.cs diff --git a/resources/commit b/resources/commit index 6753a3c..4aae344 100644 --- a/resources/commit +++ b/resources/commit @@ -1 +1 @@ -53569134f16dce4804655b3c1edf696475f06dd5 +911fe9d918da9fbb88fd27af809e9fb65dc2342d diff --git a/resources/locales/ch.json b/resources/locales/ch.json index 3278ef7..6dbf279 100644 --- a/resources/locales/ch.json +++ b/resources/locales/ch.json @@ -6,6 +6,10 @@ "NeoModLoader Update Title": "NeoModLoader 更新", "NeoModLoader Update Complete": "NeoModLoader 更新至{0},\n 重啟遊戲以應用更新。", "ModUpload Title": "上傳模組", + "ModUpdate Title": "更新模組", + "ModUploadModeWindow Title": "Steam 創意工坊", + "Clear Steam ID": "清除 Steam ID", + "Clear Steam ID Confirm": "確定要清除綁定的創意工坊 ID 嗎?", "ModUpload_Categories_Title": "分類標籤 (點擊切換):", "Information Title": "提示", "AIConfirmWindow Title": "AI 內容免責聲明", diff --git a/resources/locales/cz.json b/resources/locales/cz.json index 1b82704..4155f4c 100644 --- a/resources/locales/cz.json +++ b/resources/locales/cz.json @@ -6,6 +6,10 @@ "NeoModLoader Update Title": "NeoModLoader 更新", "NeoModLoader Update Complete": "NeoModLoader 更新至{0},\n 重启游戏以应用更新。", "ModUpload Title": "上传模组", + "ModUpdate Title": "更新模组", + "ModUploadModeWindow Title": "Steam 创意工坊", + "Clear Steam ID": "清除 Steam ID", + "Clear Steam ID Confirm": "确定要清除绑定的创意工坊 ID 吗?", "ModUpload_Categories_Title": "分类标签 (点击切换):", "Information Title": "信息", "AIConfirmWindow Title": "AI 内容免责声明", diff --git a/resources/locales/en.json b/resources/locales/en.json index f4a866b..dcec291 100644 --- a/resources/locales/en.json +++ b/resources/locales/en.json @@ -6,6 +6,10 @@ "NeoModLoader Update Title": "NeoModLoader Update", "NeoModLoader Update Complete": "NeoModLoader has been updated to version {0}.\nPlease restart the game to apply the update.", "ModUpload Title": "Upload Mod", + "ModUpdate Title": "Update Mod", + "ModUploadModeWindow Title": "Steam Workshop", + "Clear Steam ID": "Clear Steam ID", + "Clear Steam ID Confirm": "Are you sure you want to clear the associated Steam Workshop ID?", "ModUpload_Categories_Title": "Category Tags (Click to toggle):", "Information Title": "Information", "AIConfirmWindow Title": "AI Content Disclaimer", diff --git a/services/IPlatformSpecificModWorkshopService.cs b/services/IPlatformSpecificModWorkshopService.cs index b3b05ed..54186f0 100644 --- a/services/IPlatformSpecificModWorkshopService.cs +++ b/services/IPlatformSpecificModWorkshopService.cs @@ -10,8 +10,7 @@ internal interface IPlatformSpecificModWorkshopService Promise UploadMod(string name, string description, string previewImagePath, string workshopPath, string changelog, bool verified, string aiTag = null, List extraTags = null); - Promise EditMod(ulong fileID, string previewImagePath, string workshopPath, string changelog, - string aiTag = null, List extraTags = null); + Promise EditMod(ulong fileID, string previewImagePath, string workshopPath, string changelog, ModDeclare mod_decl); void FindSubscribedMods(); ModDeclare GetNextModFromWorkshopItem(); } \ No newline at end of file diff --git a/services/ModWorkshopService.cs b/services/ModWorkshopService.cs index 04df0be..a0b4998 100644 --- a/services/ModWorkshopService.cs +++ b/services/ModWorkshopService.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Reflection; +using System.Text.RegularExpressions; using NeoModLoader.api; using NeoModLoader.api.attributes; using NeoModLoader.constants; @@ -38,10 +39,10 @@ private static void UploadModLoader(string changelog) /// /// Try to Upload a mod to Steam Workshop /// - public static Promise UploadMod(IMod mod, string changelog, bool verified = false) + public static Promise UploadMod(IMod mod, string changelog, bool verified = false, string uploadName = null) { ModDeclare mod_decl = mod.GetDeclaration(); - string name = mod_decl.Name; + string name = string.IsNullOrEmpty(uploadName) ? mod_decl.Name : uploadName; string description = BuildModDescription(mod_decl); string workshopPath = Path.Combine(SaveManager.generateMainPath("workshop_upload_mod") + mod_decl.UID); @@ -50,7 +51,6 @@ public static Promise UploadMod(IMod mod, string changelog, bool verified = fals string previewImagePath = PreparePreviewImage(mod_decl, workshopPath); - // This works for BepInEx mods File.WriteAllText(Path.Combine(workshopPath, "mod.json"), JsonConvert.SerializeObject(mod_decl, Formatting.Indented)); return workshopServiceBackend.UploadMod(name, description, previewImagePath, workshopPath, changelog, verified, mod_decl.GetAIAttributionDisplay(), mod_decl.Tags); @@ -68,10 +68,42 @@ public static Promise TryEditMod(ulong fileID, IMod mod, string changelog) File.WriteAllText(Path.Combine(workshopPath, "mod.json"), JsonConvert.SerializeObject(mod_decl, Formatting.Indented)); - return workshopServiceBackend.EditMod(fileID, previewImagePath, workshopPath, changelog, mod_decl.GetAIAttributionDisplay(), mod_decl.Tags); + return workshopServiceBackend.EditMod(fileID, previewImagePath, workshopPath, changelog, mod_decl); + } + + public static string UpdateDescriptionDisclaimer(string steamDescription, ModDeclare mod_decl) + { + string newDisclaimer = BuildAIDisclaimer(mod_decl); + if (string.IsNullOrEmpty(steamDescription)) + { + return BuildModDescription(mod_decl); + } + + string pattern = @"\[hr\]\[\/hr\](?:(?!\[hr\]\[\/hr\])[\s\S])*?(?:AI Content Disclosure|Authorship:|generative AI|AI Content)[\s\S]*?\[hr\]\[\/hr\]"; + if (Regex.IsMatch(steamDescription, pattern, RegexOptions.IgnoreCase)) + { + return Regex.Replace(steamDescription, pattern, newDisclaimer, RegexOptions.IgnoreCase); + } + + string partialPattern = @"(?:\[hr\]\[\/hr\]\s*)?(?:\[b\])?(?:AI Content Disclosure|Authorship:)[\s\S]*?(?:\[hr\]\[\/hr\]|(?=(?:ModLoader:|模组加载器:|\z)))"; + if (Regex.IsMatch(steamDescription, partialPattern, RegexOptions.IgnoreCase)) + { + return Regex.Replace(steamDescription, partialPattern, newDisclaimer, RegexOptions.IgnoreCase); + } + + string footerPattern = @"(?:\r?\n)+(?:ModLoader:\s*https?:\S+|模组加载器:\s*https?:\S+)[\s\S]*$"; + Match footerMatch = Regex.Match(steamDescription, footerPattern, RegexOptions.IgnoreCase); + if (footerMatch.Success) + { + string beforeFooter = steamDescription.Substring(0, footerMatch.Index).TrimEnd(); + string footer = steamDescription.Substring(footerMatch.Index).TrimStart(); + return beforeFooter + "\n\n" + newDisclaimer + "\n\n" + footer; + } + + return steamDescription.TrimEnd() + "\n\n" + newDisclaimer; } - private static string BuildModDescription(ModDeclare mod_decl) + public static string BuildModDescription(ModDeclare mod_decl) { string name = mod_decl.Name; string aiDisclaimer = BuildAIDisclaimer(mod_decl); @@ -84,7 +116,7 @@ private static string BuildModDescription(ModDeclare mod_decl) $"模组加载器: {CoreConstants.RepoURL}"; } - private static string BuildAIDisclaimer(ModDeclare mod_decl) + public static string BuildAIDisclaimer(ModDeclare mod_decl) { if (mod_decl.AIAttribution == "ai_made" || mod_decl.AIAttribution == "ai_assisted") { @@ -144,7 +176,8 @@ private static void CopyModFiles(string sourceFolder, string targetFolder) private static string PreparePreviewImage(ModDeclare mod_decl, string workshopPath) { string previewImagePath; - if (string.IsNullOrEmpty(mod_decl.IconPath)) + if (string.IsNullOrEmpty(mod_decl.IconPath) || + !File.Exists(Path.Combine(mod_decl.FolderPath, mod_decl.IconPath))) { using Stream icon_stream = Assembly.GetExecutingAssembly() .GetManifestResourceStream("NeoModLoader.resources.logo.png"); diff --git a/services/ModWorkshopServiceUnix.cs b/services/ModWorkshopServiceUnix.cs index df0e230..6966103 100644 --- a/services/ModWorkshopServiceUnix.cs +++ b/services/ModWorkshopServiceUnix.cs @@ -128,59 +128,92 @@ public Promise UploadMod(string name, string description, string previewImagePat return promise; } - public Promise EditMod(ulong fileID, string previewImagePath, string workshopPath, string changelog, - string aiTag = null, List extraTags = null) + public Promise EditMod(ulong fileID, string previewImagePath, string workshopPath, string changelog, ModDeclare mod_decl) { Promise promise = new(); - // Create Upload Files Descriptor - Editor editor = new Editor(fileID) - .WithPreviewFile(previewImagePath) - .WithContent(workshopPath).WithChangeLog(changelog) - .WithTag("Mod"); + var progress = ModUploadingProgressWindow.ShowWindow(); + ExecuteEditMod(fileID, previewImagePath, workshopPath, changelog, mod_decl, promise, progress); + return promise; + } - if (!string.IsNullOrEmpty(aiTag)) - { - editor = editor.WithTag(aiTag); - } - if (extraTags != null) + private async void ExecuteEditMod(ulong fileID, string previewImagePath, string workshopPath, string changelog, + ModDeclare mod_decl, Promise promise, ModUploadingProgressWindow.UploadProgress progress) + { + try { - foreach (string tag in extraTags) + string desc = null; + try { - if (!string.IsNullOrEmpty(tag)) + Query q = Query.Items.WithFileId(fileID).WithLongDescription(true); + ResultPage? resultPage = await q.GetPageAsync(1); + if (resultPage.HasValue) { - editor = editor.WithTag(tag); + foreach (var entry in resultPage.Value.Entries) + { + if (!string.IsNullOrEmpty(entry.Description)) + { + desc = ModWorkshopService.UpdateDescriptionDisclaimer(entry.Description, mod_decl); + break; + } + } } } - } + catch (Exception e) + { + LogService.LogWarning($"Failed to get existing description: {e.Message}"); + } - editor.SubmitAsync(ModUploadingProgressWindow.ShowWindow()).ContinueWith( - delegate(Task taskResult) + if (string.IsNullOrEmpty(desc)) { - if (taskResult.Status != TaskStatus.RanToCompletion) - { - promise.Reject(taskResult.Exception.GetBaseException()); - return; - } + desc = ModWorkshopService.BuildModDescription(mod_decl); + } - PublishResult result = taskResult.Result; - // Result process refer to: https://partner.steamgames.com/doc/api/steam_api#EResult - if (result.NeedsWorkshopAgreement) - { - LogService.LogWarning("Needs Workshop Agreement"); - // TODO: Open Workshop Agreement - Application.OpenURL("steam://url/CommunityFilePage/" + result.FileId); - } + Editor editor = new Editor(fileID) + .WithPreviewFile(previewImagePath) + .WithContent(workshopPath) + .WithChangeLog(changelog) + .WithTag("Mod"); - if (result.Result != Result.OK) + if (!string.IsNullOrEmpty(desc)) + { + editor = editor.WithDescription(desc); + } + + string aiTag = mod_decl.GetAIAttributionDisplay(); + if (!string.IsNullOrEmpty(aiTag)) + { + editor = editor.WithTag(aiTag); + } + if (mod_decl.Tags != null) + { + foreach (string tag in mod_decl.Tags) { - promise.Reject(new Exception(result.Result.ToString())); - return; + if (!string.IsNullOrEmpty(tag)) + { + editor = editor.WithTag(tag); + } } + } - ModUploadingProgressWindow.Instance.fileId = fileID; - promise.Resolve(); - }, TaskScheduler.FromCurrentSynchronizationContext()); - return promise; + PublishResult result = await editor.SubmitAsync(progress); + if (result.NeedsWorkshopAgreement) + { + Application.OpenURL("steam://url/CommunityFilePage/" + result.FileId); + } + + if (result.Result != Result.OK) + { + promise.Reject(new Exception(result.Result.ToString())); + return; + } + + ModUploadingProgressWindow.Instance.fileId = fileID; + promise.Resolve(); + } + catch (Exception ex) + { + promise.Reject(ex); + } } public async void FindSubscribedMods() diff --git a/services/ModWorkshopServiceWindows.cs b/services/ModWorkshopServiceWindows.cs index 7a82c58..8c3aeee 100644 --- a/services/ModWorkshopServiceWindows.cs +++ b/services/ModWorkshopServiceWindows.cs @@ -128,59 +128,92 @@ public Promise UploadMod(string name, string description, string previewImagePat return promise; } - public Promise EditMod(ulong fileID, string previewImagePath, string workshopPath, string changelog, - string aiTag = null, List extraTags = null) + public Promise EditMod(ulong fileID, string previewImagePath, string workshopPath, string changelog, ModDeclare mod_decl) { Promise promise = new(); - // Create Upload Files Descriptor - Editor editor = new Editor(fileID) - .WithPreviewFile(previewImagePath) - .WithContent(workshopPath).WithChangeLog(changelog) - .WithTag("Mod"); + var progress = ModUploadingProgressWindow.ShowWindow(); + ExecuteEditMod(fileID, previewImagePath, workshopPath, changelog, mod_decl, promise, progress); + return promise; + } - if (!string.IsNullOrEmpty(aiTag)) - { - editor = editor.WithTag(aiTag); - } - if (extraTags != null) + private async void ExecuteEditMod(ulong fileID, string previewImagePath, string workshopPath, string changelog, + ModDeclare mod_decl, Promise promise, ModUploadingProgressWindow.UploadProgress progress) + { + try { - foreach (string tag in extraTags) + string desc = null; + try { - if (!string.IsNullOrEmpty(tag)) + Query q = Query.Items.WithFileId(fileID).WithLongDescription(true); + ResultPage? resultPage = await q.GetPageAsync(1); + if (resultPage.HasValue) { - editor = editor.WithTag(tag); + foreach (var entry in resultPage.Value.Entries) + { + if (!string.IsNullOrEmpty(entry.Description)) + { + desc = ModWorkshopService.UpdateDescriptionDisclaimer(entry.Description, mod_decl); + break; + } + } } } - } + catch (Exception e) + { + LogService.LogWarning($"Failed to get existing description: {e.Message}"); + } - editor.SubmitAsync(ModUploadingProgressWindow.ShowWindow()).ContinueWith( - delegate(Task taskResult) + if (string.IsNullOrEmpty(desc)) { - if (taskResult.Status != TaskStatus.RanToCompletion) - { - promise.Reject(taskResult.Exception.GetBaseException()); - return; - } + desc = ModWorkshopService.BuildModDescription(mod_decl); + } - PublishResult result = taskResult.Result; - // Result process refer to: https://partner.steamgames.com/doc/api/steam_api#EResult - if (result.NeedsWorkshopAgreement) - { - LogService.LogWarning("Needs Workshop Agreement"); - // TODO: Open Workshop Agreement - Application.OpenURL("steam://url/CommunityFilePage/" + result.FileId); - } + Editor editor = new Editor(fileID) + .WithPreviewFile(previewImagePath) + .WithContent(workshopPath) + .WithChangeLog(changelog) + .WithTag("Mod"); - if (result.Result != Result.OK) + if (!string.IsNullOrEmpty(desc)) + { + editor = editor.WithDescription(desc); + } + + string aiTag = mod_decl.GetAIAttributionDisplay(); + if (!string.IsNullOrEmpty(aiTag)) + { + editor = editor.WithTag(aiTag); + } + if (mod_decl.Tags != null) + { + foreach (string tag in mod_decl.Tags) { - promise.Reject(new Exception(result.Result.ToString())); - return; + if (!string.IsNullOrEmpty(tag)) + { + editor = editor.WithTag(tag); + } } + } - ModUploadingProgressWindow.Instance.fileId = fileID; - promise.Resolve(); - }, TaskScheduler.FromCurrentSynchronizationContext()); - return promise; + PublishResult result = await editor.SubmitAsync(progress); + if (result.NeedsWorkshopAgreement) + { + Application.OpenURL("steam://url/CommunityFilePage/" + result.FileId); + } + + if (result.Result != Result.OK) + { + promise.Reject(new Exception(result.Result.ToString())); + return; + } + + ModUploadingProgressWindow.Instance.fileId = fileID; + promise.Resolve(); + } + catch (Exception ex) + { + promise.Reject(ex); + } } public ModDeclare GetNextModFromWorkshopItem() diff --git a/ui/AIConfirmWindow.cs b/ui/AIConfirmWindow.cs index 8405d18..6971d91 100644 --- a/ui/AIConfirmWindow.cs +++ b/ui/AIConfirmWindow.cs @@ -9,7 +9,10 @@ namespace NeoModLoader.ui; internal class AIConfirmWindow : AbstractWindow { private Action onConfirmAction; + private Action onBackAction; private Text messageText; + private Text backText; + private Text continueText; protected override void Init() { @@ -57,7 +60,7 @@ protected override void Init() backBg.sprite = SpriteTextureLoader.getSprite("ui/special/special_buttonred"); backBg.type = Image.Type.Sliced; - Text backText = new GameObject("Text", typeof(Text)).GetComponent(); + backText = new GameObject("Text", typeof(Text)).GetComponent(); backText.transform.SetParent(backButtonObj.transform); backText.transform.localScale = Vector3.one; backText.GetComponent().sizeDelta = new Vector2(85, 25); @@ -67,7 +70,15 @@ protected override void Init() backButtonObj.GetComponent