mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 14:29:25 +00:00
stickers
This commit is contained in:
parent
61f1a884d2
commit
475593bc1d
25 changed files with 2172 additions and 0 deletions
80
Stickers/Integrations/BTKUI/BtkUiAddon.cs
Normal file
80
Stickers/Integrations/BTKUI/BtkUiAddon.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
using ABI_RC.Core.Player;
|
||||
using BTKUILib;
|
||||
using BTKUILib.UIObjects;
|
||||
|
||||
namespace NAK.Stickers.Integrations;
|
||||
|
||||
public static partial class BtkUiAddon
|
||||
{
|
||||
private static Page _rootPage;
|
||||
private static string _rootPageElementID;
|
||||
|
||||
private static bool _isOurTabOpened;
|
||||
private static Action _onOurTabOpened;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Prepare_Icons();
|
||||
Setup_AvatarScaleModTab();
|
||||
//Setup_PlayerSelectPage();
|
||||
}
|
||||
|
||||
#region Initialization
|
||||
|
||||
private static void Prepare_Icons()
|
||||
{
|
||||
// All icons used - https://www.flaticon.com/authors/gohsantosadrive
|
||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "Stickers-alphabet", GetIconStream("Gohsantosadrive_Icons.Stickers-alphabet.png"));
|
||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "Stickers-eraser", GetIconStream("Gohsantosadrive_Icons.Stickers-eraser.png"));
|
||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "Stickers-folder", GetIconStream("Gohsantosadrive_Icons.Stickers-folder.png"));
|
||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "Stickers-headset", GetIconStream("Gohsantosadrive_Icons.Stickers-headset.png"));
|
||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "Stickers-magic-wand", GetIconStream("Gohsantosadrive_Icons.Stickers-magic-wand.png"));
|
||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "Stickers-pencil", GetIconStream("Gohsantosadrive_Icons.Stickers-pencil.png"));
|
||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "Stickers-puzzle", GetIconStream("Gohsantosadrive_Icons.Stickers-puzzle.png"));
|
||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "Stickers-rubbish-bin", GetIconStream("Gohsantosadrive_Icons.Stickers-rubbish-bin.png"));
|
||||
}
|
||||
|
||||
private static void Setup_AvatarScaleModTab()
|
||||
{
|
||||
_rootPage = new Page(ModSettings.ModName, ModSettings.SM_SettingsCategory, true, "Stickers-puzzle")
|
||||
{
|
||||
MenuTitle = ModSettings.SM_SettingsCategory,
|
||||
MenuSubtitle = "Stickers! Double-click the tab to quickly toggle Sticker Mode.",
|
||||
};
|
||||
|
||||
_rootPageElementID = _rootPage.ElementID;
|
||||
QuickMenuAPI.OnTabChange += OnTabChange;
|
||||
// QuickMenuAPI.UserJoin += OnUserJoinLeave;
|
||||
// QuickMenuAPI.UserLeave += OnUserJoinLeave;
|
||||
// QuickMenuAPI.OnWorldLeave += OnWorldLeave;
|
||||
|
||||
Setup_StickersModCategory(_rootPage);
|
||||
Setup_StickerSelectionCategory(_rootPage);
|
||||
Setup_DebugOptionsCategory(_rootPage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Double-Click Place Sticker
|
||||
|
||||
private static DateTime lastTime = DateTime.Now;
|
||||
|
||||
private static void OnTabChange(string newTab, string previousTab)
|
||||
{
|
||||
_isOurTabOpened = newTab == _rootPageElementID;
|
||||
if (_isOurTabOpened)
|
||||
{
|
||||
_onOurTabOpened?.Invoke();
|
||||
TimeSpan timeDifference = DateTime.Now - lastTime;
|
||||
if (timeDifference.TotalSeconds <= 0.5)
|
||||
{
|
||||
//AvatarScaleManager.Instance.Setting_UniversalScaling = false;
|
||||
StickerSystem.Instance.IsInStickerMode = !StickerSystem.Instance.IsInStickerMode;
|
||||
return;
|
||||
}
|
||||
}
|
||||
lastTime = DateTime.Now;
|
||||
}
|
||||
|
||||
#endregion Double-Click Place Sticker
|
||||
}
|
15
Stickers/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs
Normal file
15
Stickers/Integrations/BTKUI/BtkUiAddon_CAT_DebugOptions.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using BTKUILib.UIObjects;
|
||||
|
||||
namespace NAK.Stickers.Integrations
|
||||
{
|
||||
public static partial class BtkUiAddon
|
||||
{
|
||||
private static void Setup_DebugOptionsCategory(Page page)
|
||||
{
|
||||
Category debugCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_DebugCategory);
|
||||
|
||||
AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkInbound);
|
||||
AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkOutbound);
|
||||
}
|
||||
}
|
||||
}
|
356
Stickers/Integrations/BTKUI/BtkUiAddon_CAT_StickerSelection.cs
Normal file
356
Stickers/Integrations/BTKUI/BtkUiAddon_CAT_StickerSelection.cs
Normal file
|
@ -0,0 +1,356 @@
|
|||
using BTKUILib;
|
||||
using BTKUILib.UIObjects;
|
||||
using BTKUILib.UIObjects.Components;
|
||||
using MTJobSystem;
|
||||
using NAK.Stickers.Networking;
|
||||
using NAK.Stickers.Utilities;
|
||||
|
||||
namespace NAK.Stickers.Integrations
|
||||
{
|
||||
public static partial class BtkUiAddon
|
||||
{
|
||||
private static readonly object _cacheLock = new();
|
||||
|
||||
private static bool _initialClearCacheFolder;
|
||||
private static Category _stickerSelectionCategory;
|
||||
internal static readonly Dictionary<string, ImageInfo> _cachedImages = new();
|
||||
|
||||
public static string GetBtkUiCachePath(string stickerName)
|
||||
{
|
||||
if (_cachedImages.TryGetValue(stickerName, out ImageInfo imageInfo))
|
||||
return "coui://uiresources/GameUI/mods/BTKUI/images/" + ModSettings.ModName + "/UserImages/" + imageInfo.cacheName + ".png";
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
internal class ImageInfo
|
||||
{
|
||||
public string filePath;
|
||||
public string cacheName; // BTKUI cache path
|
||||
public bool wasFoundThisPass;
|
||||
public bool hasChanged;
|
||||
public DateTime lastModified;
|
||||
public Button button;
|
||||
}
|
||||
|
||||
#region Setup
|
||||
|
||||
private static void Setup_StickerSelectionCategory(Page page)
|
||||
{
|
||||
_onOurTabOpened += UpdateStickerSelectionAsync;
|
||||
_stickerSelectionCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_SelectionCategory);
|
||||
ModNetwork.OnTextureOutboundStateChanged += OnSendingTextureOverNetworkChanged; // disable buttons when sending texture over network
|
||||
StickerSystem.OnImageLoadFailed += OnLoadImageFailed;
|
||||
GetInitialImageInfo();
|
||||
}
|
||||
|
||||
private static void GetInitialImageInfo()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = StickerSystem.GetStickersFolderPath();
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
StickerMod.Logger.Warning("Stickers folder not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
var stickerFiles = Directory.EnumerateFiles(path, "*.png");
|
||||
var currentFiles = new HashSet<string>(stickerFiles);
|
||||
|
||||
lock (_cacheLock)
|
||||
{
|
||||
if (!_initialClearCacheFolder)
|
||||
{
|
||||
_initialClearCacheFolder = true;
|
||||
DeleteOldIcons(ModSettings.ModName);
|
||||
}
|
||||
|
||||
var keysToRemove = new List<string>();
|
||||
|
||||
foreach (var stickerFile in currentFiles)
|
||||
{
|
||||
string stickerName = Path.GetFileNameWithoutExtension(stickerFile);
|
||||
|
||||
if (_cachedImages.TryGetValue(stickerName, out ImageInfo imageInfo))
|
||||
{
|
||||
imageInfo.wasFoundThisPass = true;
|
||||
DateTime lastModified = File.GetLastWriteTime(stickerFile);
|
||||
if (lastModified == imageInfo.lastModified) continue;
|
||||
imageInfo.hasChanged = true;
|
||||
imageInfo.lastModified = lastModified;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedImages[stickerName] = new ImageInfo
|
||||
{
|
||||
filePath = stickerFile,
|
||||
wasFoundThisPass = true,
|
||||
hasChanged = true,
|
||||
lastModified = File.GetLastWriteTime(stickerFile)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kvp in _cachedImages)
|
||||
{
|
||||
var imageName = kvp.Key;
|
||||
ImageInfo imageInfo = kvp.Value;
|
||||
|
||||
if (!imageInfo.wasFoundThisPass)
|
||||
{
|
||||
MainThreadInvoke(() =>
|
||||
{
|
||||
if (imageInfo.button != null)
|
||||
{
|
||||
imageInfo.button.Delete();
|
||||
imageInfo.button = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(imageInfo.cacheName))
|
||||
{
|
||||
DeleteOldIcon(ModSettings.ModName, imageInfo.cacheName);
|
||||
imageInfo.cacheName = string.Empty;
|
||||
}
|
||||
|
||||
keysToRemove.Add(imageName);
|
||||
}
|
||||
else if (imageInfo.hasChanged)
|
||||
{
|
||||
imageInfo.hasChanged = false;
|
||||
|
||||
if (!string.IsNullOrEmpty(imageInfo.cacheName))
|
||||
{
|
||||
DeleteOldIcon(ModSettings.ModName, imageInfo.cacheName);
|
||||
imageInfo.cacheName = string.Empty;
|
||||
}
|
||||
|
||||
MemoryStream imageStream = LoadStreamFromFile(imageInfo.filePath);
|
||||
if (imageStream == null) continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (imageStream.Length > 256 * 1024)
|
||||
ImageUtility.Resize(ref imageStream, 256, 256);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StickerMod.Logger.Warning($"Failed to resize image: {e.Message}");
|
||||
}
|
||||
|
||||
imageInfo.cacheName = $"{imageName}_{Guid.NewGuid()}";
|
||||
|
||||
PrepareIconFromMemoryStream(ModSettings.ModName, imageInfo.cacheName, imageStream);
|
||||
}
|
||||
|
||||
imageInfo.wasFoundThisPass = false;
|
||||
}
|
||||
|
||||
foreach (var key in keysToRemove)
|
||||
_cachedImages.Remove(key);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StickerMod.Logger.Error($"Failed to update sticker selection: {e.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void UpdateStickerSelectionAsync()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string path = StickerSystem.GetStickersFolderPath();
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
StickerMod.Logger.Warning("Stickers folder not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
var stickerFiles = Directory.EnumerateFiles(path, "*.png");
|
||||
var currentFiles = new HashSet<string>(stickerFiles);
|
||||
|
||||
lock (_cacheLock)
|
||||
{
|
||||
if (!_initialClearCacheFolder)
|
||||
{
|
||||
_initialClearCacheFolder = true;
|
||||
DeleteOldIcons(ModSettings.ModName);
|
||||
}
|
||||
|
||||
var keysToRemove = new List<string>();
|
||||
|
||||
foreach (var stickerFile in currentFiles)
|
||||
{
|
||||
string stickerName = Path.GetFileNameWithoutExtension(stickerFile);
|
||||
|
||||
if (_cachedImages.TryGetValue(stickerName, out ImageInfo imageInfo))
|
||||
{
|
||||
imageInfo.wasFoundThisPass = true;
|
||||
if (imageInfo.button == null)
|
||||
{
|
||||
imageInfo.hasChanged = true;
|
||||
continue;
|
||||
}
|
||||
DateTime lastModified = File.GetLastWriteTime(stickerFile);
|
||||
if (lastModified == imageInfo.lastModified) continue;
|
||||
imageInfo.hasChanged = true;
|
||||
imageInfo.lastModified = lastModified;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedImages[stickerName] = new ImageInfo
|
||||
{
|
||||
filePath = stickerFile,
|
||||
wasFoundThisPass = true,
|
||||
hasChanged = true,
|
||||
lastModified = File.GetLastWriteTime(stickerFile)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kvp in _cachedImages)
|
||||
{
|
||||
var imageName = kvp.Key;
|
||||
ImageInfo imageInfo = kvp.Value;
|
||||
|
||||
if (!imageInfo.wasFoundThisPass)
|
||||
{
|
||||
MainThreadInvoke(() =>
|
||||
{
|
||||
if (imageInfo.button != null)
|
||||
{
|
||||
imageInfo.button.Delete();
|
||||
imageInfo.button = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(imageInfo.cacheName))
|
||||
{
|
||||
DeleteOldIcon(ModSettings.ModName, imageInfo.cacheName);
|
||||
imageInfo.cacheName = string.Empty;
|
||||
}
|
||||
|
||||
keysToRemove.Add(imageName);
|
||||
}
|
||||
else if (imageInfo.hasChanged)
|
||||
{
|
||||
imageInfo.hasChanged = false;
|
||||
|
||||
if (!string.IsNullOrEmpty(imageInfo.cacheName))
|
||||
{
|
||||
DeleteOldIcon(ModSettings.ModName, imageInfo.cacheName);
|
||||
imageInfo.cacheName = string.Empty;
|
||||
}
|
||||
|
||||
MemoryStream imageStream = LoadStreamFromFile(imageInfo.filePath);
|
||||
if (imageStream == null) continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (imageStream.Length > 256 * 1024)
|
||||
ImageUtility.Resize(ref imageStream, 256, 256);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StickerMod.Logger.Warning($"Failed to resize image: {e.Message}");
|
||||
}
|
||||
|
||||
imageInfo.cacheName = $"{imageName}_{Guid.NewGuid()}";
|
||||
|
||||
PrepareIconFromMemoryStream(ModSettings.ModName, imageInfo.cacheName, imageStream);
|
||||
|
||||
MainThreadInvoke(() =>
|
||||
{
|
||||
if (imageInfo.button != null)
|
||||
imageInfo.button.ButtonIcon = "UserImages/" + imageInfo.cacheName;
|
||||
else
|
||||
{
|
||||
imageInfo.button = _stickerSelectionCategory.AddButton(imageName, "UserImages/" + imageInfo.cacheName, $"Select {imageName}.", ButtonStyle.TextWithIcon);
|
||||
imageInfo.button.OnPress += () => OnStickerButtonClick(imageInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
imageInfo.wasFoundThisPass = false;
|
||||
}
|
||||
|
||||
foreach (var key in keysToRemove)
|
||||
_cachedImages.Remove(key);
|
||||
|
||||
MainThreadInvoke(() =>
|
||||
{
|
||||
_stickerSelectionCategory.CategoryName = $"{ModSettings.SM_SelectionCategory} ({_cachedImages.Count})";
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StickerMod.Logger.Error($"Failed to update sticker selection: {e.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static MemoryStream LoadStreamFromFile(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
//StickerMod.Logger.Msg($"Loaded sticker stream from {filePath}");
|
||||
|
||||
using FileStream fileStream = new(filePath, FileMode.Open, FileAccess.Read);
|
||||
|
||||
MemoryStream memoryStream = new();
|
||||
fileStream.CopyTo(memoryStream);
|
||||
memoryStream.Position = 0; // Ensure the position is reset before returning
|
||||
return memoryStream;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
StickerMod.Logger.Warning($"Failed to load stream from {filePath}: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static void MainThreadInvoke(Action action)
|
||||
=> MTJobManager.RunOnMainThread("fuck", action.Invoke);
|
||||
|
||||
#endregion Setup
|
||||
|
||||
#region Button Actions
|
||||
|
||||
private static void OnStickerButtonClick(ImageInfo imageInfo)
|
||||
{
|
||||
// i wish i could highlight it
|
||||
StickerSystem.Instance.LoadImage(imageInfo.button.ButtonText);
|
||||
}
|
||||
|
||||
#endregion Button Actions
|
||||
|
||||
#region Callbacks
|
||||
|
||||
private static void OnSendingTextureOverNetworkChanged(bool isSending)
|
||||
{
|
||||
MTJobManager.RunAsyncOnMainThread("fuck2", () =>
|
||||
{
|
||||
// go through all buttons and disable them
|
||||
if (_isOurTabOpened && isSending) QuickMenuAPI.ShowAlertToast("Sending Sticker over Mod Network...", 2);
|
||||
foreach ((_, ImageInfo value) in _cachedImages) value.button.Disabled = isSending;
|
||||
});
|
||||
}
|
||||
|
||||
private static void OnLoadImageFailed(string reason)
|
||||
{
|
||||
if (!_isOurTabOpened) return;
|
||||
QuickMenuAPI.ShowAlertToast(reason, 2);
|
||||
}
|
||||
|
||||
#endregion Callbacks
|
||||
}
|
||||
}
|
105
Stickers/Integrations/BTKUI/BtkUiAddon_CAT_StickersMod.cs
Normal file
105
Stickers/Integrations/BTKUI/BtkUiAddon_CAT_StickersMod.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
using BTKUILib;
|
||||
using BTKUILib.UIObjects;
|
||||
using BTKUILib.UIObjects.Components;
|
||||
using BTKUILib.UIObjects.Objects;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.Stickers.Integrations;
|
||||
|
||||
public static partial class BtkUiAddon
|
||||
{
|
||||
private static Category _ourCategory;
|
||||
|
||||
private static readonly MultiSelection _sfxSelection =
|
||||
new(
|
||||
"Sticker SFX",
|
||||
new[] { "Little Big Planet", "Source Engine", "None" },
|
||||
(int)ModSettings.Entry_SelectedSFX.Value
|
||||
)
|
||||
{
|
||||
OnOptionUpdated = i => ModSettings.Entry_SelectedSFX.Value = (ModSettings.SFXType)i
|
||||
};
|
||||
|
||||
private static readonly MultiSelection _desktopKeybindSelection =
|
||||
new(
|
||||
"Desktop Keybind",
|
||||
Enum.GetNames(typeof(KeyCode)),
|
||||
(int)ModSettings.Entry_PlaceBinding.Value
|
||||
)
|
||||
{
|
||||
OnOptionUpdated = i =>
|
||||
{
|
||||
if (Enum.GetValues(typeof(KeyCode)) is string[] options) // inefficient but works
|
||||
ModSettings.Entry_PlaceBinding.Value = (KeyCode)Enum.Parse(typeof(KeyCode), options[i]);
|
||||
}
|
||||
};
|
||||
|
||||
#region Category Setup
|
||||
|
||||
private static void Setup_StickersModCategory(Page page)
|
||||
{
|
||||
//_ourCategory = page.AddCategory(ModSettings.Stickers_SettingsCategory, ModSettings.ModName, true, true, false);
|
||||
_ourCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_SettingsCategory);
|
||||
|
||||
Button placeStickersButton = _ourCategory.AddButton("Place Stickers", "Stickers-magic-wand", "Place stickers via raycast.", ButtonStyle.TextWithIcon);
|
||||
placeStickersButton.OnPress += OnPlaceStickersButtonClick;
|
||||
|
||||
Button clearSelfStickersButton = _ourCategory.AddButton("Clear Self", "Stickers-eraser", "Clear own stickers.", ButtonStyle.TextWithIcon);
|
||||
clearSelfStickersButton.OnPress += OnClearSelfStickersButtonClick;
|
||||
|
||||
Button clearAllStickersButton = _ourCategory.AddButton("Clear All", "Stickers-rubbish-bin", "Clear all stickers.", ButtonStyle.TextWithIcon);
|
||||
clearAllStickersButton.OnPress += OnClearAllStickersButtonClick;
|
||||
|
||||
Button openStickersFolderButton = _ourCategory.AddButton("Open Stickers Folder", "Stickers-folder", "Open UserData/Stickers folder in explorer. If above 256kb your image will automatically be downscaled for networking reasons.", ButtonStyle.TextWithIcon);
|
||||
openStickersFolderButton.OnPress += OnOpenStickersFolderButtonClick;
|
||||
|
||||
Button openMultiSelectionButton = _ourCategory.AddButton("Sticker SFX", "Stickers-headset", "Choose the SFX used when a sticker is placed.", ButtonStyle.TextWithIcon);
|
||||
openMultiSelectionButton.OnPress += () => QuickMenuAPI.OpenMultiSelect(_sfxSelection);
|
||||
|
||||
ToggleButton toggleDesktopKeybindButton = _ourCategory.AddToggle("Use Desktop Keybind", "Should the Desktop keybind be active.", ModSettings.Entry_UsePlaceBinding.Value);
|
||||
Button openDesktopKeybindButton = _ourCategory.AddButton("Desktop Keybind", "Stickers-alphabet", "Choose the key binding to place stickers.", ButtonStyle.TextWithIcon);
|
||||
openDesktopKeybindButton.OnPress += () => QuickMenuAPI.OpenMultiSelect(_desktopKeybindSelection);
|
||||
toggleDesktopKeybindButton.OnValueUpdated += (b) =>
|
||||
{
|
||||
ModSettings.Entry_UsePlaceBinding.Value = b;
|
||||
openDesktopKeybindButton.Disabled = !b;
|
||||
};
|
||||
|
||||
//AddMelonToggle(ref _ourCategory, ModSettings.Entry_UsePlaceBinding);
|
||||
}
|
||||
|
||||
#endregion Category Setup
|
||||
|
||||
#region Button Actions
|
||||
|
||||
private static void OnPlaceStickersButtonClick()
|
||||
{
|
||||
if (!_isOurTabOpened) return;
|
||||
string mode = StickerSystem.Instance.IsInStickerMode ? "Exiting" : "Entering";
|
||||
QuickMenuAPI.ShowAlertToast($"{mode} sticker placement mode...", 2);
|
||||
StickerSystem.Instance.IsInStickerMode = !StickerSystem.Instance.IsInStickerMode;
|
||||
}
|
||||
|
||||
private static void OnClearSelfStickersButtonClick()
|
||||
{
|
||||
if (!_isOurTabOpened) return;
|
||||
QuickMenuAPI.ShowAlertToast("Clearing own stickers in world...", 2);
|
||||
StickerSystem.Instance.ClearStickersSelf();
|
||||
}
|
||||
|
||||
private static void OnClearAllStickersButtonClick()
|
||||
{
|
||||
if (!_isOurTabOpened) return;
|
||||
QuickMenuAPI.ShowAlertToast("Clearing all stickers in world...", 2);
|
||||
StickerSystem.Instance.ClearAllStickers();
|
||||
}
|
||||
|
||||
private static void OnOpenStickersFolderButtonClick()
|
||||
{
|
||||
if (!_isOurTabOpened) return;
|
||||
QuickMenuAPI.ShowAlertToast("Opening Stickers folder in Explorer...", 2);
|
||||
StickerSystem.OpenStickersFolder();
|
||||
}
|
||||
|
||||
#endregion Button Actions
|
||||
}
|
104
Stickers/Integrations/BTKUI/BtkuiAddon_Utils.cs
Normal file
104
Stickers/Integrations/BTKUI/BtkuiAddon_Utils.cs
Normal file
|
@ -0,0 +1,104 @@
|
|||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using BTKUILib;
|
||||
using BTKUILib.UIObjects;
|
||||
using BTKUILib.UIObjects.Components;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NAK.Stickers.Integrations;
|
||||
|
||||
public static partial class BtkUiAddon
|
||||
{
|
||||
#region Melon Preference Helpers
|
||||
|
||||
private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry<bool> entry)
|
||||
{
|
||||
ToggleButton toggle = category.AddToggle(entry.DisplayName, entry.Description, entry.Value);
|
||||
toggle.OnValueUpdated += b => entry.Value = b;
|
||||
return toggle;
|
||||
}
|
||||
|
||||
private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry<float> entry, float min,
|
||||
float max, int decimalPlaces = 2, bool allowReset = true)
|
||||
{
|
||||
SliderFloat slider = category.AddSlider(entry.DisplayName, entry.Description,
|
||||
Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset);
|
||||
slider.OnValueUpdated += f => entry.Value = f;
|
||||
return slider;
|
||||
}
|
||||
|
||||
private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry<string> entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly)
|
||||
{
|
||||
Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle);
|
||||
button.OnPress += () => QuickMenuAPI.OpenKeyboard(entry.Value, s => entry.Value = s);
|
||||
return button;
|
||||
}
|
||||
|
||||
private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry<float> entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly)
|
||||
{
|
||||
Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle);
|
||||
button.OnPress += () => QuickMenuAPI.OpenNumberInput(entry.DisplayName, entry.Value, f => entry.Value = f);
|
||||
return button;
|
||||
}
|
||||
|
||||
private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry<bool> entry, bool showHeader = true)
|
||||
{
|
||||
Category category = page.AddCategory(entry.DisplayName, showHeader, true, entry.Value);
|
||||
category.OnCollapse += b => entry.Value = b;
|
||||
return category;
|
||||
}
|
||||
|
||||
#endregion Melon Preference Helpers
|
||||
|
||||
#region Icon Utils
|
||||
|
||||
private static Stream GetIconStream(string iconName)
|
||||
{
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
string assemblyName = assembly.GetName().Name;
|
||||
return assembly.GetManifestResourceStream($"{assemblyName}.Resources.{iconName}");
|
||||
}
|
||||
|
||||
#endregion Icon Utils
|
||||
|
||||
public static void PrepareIconFromMemoryStream(string modName, string iconName, MemoryStream destination)
|
||||
{
|
||||
if (destination == null)
|
||||
{
|
||||
StickerMod.Logger.Error("Mod " + modName + " attempted to prepare " + iconName + " but the resource stream was null! Yell at the mod author to fix this!");
|
||||
}
|
||||
else
|
||||
{
|
||||
modName = UIUtils.GetCleanString(modName);
|
||||
string path1 = @"ChilloutVR_Data\StreamingAssets\Cohtml\UIResources\GameUI\mods\BTKUI\images\" + modName + @"\UserImages";
|
||||
if (!Directory.Exists(path1)) Directory.CreateDirectory(path1);
|
||||
string path2 = path1 + "\\" + iconName + ".png";
|
||||
File.WriteAllBytes(path2, destination.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeleteOldIcon(string modName, string iconName)
|
||||
{
|
||||
string directoryPath = Path.Combine("ChilloutVR_Data", "StreamingAssets", "Cohtml", "UIResources", "GameUI", "mods", "BTKUI", "images", modName, "UserImages");
|
||||
string oldIconPath = Path.Combine(directoryPath, $"{iconName}.png");
|
||||
if (!File.Exists(oldIconPath))
|
||||
return;
|
||||
|
||||
File.Delete(oldIconPath);
|
||||
//StickerMod.Logger.Msg($"Deleted old icon: {oldIconPath}");
|
||||
}
|
||||
|
||||
private static void DeleteOldIcons(string modName)
|
||||
{
|
||||
string directoryPath = Path.Combine("ChilloutVR_Data", "StreamingAssets", "Cohtml", "UIResources", "GameUI", "mods", "BTKUI", "images", modName, "UserImages");
|
||||
if (!Directory.Exists(directoryPath))
|
||||
return;
|
||||
|
||||
foreach (string file in Directory.EnumerateFiles(directoryPath, "*.png"))
|
||||
{
|
||||
File.Delete(file);
|
||||
//StickerMod.Logger.Msg($"Deleted old icon: {file}");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue