From 4c2db081b983b14e3e31b792be0d2bc038163c29 Mon Sep 17 00:00:00 2001 From: Commander-Cat101 Date: Sat, 13 Sep 2025 15:37:32 +1200 Subject: [PATCH 1/5] initial work --- Assets/EmptyLikeIcon.png | Bin 0 -> 15336 bytes Assets/FullLikeIcon.png | Bin 0 -> 10793 bytes Modules/Core/BloonModule.cs | 1 - SerializationHandler.cs | 20 +++++++++-- ServerHandler.cs | 62 ++++++++++++++++++++++++++++++++++ UI/BloonBrowserBloonPanel.cs | 63 +++++++++++++++++++++++++++++++++++ UI/BloonBrowserUI.cs | 57 +++++++++++++++++++++++++++++++ UI/BloonEditorButton.cs | 2 +- UI/EditSelectorUI.cs | 11 +++--- 9 files changed, 207 insertions(+), 9 deletions(-) create mode 100644 Assets/EmptyLikeIcon.png create mode 100644 Assets/FullLikeIcon.png create mode 100644 ServerHandler.cs create mode 100644 UI/BloonBrowserBloonPanel.cs diff --git a/Assets/EmptyLikeIcon.png b/Assets/EmptyLikeIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..14f8f2307b86e82f011f03ab2b853225452c2412 GIT binary patch literal 15336 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 literal 0 HcmV?d00001 diff --git a/Modules/Core/BloonModule.cs b/Modules/Core/BloonModule.cs index 7d4e2e2..1c57c30 100644 --- a/Modules/Core/BloonModule.cs +++ b/Modules/Core/BloonModule.cs @@ -21,7 +21,6 @@ internal class BloonModule : Module public RoundSetModel currentRoundSet; public override void GetModuleProperties() { - AddProperty(new StringModuleProperty("Name", "Custom Bloon", 20)); AddProperty(new IntModuleProperty("Health", 1, 1, int.MaxValue)); AddProperty(new FloatModuleProperty("Speed", 25, 1, float.MaxValue)); AddProperty(new IntModuleProperty("Damage", 1, 1, int.MaxValue)); diff --git a/SerializationHandler.cs b/SerializationHandler.cs index 3c6f8dc..f389399 100644 --- a/SerializationHandler.cs +++ b/SerializationHandler.cs @@ -1,6 +1,7 @@ using BloonFactory.Modules.Core; using FactoryCore.API; using Il2CppSystem.Security.Cryptography; +using MelonLoader; using MelonLoader.Utils; using Newtonsoft.Json; using System; @@ -34,7 +35,7 @@ internal static void SaveTemplate(BloonTemplate template) var path = Path.Combine(FolderDirectory, template.Guid.ToString() + FileExtention); File.WriteAllText(path, content); } - internal static BloonTemplate LoadTemplate(string path) + internal static BloonTemplate GetTemplate(string path) { EnsureFolderExists(); @@ -44,13 +45,28 @@ internal static BloonTemplate LoadTemplate(string path) var content = JsonConvert.DeserializeObject(File.ReadAllText(path), Settings); return content; } + internal static bool TryLoadTemplate(BloonTemplate template) + { + EnsureFolderExists(); + + if (Templates.Any(a => a.Guid == template.Guid)) + { + MelonLogger.Msg("File already exists"); + return false; + } + + template.IsLoaded = false; + SaveTemplate(template); + Templates.Add(template); + return true; + } internal static void LoadAllTemplates() { EnsureFolderExists(); foreach (var path in Directory.GetFiles(FolderDirectory).Where(f => f.EndsWith(".cstmbln"))) { - var template = LoadTemplate(path); + var template = GetTemplate(path); if (!Templates.Any(a => a.Guid == template.Guid)) { template.LoadModules(); diff --git a/ServerHandler.cs b/ServerHandler.cs new file mode 100644 index 0000000..cdc1041 --- /dev/null +++ b/ServerHandler.cs @@ -0,0 +1,62 @@ + +using JetBrains.Annotations; +using MelonLoader; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Octokit; +using Octokit.Internal; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using static BloonFactory.UI.BloonBrowserBloonPanel; + +namespace BloonFactory +{ + internal static class ServerHandler + { + public const string URL = "http://localhost:8000/"; + private static HttpClient client = new HttpClient(); + internal static async Task Ping() + { + HttpResponseMessage response = await client.GetAsync(URL + "ping"); + response.EnsureSuccessStatusCode(); + byte[] bytes = await response.Content.ReadAsByteArrayAsync(); + MelonLogger.Msg(Encoding.UTF8.GetString(bytes)); + } + internal static async Task RequestPageUpdate() + { + HttpResponseMessage response = await client.GetAsync(URL + "getPage"); + response.EnsureSuccessStatusCode(); + byte[] bytes = await response.Content.ReadAsByteArrayAsync(); + + var obj = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bytes), new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None }); + return obj; + } + internal static async Task DownloadTemplate(Guid guid) + { + HttpResponseMessage response = await client.GetAsync(URL + $"getTemplate={guid.ToString()}"); + response.EnsureSuccessStatusCode(); + byte[] bytes = await response.Content.ReadAsByteArrayAsync(); + + var obj = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bytes), SerializationHandler.Settings); + return obj; + } + } + public class PageUpdateRequest + { + public List Data; + } + public class BloonBrowserEntry + { + public string Name; + public Guid Guid; + public int LikeCount; + public int FileSize; + } +} diff --git a/UI/BloonBrowserBloonPanel.cs b/UI/BloonBrowserBloonPanel.cs new file mode 100644 index 0000000..f470996 --- /dev/null +++ b/UI/BloonBrowserBloonPanel.cs @@ -0,0 +1,63 @@ +using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Api.Components; +using BTD_Mod_Helper.Api.Enums; +using Il2CppTMPro; +using MelonLoader; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using static UnityEngine.RectTransform; + +namespace BloonFactory.UI +{ + internal class BloonBrowserBloonPanel + { + + public static ModHelperPanel CreateTemplate(BloonBrowserEntry entry) + { + if (entry is null) + return null; + + var panel = ModHelperPanel.Create(new Info("Panel", 3600, 250), VanillaSprites.MainBGPanelBlue); + panel.AddText(new Info("Name", 575, 0, 1000, 200, new Vector2(0, 0.5f)), entry.Name, 100, TextAlignmentOptions.Left).EnableAutoSizing(120, 20); + + panel.AddButton(new Info("Download", -125, 0, 200, 200, new Vector2(1, 0.5f)), ModHelperSprites.DownloadBtn, new Action(() => + { + Download(entry.Guid); + })); + panel.AddText(new Info("FileSize", -375, 0, 450, 200, new Vector2(1, 0.5f)), ByteArrayLengthToSizeText(entry.FileSize), 120, TextAlignmentOptions.Left).EnableAutoSizing(120, 20); + + /*panel.AddButton(new Info("Heart", -675, 0, 200, 200, new Vector2(1, 0.5f)), ModContent.GetSpriteReference("EmptyLikeIcon").guidRef, new Action(() => + { + + })); + panel.AddText(new Info("HeartCount", -450, 0, 200, 200, new Vector2(1, 0.5f)), entry.LikeCount.ToString(), 120, TextAlignmentOptions.Left);*/ + + return panel; + } + private static string ByteArrayLengthToSizeText(int length) + { + if (length >= 1_000_000) + { + return $"{Math.Round((double)(length / 1_000_000), 2)} MB"; + } + if (length >= 1_000) + { + return $"{Math.Round((double)(length / 1_000), 2)} KB"; + } + else + { + return $"{length} B"; + } + } + private static async void Download(Guid guid) + { + BloonTemplate template = await ServerHandler.DownloadTemplate(guid); + SerializationHandler.TryLoadTemplate(template); + } + + } +} diff --git a/UI/BloonBrowserUI.cs b/UI/BloonBrowserUI.cs index e200a61..25e31dd 100644 --- a/UI/BloonBrowserUI.cs +++ b/UI/BloonBrowserUI.cs @@ -1,19 +1,76 @@ using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Api.Components; +using BTD_Mod_Helper.Api.Enums; using BTD_Mod_Helper.Api.Legends; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Unity; using Il2CppAssets.Scripts.Unity.UI_New.ChallengeEditor; +using Il2CppNinjaKiwi.Common; +using MelonLoader; +using Newtonsoft.Json; +using Octokit.Internal; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.UI; +using static BloonFactory.UI.BloonBrowserBloonPanel; namespace BloonFactory.UI { internal class BloonBrowserUI : ModGameMenu { + public bool generatedContentReady = false; + public BloonBrowserEntry[] currentPage; public override bool OnMenuOpened(Il2CppSystem.Object data) { + ModifyElements(); + AddElements(); + GenerateContentForPage(); + return false; + } + public override void OnMenuUpdate() + { + if (generatedContentReady) + { + generatedContentReady = false; + foreach (var entry in currentPage) + { + GameMenu.scrollRect.content.gameObject.AddModHelperComponent(CreateTemplate(entry)); + } + } + } + public void ModifyElements() + { + GameMenu.GetComponentFromChildrenByName("TopBar").gameObject.active = false; + GameMenu.GetComponentFromChildrenByName("Tabs").gameObject.active = false; + + var verticalLayoutGroup = GameMenu.scrollRect.content.GetComponent(); + verticalLayoutGroup.SetPadding(50); + verticalLayoutGroup.spacing = 50; + verticalLayoutGroup.childControlWidth = false; + verticalLayoutGroup.childControlHeight = false; + GameMenu.scrollRect.rectTransform.sizeDelta += new Vector2(0, 200); + GameMenu.scrollRect.rectTransform.localPosition += new Vector3(0, 100, 0); + } + public void AddElements() + { + var container = GameMenu.GetComponentFromChildrenByName("Container").gameObject.AddModHelperPanel(new Info("SearchBar", 0, -475, new Vector2(0.5f, 1))); + container.AddInputField(new Info("Search", 0, -425, 1500, 150), "Search...", VanillaSprites.BlueInsertPanel).InputField.textComponent.enableAutoSizing = true; + } + public void GenerateContentForPage() + { + GameMenu.scrollRect.content.transform.DestroyAllChildren(); + + Task.Run(async () => + { + PageUpdateRequest request = await ServerHandler.RequestPageUpdate(); + currentPage = request.Data.ToArray(); + generatedContentReady = true; + }); } } } diff --git a/UI/BloonEditorButton.cs b/UI/BloonEditorButton.cs index 1b896a1..1db8662 100644 --- a/UI/BloonEditorButton.cs +++ b/UI/BloonEditorButton.cs @@ -33,7 +33,7 @@ public static void Create(MainMenu menu) matchLocalPosition.transformToCopy = trophyStore.transform; matchLocalPosition.offset = new Vector3(0, -325); - var text = ModHelperText.Create(new Info("BloonEditor", 100, 150), "Bloon\nEditor"); + var text = ModHelperText.Create(new Info("BloonEditor", 125, 175), "Bloon\nFactory"); text.transform.GetComponent().enableAutoSizing = true; text.transform.SetParent(modsButton.GetComponentInChildren