Stickers: minor changes

This commit is contained in:
NotAKidoS 2024-09-02 00:18:57 -05:00
parent c206d98a97
commit 2f65634031
16 changed files with 204 additions and 140 deletions

View file

@ -1,13 +0,0 @@
using BTKUILib.UIObjects;
namespace NAK.Stickers.Integrations;
public static partial class BTKUIAddon
{
private static void Setup_DebugOptionsCategory()
{
Category debugCategory = _rootPage.AddMelonCategory(ModSettings.Hidden_Foldout_DebugCategory);
debugCategory.AddMelonToggle(ModSettings.Debug_NetworkInbound);
debugCategory.AddMelonToggle(ModSettings.Debug_NetworkOutbound);
}
}

View file

@ -0,0 +1,24 @@
using BTKUILib;
using BTKUILib.UIObjects;
using BTKUILib.UIObjects.Components;
using NAK.Stickers.Utilities;
namespace NAK.Stickers.Integrations;
public static partial class BTKUIAddon
{
private static void Setup_OtherOptionsCategory()
{
Category debugCategory = _rootPage.AddMelonCategory(ModSettings.Hidden_Foldout_MiscCategory);
debugCategory.AddMelonToggle(ModSettings.Debug_NetworkInbound);
debugCategory.AddMelonToggle(ModSettings.Debug_NetworkOutbound);
debugCategory.AddMelonToggle(ModSettings.Entry_FriendsOnly);
debugCategory.AddButton("Clear Thumbnail Cache", "Stickers-rubbish-bin", "Clear the cache of all loaded stickers.", ButtonStyle.TextWithIcon)
.OnPress += () => QuickMenuAPI.ShowConfirm("Clear Thumbnail Cache", "Are you sure you want to clear the Cohtml thumbnail cache for all stickers?",
() =>
{
StickerCache.ClearCache();
QuickMenuAPI.ShowAlertToast("Thumbnail cache cleared.", 2);
});
}
}

View file

@ -36,8 +36,8 @@ public static partial class BTKUIAddon
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); 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; openStickersFolderButton.OnPress += OnOpenStickersFolderButtonClick;
Button openMultiSelectionButton = _ourCategory.AddButton("Sticker SFX", "Stickers-headset", "Choose the SFX used when a sticker is placed.", ButtonStyle.TextWithIcon); Button openStickerSFXButton = _ourCategory.AddButton("Sticker SFX", "Stickers-headset", "Choose the SFX used when a sticker is placed.", ButtonStyle.TextWithIcon);
openMultiSelectionButton.OnPress += () => QuickMenuAPI.OpenMultiSelect(_sfxSelection); openStickerSFXButton.OnPress += () => QuickMenuAPI.OpenMultiSelect(_sfxSelection);
ToggleButton toggleDesktopKeybindButton = _ourCategory.AddToggle("Use Desktop Keybind", "Should the Desktop keybind be active.", ModSettings.Entry_UsePlaceBinding.Value); 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); Button openDesktopKeybindButton = _ourCategory.AddButton("Desktop Keybind", "Stickers-alphabet", "Choose the key binding to place stickers.", ButtonStyle.TextWithIcon);

View file

@ -66,7 +66,7 @@ public static partial class BTKUIAddon
Setup_StickersModCategory(); Setup_StickersModCategory();
Setup_StickerSelectionCategory(); Setup_StickerSelectionCategory();
Setup_DebugOptionsCategory(); Setup_OtherOptionsCategory();
} }
#endregion Setup #endregion Setup

View file

@ -18,6 +18,7 @@ public static partial class BTKUIAddon
private static Category _fileCategory; private static Category _fileCategory;
private static Category _folderCategory; private static Category _folderCategory;
private static TextBlock _noFilesTextBlock;
private const int MAX_BUTTONS = 512; // cohtml literally will start to explode private const int MAX_BUTTONS = 512; // cohtml literally will start to explode
private static Button[] _fileButtons = new Button[80]; // 100 files, will resize if needed private static Button[] _fileButtons = new Button[80]; // 100 files, will resize if needed
@ -53,6 +54,8 @@ public static partial class BTKUIAddon
// Setup categories // Setup categories
_folderCategory = _ourDirectoryBrowserPage.AddCategory("Subdirectories"); _folderCategory = _ourDirectoryBrowserPage.AddCategory("Subdirectories");
_fileCategory = _ourDirectoryBrowserPage.AddCategory("Images"); _fileCategory = _ourDirectoryBrowserPage.AddCategory("Images");
_noFilesTextBlock = _fileCategory.AddTextBlock("No images found in this directory. You can add your own images and subfolders to the `UserData/Stickers/` folder.");
_noFilesTextBlock.Hidden = true;
SetupFolderButtons(); SetupFolderButtons();
SetupFileButtons(); SetupFileButtons();
@ -88,6 +91,7 @@ public static partial class BTKUIAddon
string absolutePath = Path.Combine(_curDirectoryInfo.FullName, button.ButtonTooltip[5..]); string absolutePath = Path.Combine(_curDirectoryInfo.FullName, button.ButtonTooltip[5..]);
string relativePath = Path.GetRelativePath(_initialDirectory, absolutePath); string relativePath = Path.GetRelativePath(_initialDirectory, absolutePath);
StickerSystem.Instance.LoadImage(relativePath, _curSelectedSticker); StickerSystem.Instance.LoadImage(relativePath, _curSelectedSticker);
_rootPage.OpenPage(true); // close the directory browser to artificially limit loading speed
}; };
_fileButtons[i] = button; _fileButtons[i] = button;
} }
@ -162,12 +166,16 @@ public static partial class BTKUIAddon
return; return;
} }
_stickerSelectionButtonDoubleClickTime = Time.time; _stickerSelectionButtonDoubleClickTime = Time.time;
// quick menu notification
QuickMenuAPI.ShowAlertToast($"Selected sticker slot {index + 1}", 1);
} }
private static void OpenStickerSelectionForSlot(int index) private static void OpenStickerSelectionForSlot(int index)
{ {
if (IsPopulatingPage) return; if (IsPopulatingPage) return;
_curSelectedSticker = index; _curSelectedSticker = index;
_initialDirectory = StickerSystem.GetStickersFolderPath(); // creates folder if needed (lazy fix)
_curDirectoryInfo = new DirectoryInfo(_initialDirectory); _curDirectoryInfo = new DirectoryInfo(_initialDirectory);
_ourDirectoryBrowserPage.OpenPage(false, true); _ourDirectoryBrowserPage.OpenPage(false, true);
} }
@ -203,8 +211,9 @@ public static partial class BTKUIAddon
_folderCategory.Hidden = foldersCount == 0; _folderCategory.Hidden = foldersCount == 0;
_folderCategory.CategoryName = $"Subdirectories ({foldersCount})"; _folderCategory.CategoryName = $"Subdirectories ({foldersCount})";
_fileCategory.Hidden = filesCount == 0; //_fileCategory.Hidden = filesCount == 0;
_fileCategory.CategoryName = $"Images ({filesCount})"; _fileCategory.CategoryName = $"Images ({filesCount})";
_noFilesTextBlock.Hidden = filesCount > 0;
}); });
PopulateFolders(directories); PopulateFolders(directories);

View file

@ -11,7 +11,7 @@ public static class ModSettings
internal const string SM_SettingsCategory = "Stickers Mod"; internal const string SM_SettingsCategory = "Stickers Mod";
private const string SM_SelectionCategory = "Sticker Selection"; private const string SM_SelectionCategory = "Sticker Selection";
private const string DEBUG_SettingsCategory = "Debug Options"; private const string MISC_SettingsCategory = "Miscellaneous Options";
internal const int MaxStickerSlots = 4; internal const int MaxStickerSlots = 4;
@ -28,16 +28,13 @@ public static class ModSettings
internal static readonly MelonPreferences_Entry<bool> Hidden_Foldout_SelectionCategory = internal static readonly MelonPreferences_Entry<bool> Hidden_Foldout_SelectionCategory =
Category.CreateEntry("hidden_foldout_selection", true, is_hidden: true, display_name: SM_SelectionCategory, description: "Foldout state for Sticker selection."); Category.CreateEntry("hidden_foldout_selection", true, is_hidden: true, display_name: SM_SelectionCategory, description: "Foldout state for Sticker selection.");
internal static readonly MelonPreferences_Entry<bool> Hidden_Foldout_DebugCategory = internal static readonly MelonPreferences_Entry<bool> Hidden_Foldout_MiscCategory =
Category.CreateEntry("hidden_foldout_debug", false, is_hidden: true, display_name: DEBUG_SettingsCategory, description: "Foldout state for Debug settings."); Category.CreateEntry("hidden_foldout_miscellaneous", false, is_hidden: true, display_name: MISC_SettingsCategory, description: "Foldout state for Miscellaneous settings.");
#endregion Hidden Foldout Entries #endregion Hidden Foldout Entries
#region Stickers Mod Settings #region Stickers Mod Settings
internal static readonly MelonPreferences_Entry<bool> Entry_HapticsOnPlace =
Category.CreateEntry("haptics_on_place", true, "Haptics On Place", "Enable haptic feedback when placing stickers.");
internal static readonly MelonPreferences_Entry<float> Entry_PlayerUpAlignmentThreshold = internal static readonly MelonPreferences_Entry<float> Entry_PlayerUpAlignmentThreshold =
Category.CreateEntry("player_up_alignment_threshold", 20f, "Player Up Alignment Threshold", "The threshold the controller roll can be within to align perfectly with the player up vector. Set to 0f to always align to controller up."); Category.CreateEntry("player_up_alignment_threshold", 20f, "Player Up Alignment Threshold", "The threshold the controller roll can be within to align perfectly with the player up vector. Set to 0f to always align to controller up.");
@ -59,6 +56,9 @@ public static class ModSettings
description: "The name of the sticker selected for stickering.", description: "The name of the sticker selected for stickering.",
is_hidden: true); is_hidden: true);
internal static readonly MelonPreferences_Entry<bool> Entry_FriendsOnly =
Category.CreateEntry("friends_only", false, "Friends Only", "Only allow friends to use stickers.");
#endregion Stickers Mod Settings #endregion Stickers Mod Settings
#region Debug Settings #region Debug Settings

View file

@ -27,6 +27,6 @@ using System.Reflection;
namespace NAK.Stickers.Properties; namespace NAK.Stickers.Properties;
internal static class AssemblyInfoParams internal static class AssemblyInfoParams
{ {
public const string Version = "1.0.4"; public const string Version = "1.0.5";
public const string Author = "NotAKidoS"; public const string Author = "NotAKidoS";
} }

View file

@ -4,7 +4,7 @@
<TargetFramework>net48</TargetFramework> <TargetFramework>net48</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>TRACE;TRACE;UNITY_2017_1_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2019_3_OR_NEWER;USE_BURST;USE_NEWMATHS;USE_BURST_REALLY;</DefineConstants> <DefineConstants>TRACE;TRACE;UNITY_2017_1_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2019_3_OR_NEWER;USE_BURST;USE_NEWMATHS;USE_BURST_REALLY;USEDFORSTICKERMOD;</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Folder Include="ThirdParty\" /> <Folder Include="ThirdParty\" />

View file

@ -1,4 +1,5 @@
using NAK.Stickers.Properties; using ABI_RC.Core.Util.AnimatorManager;
using NAK.Stickers.Properties;
namespace NAK.Stickers.Networking; namespace NAK.Stickers.Networking;

View file

@ -1,4 +1,5 @@
using ABI_RC.Core.Savior; using ABI_RC.Core.Networking.IO.Social;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.ModNetwork; using ABI_RC.Systems.ModNetwork;
using NAK.Stickers.Utilities; using NAK.Stickers.Utilities;
using UnityEngine; using UnityEngine;
@ -16,9 +17,39 @@ public static partial class ModNetwork
#endregion Inbound Buffers #endregion Inbound Buffers
#region Reset Method
public static void Reset()
{
_textureChunkBuffers.Clear();
_receivedChunkCounts.Clear();
_expectedChunkCounts.Clear();
_textureMetadata.Clear();
LoggerInbound("ModNetwork inbound buffers and metadata have been reset.");
}
#endregion Reset Method
#region Inbound Methods #region Inbound Methods
private static bool ShouldReceiveFromSender(string sender)
{
if (_disallowedForSession.Contains(sender))
return false; // ignore messages from disallowed users
if (MetaPort.Instance.blockedUserIds.Contains(sender))
return false; // ignore messages from blocked users
if (ModSettings.Entry_FriendsOnly.Value && !Friends.FriendsWith(sender))
return false; // ignore messages from non-friends if friends only is enabled
return true;
}
private static void HandleMessageReceived(ModNetworkMessage msg) private static void HandleMessageReceived(ModNetworkMessage msg)
{
try
{ {
string sender = msg.Sender; string sender = msg.Sender;
msg.Read(out byte msgTypeRaw); msg.Read(out byte msgTypeRaw);
@ -26,11 +57,8 @@ public static partial class ModNetwork
if (!Enum.IsDefined(typeof(MessageType), msgTypeRaw)) if (!Enum.IsDefined(typeof(MessageType), msgTypeRaw))
return; return;
if (_disallowedForSession.Contains(sender)) if (!ShouldReceiveFromSender(sender))
return; // ignore messages from disallowed users return;
if (MetaPort.Instance.blockedUserIds.Contains(sender))
return; // ignore messages from blocked users
LoggerInbound($"Received message from {msg.Sender}, Type: {(MessageType)msgTypeRaw}"); LoggerInbound($"Received message from {msg.Sender}, Type: {(MessageType)msgTypeRaw}");
@ -68,6 +96,12 @@ public static partial class ModNetwork
LoggerInbound($"Invalid message type received: {msgTypeRaw}"); LoggerInbound($"Invalid message type received: {msgTypeRaw}");
break; break;
} }
}
catch (Exception e)
{
LoggerInbound($"Error handling message from {msg.Sender}: {e.Message}", true);
}
} }
private static void HandlePlaceSticker(ModNetworkMessage msg) private static void HandlePlaceSticker(ModNetworkMessage msg)

View file

@ -9,13 +9,12 @@ namespace NAK.Stickers
{ {
private const float DECAL_SIZE = 0.25f; private const float DECAL_SIZE = 0.25f;
private static readonly int s_EmissionStrengthID = Shader.PropertyToID("_EmissionStrength"); public readonly string PlayerId;
public float DeathTime; // when a remote player leaves, we need to kill their stickers
public float LastPlacedTime; public float LastPlacedTime;
public float DeathTime = -1f;
private Vector3 _lastPlacedPosition = Vector3.zero; private Vector3 _lastPlacedPosition = Vector3.zero;
public readonly bool IsLocal;
private readonly DecalType _decal; private readonly DecalType _decal;
private readonly DecalSpawner[] _decalSpawners; private readonly DecalSpawner[] _decalSpawners;
@ -23,9 +22,9 @@ namespace NAK.Stickers
private readonly Material[] _materials; private readonly Material[] _materials;
private readonly AudioSource _audioSource; private readonly AudioSource _audioSource;
public StickerData(bool isLocal, int decalSpawnersCount) public StickerData(string playerId, int decalSpawnersCount)
{ {
IsLocal = isLocal; PlayerId = playerId;
_decal = ScriptableObject.CreateInstance<DecalType>(); _decal = ScriptableObject.CreateInstance<DecalType>();
_decalSpawners = new DecalSpawner[decalSpawnersCount]; _decalSpawners = new DecalSpawner[decalSpawnersCount];
@ -54,7 +53,7 @@ namespace NAK.Stickers
_audioSource.maxDistance = 5f; _audioSource.maxDistance = 5f;
_audioSource.minDistance = 1f; _audioSource.minDistance = 1f;
_audioSource.outputAudioMixerGroup = RootLogic.Instance.propSfx; // props are close enough to stickers _audioSource.outputAudioMixerGroup = RootLogic.Instance.propSfx; // props are close enough to stickers
if (isLocal) Object.DontDestroyOnLoad(_audioSource.gameObject); // keep audio source through world transitions if (PlayerId == StickerSystem.PlayerLocalId) Object.DontDestroyOnLoad(_audioSource.gameObject); // keep audio source through world transitions
} }
public Guid GetTextureHash(int spawnerIndex = 0) public Guid GetTextureHash(int spawnerIndex = 0)
@ -95,8 +94,6 @@ namespace NAK.Stickers
? FilterMode.Bilinear // smear it cause its fat ? FilterMode.Bilinear // smear it cause its fat
: FilterMode.Point; // my minecraft skin looked shit : FilterMode.Point; // my minecraft skin looked shit
if (IsLocal) StickerMod.Logger.Msg($"Set texture filter mode to: {texture.filterMode}");
Material material = _materials[spawnerIndex]; Material material = _materials[spawnerIndex];
// Destroy the previous texture to avoid memory leaks // Destroy the previous texture to avoid memory leaks
@ -117,9 +114,9 @@ namespace NAK.Stickers
Transform rootObject = null; Transform rootObject = null;
GameObject hitGO = hit.transform.gameObject; GameObject hitGO = hit.transform.gameObject;
if (hitGO.TryGetComponent(out Rigidbody _) if (hitGO.scene.buildIndex == 4 // additive (dynamic) content
|| hitGO.TryGetComponent(out Animator _) || hitGO.TryGetComponent(out Animator _) // potentially movable
|| hitGO.scene.buildIndex == 4) // additive (dynamic) content || hitGO.GetComponentInParent<Rigidbody>() != null) // movable
rootObject = hitGO.transform; rootObject = hitGO.transform;
_lastPlacedPosition = hit.point; _lastPlacedPosition = hit.point;
@ -128,7 +125,7 @@ namespace NAK.Stickers
// Add decal to the specified spawner // Add decal to the specified spawner
_decalSpawners[spawnerIndex].AddDecal( _decalSpawners[spawnerIndex].AddDecal(
_lastPlacedPosition, Quaternion.LookRotation(forwardDirection, upDirection), _lastPlacedPosition, Quaternion.LookRotation(forwardDirection, upDirection),
hit.collider.gameObject, hitGO,
DECAL_SIZE, DECAL_SIZE, 1f, 1f, 0f, rootObject); DECAL_SIZE, DECAL_SIZE, 1f, 1f, 0f, rootObject);
} }
@ -164,6 +161,7 @@ namespace NAK.Stickers
_decalSpawners[i].movableGroups.Clear(); _decalSpawners[i].movableGroups.Clear();
// Clean up textures and materials // Clean up textures and materials
if (_materials[i] == null) continue;
if (_materials[i].mainTexture != null) Object.Destroy(_materials[i].mainTexture); if (_materials[i].mainTexture != null) Object.Destroy(_materials[i].mainTexture);
Object.Destroy(_materials[i]); Object.Destroy(_materials[i]);
} }

View file

@ -150,5 +150,10 @@ public partial class StickerSystem
return s_StickersFolderPath; return s_StickersFolderPath;
} }
public static void EnsureStickersFolderExists()
{
if (!Directory.Exists(s_StickersFolderPath)) Directory.CreateDirectory(s_StickersFolderPath);
}
#endregion Image Loading #endregion Image Loading
} }

View file

@ -1,5 +1,8 @@
using ABI_RC.Core.UI; using ABI_RC.Core.IO;
using ABI_RC.Core.Networking.IO.Instancing;
using ABI_RC.Core.UI;
using ABI_RC.Systems.GameEventSystem; using ABI_RC.Systems.GameEventSystem;
using NAK.Stickers.Networking;
using NAK.Stickers.Utilities; using NAK.Stickers.Utilities;
using UnityEngine; using UnityEngine;
@ -22,7 +25,7 @@ public partial class StickerSystem
DecalManager.SetPreferredMode(DecalUtils.Mode.GPU, false, 0); DecalManager.SetPreferredMode(DecalUtils.Mode.GPU, false, 0);
// ensure cache folder exists // ensure cache folder exists
if (!Directory.Exists(s_StickersFolderPath)) Directory.CreateDirectory(s_StickersFolderPath); EnsureStickersFolderExists();
// listen for game events // listen for game events
CVRGameEventSystem.Initialization.OnPlayerSetupStart.AddListener(Instance.OnPlayerSetupStart); CVRGameEventSystem.Initialization.OnPlayerSetupStart.AddListener(Instance.OnPlayerSetupStart);
@ -30,6 +33,36 @@ public partial class StickerSystem
#endregion Singleton #endregion Singleton
#region Callback Registration
private void OnPlayerSetupStart()
{
CVRGameEventSystem.World.OnUnload.AddListener(_ => OnWorldUnload());
CVRGameEventSystem.Instance.OnConnected.AddListener((_) => { if (!Instances.IsReconnecting) OnInitialConnection(); });
CVRGameEventSystem.Player.OnJoinEntity.AddListener(Instance.OnPlayerJoined);
CVRGameEventSystem.Player.OnLeaveEntity.AddListener(Instance.OnPlayerLeft);
SchedulerSystem.AddJob(Instance.OnOccasionalUpdate, 10f, 1f);
LoadAllImagesAtStartup();
}
#endregion Callback Registration
#region Game Events
private void OnInitialConnection()
{
ClearStickersSelf(); // clear stickers on remotes just in case we rejoined
ModNetwork.Reset(); // reset network buffers and metadata
}
private void OnWorldUnload()
{
CleanupAllButSelf(); // release all stickers except for self
}
#endregion Game Events
#region Data #region Data
private int _selectedStickerSlot; private int _selectedStickerSlot;
@ -63,9 +96,7 @@ public partial class StickerSystem
private const float StickerKillTime = 30f; private const float StickerKillTime = 30f;
private const float StickerCooldown = 0.2f; private const float StickerCooldown = 0.2f;
private readonly Dictionary<string, StickerData> _playerStickers = new(); private readonly Dictionary<string, StickerData> _playerStickers = new();
private const string PlayerLocalId = "_PLAYERLOCAL"; internal const string PlayerLocalId = "_PLAYERLOCAL";
private readonly List<StickerData> _deadStickerPool = new(); // for cleanup on player leave
#endregion Data #endregion Data
} }

View file

@ -1,7 +1,4 @@
using ABI_RC.Core.IO; using ABI_RC.Core.Player;
using ABI_RC.Core.Networking.IO.Instancing;
using ABI_RC.Core.Player;
using ABI_RC.Systems.GameEventSystem;
using UnityEngine; using UnityEngine;
namespace NAK.Stickers; namespace NAK.Stickers;
@ -10,17 +7,6 @@ public partial class StickerSystem
{ {
#region Player Callbacks #region Player Callbacks
private void OnPlayerSetupStart()
{
CVRGameEventSystem.World.OnUnload.AddListener(_ => Instance.CleanupAllButSelf());
CVRGameEventSystem.Instance.OnConnected.AddListener((_) => { if (!Instances.IsReconnecting) Instance.ClearStickersSelf(); });
CVRGameEventSystem.Player.OnJoinEntity.AddListener(Instance.OnPlayerJoined);
CVRGameEventSystem.Player.OnLeaveEntity.AddListener(Instance.OnPlayerLeft);
SchedulerSystem.AddJob(Instance.OnOccasionalUpdate, 10f, 1f);
LoadAllImagesAtStartup();
}
private void OnPlayerJoined(CVRPlayerEntity playerEntity) private void OnPlayerJoined(CVRPlayerEntity playerEntity)
{ {
if (!_playerStickers.TryGetValue(playerEntity.Uuid, out StickerData stickerData)) if (!_playerStickers.TryGetValue(playerEntity.Uuid, out StickerData stickerData))
@ -28,7 +14,6 @@ public partial class StickerSystem
stickerData.DeathTime = -1f; stickerData.DeathTime = -1f;
stickerData.SetAlpha(1f); stickerData.SetAlpha(1f);
_deadStickerPool.Remove(stickerData);
} }
private void OnPlayerLeft(CVRPlayerEntity playerEntity) private void OnPlayerLeft(CVRPlayerEntity playerEntity)
@ -38,23 +23,14 @@ public partial class StickerSystem
stickerData.DeathTime = Time.time + StickerKillTime; stickerData.DeathTime = Time.time + StickerKillTime;
stickerData.SetAlpha(1f); stickerData.SetAlpha(1f);
_deadStickerPool.Add(stickerData);
} }
private void OnOccasionalUpdate() private void OnOccasionalUpdate()
{
if (_deadStickerPool.Count == 0)
return;
for (var i = _deadStickerPool.Count - 1; i >= 0; i--)
{ {
float currentTime = Time.time; float currentTime = Time.time;
StickerData stickerData = _deadStickerPool[i]; for (int i = 0; i < _playerStickers.Values.Count; i++)
if (stickerData == null)
{ {
_deadStickerPool.RemoveAt(i); StickerData stickerData = _playerStickers.Values.ElementAt(i);
continue;
}
if (stickerData.DeathTime < 0f) if (stickerData.DeathTime < 0f)
continue; continue;
@ -65,15 +41,8 @@ public partial class StickerSystem
continue; continue;
} }
for (int j = 0; j < _playerStickers.Values.Count; j++)
{
if (_playerStickers.Values.ElementAt(j) != stickerData) continue;
_playerStickers.Remove(_playerStickers.Keys.ElementAt(j));
break;
}
_deadStickerPool.RemoveAt(i);
stickerData.Cleanup(); stickerData.Cleanup();
_playerStickers.Remove(stickerData.PlayerId);
} }
} }

View file

@ -15,7 +15,7 @@ public partial class StickerSystem
if (_playerStickers.TryGetValue(playerId, out StickerData stickerData)) if (_playerStickers.TryGetValue(playerId, out StickerData stickerData))
return stickerData; return stickerData;
stickerData = new StickerData(playerId == PlayerLocalId, ModSettings.MaxStickerSlots); stickerData = new StickerData(playerId, ModSettings.MaxStickerSlots);
_playerStickers[playerId] = stickerData; _playerStickers[playerId] = stickerData;
return stickerData; return stickerData;
} }
@ -40,8 +40,6 @@ public partial class StickerSystem
if (!PlaceStickerSelf(transform.position, transform.forward, targetUp)) if (!PlaceStickerSelf(transform.position, transform.forward, targetUp))
return; return;
// do haptic if not lame
if (!ModSettings.Entry_HapticsOnPlace.Value) return;
CVRInputManager.Instance.Vibrate(0f, 0.1f, 10f, 0.1f, hand); CVRInputManager.Instance.Vibrate(0f, 0.1f, 10f, 0.1f, hand);
} }
@ -67,6 +65,10 @@ public partial class StickerSystem
10f, LayerMask, QueryTriggerInteraction.Ignore)) 10f, LayerMask, QueryTriggerInteraction.Ignore))
return false; return false;
// if gameobject name starts with [NoSticker] then don't place sticker
if (hit.transform.gameObject.name.StartsWith("[NoSticker]"))
return false;
stickerData.Place(hit, alignWithNormal ? -hit.normal : forward, up, stickerSlot); stickerData.Place(hit, alignWithNormal ? -hit.normal : forward, up, stickerSlot);
stickerData.PlayAudio(); stickerData.PlayAudio();
return true; return true;
@ -78,6 +80,12 @@ public partial class StickerSystem
ModNetwork.SendClearAllStickers(); ModNetwork.SendClearAllStickers();
} }
public void ClearStickerSelf(int stickerSlot)
{
ClearStickersForPlayer(PlayerLocalId, stickerSlot);
ModNetwork.SendClearSticker(stickerSlot);
}
private void ClearStickersForPlayer(string playerId) private void ClearStickersForPlayer(string playerId)
{ {
if (!_playerStickers.TryGetValue(playerId, out StickerData stickerData)) if (!_playerStickers.TryGetValue(playerId, out StickerData stickerData))
@ -100,6 +108,7 @@ public partial class StickerSystem
texture.LoadImage(imageBytes); texture.LoadImage(imageBytes);
texture.Compress(true); // noachi said to do texture.Compress(true); // noachi said to do
ClearStickerSelf(stickerSlot); // clear placed stickers in-scene so we can't replace an entire wall at once
OnPlayerStickerTextureReceived(PlayerLocalId, Guid.Empty, texture, stickerSlot); OnPlayerStickerTextureReceived(PlayerLocalId, Guid.Empty, texture, stickerSlot);
ModNetwork.SetTexture(stickerSlot, imageBytes); ModNetwork.SetTexture(stickerSlot, imageBytes);
} }
@ -138,7 +147,7 @@ public partial class StickerSystem
foreach ((_, StickerData data) in _playerStickers) foreach ((_, StickerData data) in _playerStickers)
{ {
if (data.IsLocal) data.Clear(); if (data == localStickerData) data.Clear();
else data.Cleanup(); else data.Cleanup();
} }
@ -146,15 +155,5 @@ public partial class StickerSystem
_playerStickers[PlayerLocalId] = localStickerData; _playerStickers[PlayerLocalId] = localStickerData;
} }
public void SelectStickerSlot(int stickerSlot)
{
SelectedStickerSlot = Mathf.Clamp(stickerSlot, 0, ModSettings.MaxStickerSlots - 1);
}
public int GetCurrentStickerSlot()
{
return SelectedStickerSlot;
}
#endregion Sticker Lifecycle #endregion Sticker Lifecycle
} }

View file

@ -66,6 +66,13 @@ public static class StickerCache
} }
} }
public static void ClearCache()
{
if (!Directory.Exists(ThumbnailPath)) return;
Directory.Delete(ThumbnailPath, true);
StickerMod.Logger.Msg("Cleared thumbnail cache.");
}
#endregion Public Methods #endregion Public Methods
#region Private Methods #region Private Methods