using ABI_RC.Core; using ABI_RC.Core.Player; using ABI_RC.Core.Savior; using ABI_RC.Systems.InputManagement; using MelonLoader; using NAK.Stickers.Integrations; using NAK.Stickers.Networking; using UnityEngine; namespace NAK.Stickers; public class StickerMod : MelonMod { internal static MelonLogger.Instance Logger; #region Melon Mod Overrides public override void OnInitializeMelon() { Logger = LoggerInstance; ModNetwork.Subscribe(); ModSettings.Initialize(); StickerSystem.Initialize(); ApplyPatches(typeof(Patches.PlayerSetup_Patches)); ApplyPatches(typeof(Patches.ControllerRay_Patches)); ApplyPatches(typeof(Patches.ShaderFilterHelper_Patches)); ApplyPatches(typeof(Patches.CVRTools_Patches)); LoadAssetBundle(); InitializeIntegration(nameof(BTKUILib), BTKUIAddon.Initialize); // quick menu ui } public override void OnUpdate() { if (StickerSystem.Instance == null) return; if (Input.mouseScrollDelta.y != 0f && Cursor.lockState == CursorLockMode.Locked // prevent scrolling while in menus && !CVRInputManager.Instance.zoom) // prevent scrolling while using scroll zoom StickerSystem.Instance.SelectedStickerSlot += (int)Input.mouseScrollDelta.y; StickerSystem.Instance.UpdateStickerPreview(); // flashy flash if (!ModSettings.Entry_UsePlaceBinding.Value) return; if (!Input.GetKeyDown((KeyCode)ModSettings.Entry_PlaceBinding.Value)) return; if (CVRInputManager.Instance.textInputFocused) return; // prevent placing stickers while typing StickerSystem.Instance.PlaceStickerFromControllerRay(PlayerSetup.Instance.activeCam.transform); } public override void OnApplicationQuit() { StickerSystem.Instance.CleanupAll(); } #endregion Melon Mod Overrides #region Melon Mod Utilities private static void InitializeIntegration(string modName, Action integrationAction) { if (RegisteredMelons.All(it => it.Info.Name != modName)) return; Logger.Msg($"Initializing {modName} integration."); integrationAction.Invoke(); } private void ApplyPatches(Type type) { try { HarmonyInstance.PatchAll(type); } catch (Exception e) { LoggerInstance.Msg($"Failed while patching {type.Name}!"); LoggerInstance.Error(e); } } #endregion Melon Mod Utilities #region Asset Bundle Loading private const string DecaleryShaderAssets = "decalery_shaders.assets"; private const string DecalerySimpleShader = "Assets/Decalery/Shaders/DecalerySimple.shader"; private const string GPUDecalWriteShader = "Assets/Decalery/fGPUDecalWriteShader.shader"; private const string SourceSFX_PlayerSprayer = "Assets/Mods/Stickers/Source_sound_player_sprayer.wav"; private const string LittleBigPlanetSFX_StickerPlace = "Assets/Mods/Stickers/LBP_Sticker_Place.wav"; private const string FactorioSFX_AlertDestroyed = "Assets/Mods/Stickers/Factorio_alert_destroyed.wav"; internal static Shader DecalSimpleShader; internal static Shader DecalWriterShader; internal static AudioClip SourceSFXPlayerSprayer; internal static AudioClip LittleBigPlanetSFXStickerPlace; internal static AudioClip FactorioSFXAlertDestroyed; private void LoadAssetBundle() { LoggerInstance.Msg($"Loading required asset bundle..."); using Stream resourceStream = MelonAssembly.Assembly.GetManifestResourceStream(DecaleryShaderAssets); using MemoryStream memoryStream = new(); if (resourceStream == null) { LoggerInstance.Error($"Failed to load {DecaleryShaderAssets}!"); return; } resourceStream.CopyTo(memoryStream); AssetBundle assetBundle = AssetBundle.LoadFromMemory(memoryStream.ToArray()); if (assetBundle == null) { LoggerInstance.Error($"Failed to load {DecaleryShaderAssets}! Asset bundle is null!"); return; } DecalSimpleShader = assetBundle.LoadAsset(DecalerySimpleShader); if (DecalSimpleShader == null) { LoggerInstance.Error($"Failed to load {DecalerySimpleShader}! Prefab is null!"); return; } DecalSimpleShader.hideFlags |= HideFlags.DontUnloadUnusedAsset; LoggerInstance.Msg($"Loaded {DecalerySimpleShader}!"); DecalWriterShader = assetBundle.LoadAsset(GPUDecalWriteShader); if (DecalWriterShader == null) { LoggerInstance.Error($"Failed to load {GPUDecalWriteShader}! Prefab is null!"); return; } DecalWriterShader.hideFlags |= HideFlags.DontUnloadUnusedAsset; LoggerInstance.Msg($"Loaded {GPUDecalWriteShader}!"); SourceSFXPlayerSprayer = assetBundle.LoadAsset(SourceSFX_PlayerSprayer); if (SourceSFXPlayerSprayer == null) { LoggerInstance.Error($"Failed to load {SourceSFX_PlayerSprayer}! Prefab is null!"); return; } SourceSFXPlayerSprayer.hideFlags |= HideFlags.DontUnloadUnusedAsset; LoggerInstance.Msg($"Loaded {SourceSFX_PlayerSprayer}!"); LittleBigPlanetSFXStickerPlace = assetBundle.LoadAsset(LittleBigPlanetSFX_StickerPlace); if (LittleBigPlanetSFXStickerPlace == null) { LoggerInstance.Error($"Failed to load {LittleBigPlanetSFX_StickerPlace}! Prefab is null!"); return; } LittleBigPlanetSFXStickerPlace.hideFlags |= HideFlags.DontUnloadUnusedAsset; LoggerInstance.Msg($"Loaded {LittleBigPlanetSFX_StickerPlace}!"); FactorioSFXAlertDestroyed = assetBundle.LoadAsset(FactorioSFX_AlertDestroyed); if (FactorioSFXAlertDestroyed == null) { LoggerInstance.Error($"Failed to load {FactorioSFX_AlertDestroyed}! Prefab is null!"); return; } FactorioSFXAlertDestroyed.hideFlags |= HideFlags.DontUnloadUnusedAsset; LoggerInstance.Msg($"Loaded {FactorioSFX_AlertDestroyed}!"); // load LoggerInstance.Msg("Asset bundle successfully loaded!"); } #endregion Asset Bundle Loading }