Achievement management for the soundboard. Tracks local one-shot toasts and cookie persistence, detects milestones from voice counts, clicks, loop plays, live playback and pad presses, shows local toasts, and queues platform achievement unlocks (Achievements.Unlock) with retry/backoff and persistent platform-synced cookies.
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox.Services;
namespace SSoundboard;
/// <summary>
/// Local achievement toasts + cookie persistence + package Achievements.Unlock.
///
/// Local toast/cookies and platform unlocks are independent:
/// - Local = one-time toast + "earned" cookie
/// - Platform = Achievements.Unlock(ident) with retries + persistent "synced" cookie
/// So a toast can never "use up" an unlock without the account receiving it.
///
/// Register matching idents on the package dashboard (Manual unlock type).
/// </summary>
public static class SoundBoardAchievements
{
public const string FiveVoicesAchievementId = "five_deep";
public const string TenVoicesAchievementId = "ten_deep";
public const string FifteenVoicesAchievementId = "fifteen_deep";
public const string TwentyFiveVoicesAchievementId = "twenty_five_deep";
public const string FiftyVoicesAchievementId = "fifty_deep";
public const string SixtyFourVoicesAchievementId = "sixty_four_deep";
public const string ErrorAchievementId = "task_failed_successfully";
public const string StopItAchievementId = "stop_it_100";
public const string FlipperReturnsAchievementId = "flipper_returns_to_ocean";
public const string IllBeBackAchievementId = "ill_be_back";
public const string HastaLaVistaAchievementId = "hasta_la_vista";
public const string ChoppaAchievementId = "get_to_da_choppa";
public const string NotATumorAchievementId = "its_not_a_tumor";
public const string VineBoomAchievementId = "vine_boom_10";
public const string BruhAchievementId = "bruh_50";
public const string YoureFiredAchievementId = "youre_fired";
public const string PanicButtonAchievementId = "panic_button";
public const string SerialSilencerAchievementId = "serial_silencer";
public const string PoliticsJunkieAchievementId = "politics_junkie";
public const string ArnoldForeverAchievementId = "arnold_forever";
public const string FullStackArnoldAchievementId = "full_stack_arnold";
public const string GasLeakAchievementId = "gas_leak";
public const string TripleThreatAchievementId = "triple_threat_nature";
public const int StopItRequired = 100;
public const int VineBoomRequired = 10;
public const int BruhRequired = 50;
public const int KillAllSerialRequired = 50;
public const int PoliticsJunkieRequired = 100;
public const int ArnoldForeverRequired = 250;
const string KillAllCountCookieKey = "ssoundboard.kill-all-count";
/// <summary>Highest concurrent voice count this session (for milestones).</summary>
public static int PeakVoiceCount { get; private set; }
static long _killAllCount = -1;
static readonly VoiceMilestone[] VoiceMilestones =
{
// Highest first so the toast shows the biggest new unlock when several fire at once.
new( 64, SixtyFourVoicesAchievementId, "ssoundboard.ach.sixty_four_deep", "Sixty-Four Deep",
"64 voices — the hard cap. The meter maxed out. Reality filed a noise complaint." ),
new( 50, FiftyVoicesAchievementId, "ssoundboard.ach.fifty_deep", "Fifty Deep",
"50 voices at once. The chaos meter has left the building. Hearing is optional now." ),
new( 25, TwentyFiveVoicesAchievementId, "ssoundboard.ach.twenty_five_deep", "Twenty-Five Deep",
"25 simultaneous voices. Neighbors are filing paperwork. The meter is glowing with pride." ),
new( 15, FifteenVoicesAchievementId, "ssoundboard.ach.fifteen_deep", "Fifteen Deep",
"15 voices stacked. You've graduated from chaos to performance art." ),
new( 10, TenVoicesAchievementId, "ssoundboard.ach.ten_deep", "Ten Deep",
"10 voices stacked. You've left \"soundboard\" and entered \"air raid\"." ),
new( 5, FiveVoicesAchievementId, "ssoundboard.ach.five_deep", "Five Deep",
"You stacked 5 voices on the chaos meter. Your ears filed a formal complaint. The meter is proud." ),
};
/// <summary>Lifetime pad-click milestones (highest first for batch unlock toasts).</summary>
static readonly ClickMilestone[] ClickMilestones =
{
new( 100_000_000_000L, "click_100b", "ssoundboard.ach.click_100b", "Heat Death of the Board",
"100,000,000,000 clicks. The universe ended. You kept mashing. Respect, monster." ),
new( 100_000_000L, "click_100m", "ssoundboard.ach.click_100m", "Hundred Million Club",
"100,000,000 clicks. Your finger filed for workers' comp. The board salutes you." ),
new( 100_000L, "click_100k", "ssoundboard.ach.click_100k", "Century of Spam",
"100,000 clicks. You are no longer a player. You are infrastructure." ),
new( 10_000L, "click_10k", "ssoundboard.ach.click_10k", "Ten Thousand Strong",
"10,000 clicks. The pads know your name. They fear it." ),
new( 1_000L, "click_1k", "ssoundboard.ach.click_1k", "Thousand Cuts",
"1,000 clicks. Dedication, delusion, or both. The meter is taking notes." ),
new( 100L, "click_100", "ssoundboard.ach.click_100", "Century Clicker",
"100 clicks. You're officially in too deep to quit now." ),
new( 50L, "click_50", "ssoundboard.ach.click_50", "Fifty Fires",
"50 clicks. Warming up. The chaos is just getting started." ),
new( 25L, "click_25", "ssoundboard.ach.click_25", "Quarter Century",
"25 clicks. A respectable warm-up mash session." ),
new( 10L, "click_10", "ssoundboard.ach.click_10", "Double Digits",
"10 clicks. The board has noticed you. So have the neighbors." ),
new( 1L, "click_1", "ssoundboard.ach.click_1", "First Blood",
"You pressed a button. There is no going back." ),
};
/// <summary>Lifetime LOOP re-fire milestones (highest first).</summary>
static readonly LoopMilestone[] LoopMilestones =
{
new( 1_000L, "loop_1k", "ssoundboard.ach.loop_1k", "Infinite Jest",
"1,000 loop re-fires. Time is a flat circle and it sounds like your soundboard." ),
new( 100L, "loop_100", "ssoundboard.ach.loop_100", "Stuck on Repeat",
"100 loop re-fires. The LOOP button has adopted you." ),
new( 50L, "loop_50", "ssoundboard.ach.loop_50", "Half-Century Loop",
"50 loop re-fires. Repetition is a feature, not a bug." ),
new( 10L, "loop_10", "ssoundboard.ach.loop_10", "Encore Machine",
"10 loop re-fires. Once was not enough. Ten was getting somewhere." ),
new( 1L, "loop_1", "ssoundboard.ach.loop_1", "First Echo",
"A sound came back for round two. Welcome to LOOP mode." ),
};
const string ErrorCookieKey = "ssoundboard.ach.task_failed_successfully";
const string ErrorTitle = "Task Failed Successfully";
const string ErrorBody =
"You pressed a button and invented a brand new error. IT departments everywhere just felt a disturbance.";
const string StopItCookieKey = "ssoundboard.ach.stop_it_100";
const string StopItTitle = "I Said STOP IT";
const string StopItBody =
"You mashed Arnold's STOP IT button 100 times. He never stopped. You never stopped. The button is tired of both of you.";
const string FlipperCookieKey = "ssoundboard.ach.flipper_returns_to_ocean";
const string FlipperTitle = "Flipper Returns to Ocean";
const string FlipperBody =
"Dolphin and ocean at the same time. Flipper found the water. The board approves of this nature documentary.";
// One-shot pad / action achievements (id, cookie, title, body).
static readonly SpecialAchievement[] SpecialAchievements =
{
new( IllBeBackAchievementId, "ssoundboard.ach.ill_be_back", "I'll Be Back",
"You pressed I'll Be Back. The board promises nothing about the sequel." ),
new( HastaLaVistaAchievementId, "ssoundboard.ach.hasta_la_vista", "Hasta La Vista, Baby",
"Hasta la vista, baby. The pad is liquidated. The vibe is terminatored." ),
new( ChoppaAchievementId, "ssoundboard.ach.get_to_da_choppa", "Get To Da Choppa",
"GET TO DA CHOPPA. Evacuation protocol: mash more pads." ),
new( NotATumorAchievementId, "ssoundboard.ach.its_not_a_tumor", "It's Not a Tumor",
"It's not a tumor. It's a lifestyle. And a button." ),
new( VineBoomAchievementId, "ssoundboard.ach.vine_boom_10", "Industrial Strength Boom",
"Vine boom ×10. Bass that walks into rooms uninvited." ),
new( BruhAchievementId, "ssoundboard.ach.bruh_50", "Professional Bruh",
"50 bruhs. You've said everything and nothing. Peak discourse." ),
new( YoureFiredAchievementId, "ssoundboard.ach.youre_fired", "You're Fired",
"You're fired. The pad. The mood. Possibly the neighbors' goodwill." ),
new( PanicButtonAchievementId, "ssoundboard.ach.panic_button", "Panic Button",
"First KILL ALL. Silence falls. The board knows what you did." ),
new( SerialSilencerAchievementId, "ssoundboard.ach.serial_silencer", "Serial Silencer",
"KILL ALL ×50. You don't play the board — you censor it." ),
new( PoliticsJunkieAchievementId, "ssoundboard.ach.politics_junkie", "Politics Junkie",
"100 politics pads. Democracy dies in darkness; you brought the soundboard." ),
new( ArnoldForeverAchievementId, "ssoundboard.ach.arnold_forever", "Arnold Forever",
"250 Arnold presses. There is no board without the Governator." ),
new( FullStackArnoldAchievementId, "ssoundboard.ach.full_stack_arnold", "Full Stack Arnold",
"5+ Arnold clips at once. Peak Austrian multi-threading." ),
new( GasLeakAchievementId, "ssoundboard.ach.gas_leak", "Gas Leak",
"5+ GAS pads stacked. Open a window. Or don't. Commit." ),
new( TripleThreatAchievementId, "ssoundboard.ach.triple_threat_nature", "Triple Threat Nature Doc",
"Dolphin + ocean + rain together. Nature is healing (loudly)." ),
};
const string PlatformSyncedPrefix = "ssoundboard.ach.platform.";
// Local toast / cookie (one-time UI).
static readonly HashSet<string> _unlockedLocal = new( StringComparer.OrdinalIgnoreCase );
// Platform unlocks confirmed this process (also persisted under PlatformSyncedPrefix).
static readonly HashSet<string> _platformSynced = new( StringComparer.OrdinalIgnoreCase );
// One Unlock attempt per tick — avoids multi-unlock frame drops.
static readonly Queue<string> _platformQueue = new();
static readonly HashSet<string> _platformQueued = new( StringComparer.OrdinalIgnoreCase );
static readonly Dictionary<string, int> _platformAttempts = new( StringComparer.OrdinalIgnoreCase );
static readonly Dictionary<string, float> _platformNextTryAt = new( StringComparer.OrdinalIgnoreCase );
const int MaxPlatformAttempts = 40; // plenty — boot can fail for seconds
const float PlatformRetryBaseSec = 1.5f; // backoff base
const float PeriodicResyncInterval = 45f; // re-queue anything still unsynced
const float InitialSyncDelay = 2f; // let Live Services wake up
static RealTimeSince _sinceStart;
static RealTimeSince _sincePeriodicResync;
static bool _bootResyncDone;
static bool _started;
public static bool ToastVisible { get; private set; }
public static string ToastTitle { get; private set; } = "";
public static string ToastBody { get; private set; } = "";
public static RealTimeSince ToastAge { get; private set; }
public static event Action StateChanged;
/// <summary>
/// Called whenever concurrent voice count changes (pad press OR loop tick stacking).
/// Uses a session high-water mark so brief spikes still count.
/// </summary>
public static void OnVoiceCountChanged( int voiceCount )
{
if ( voiceCount > PeakVoiceCount )
PeakVoiceCount = voiceCount;
var check = Math.Max( voiceCount, PeakVoiceCount );
if ( check < 5 )
return;
string toastTitle = null;
string toastBody = null;
foreach ( var milestone in VoiceMilestones )
{
if ( check < milestone.Required )
continue;
// Always queue platform — even if local toast already fired earlier.
RequestPlatformUnlock( milestone.Id );
if ( !TryUnlockLocal( milestone.Id, milestone.CookieKey ) )
continue;
if ( toastTitle is null )
{
toastTitle = milestone.Title;
toastBody = $"{milestone.Body} ({check} voices peak.)";
}
}
if ( toastTitle is not null )
ShowToast( toastTitle, toastBody );
}
/// <summary>
/// Live-voice combos: Flipper, Full Stack Arnold, Gas Leak, Triple Threat Nature.
/// </summary>
public static void OnLivePlaybackChanged( IEnumerable<string> liveSoundIds, IEnumerable<string> liveLabels )
{
var ids = liveSoundIds as IList<string> ?? liveSoundIds?.ToList() ?? (IList<string>)Array.Empty<string>();
var labels = liveLabels as IList<string> ?? liveLabels?.ToList() ?? (IList<string>)Array.Empty<string>();
if ( LiveContains( ids, labels, "dolphin" ) && LiveContains( ids, labels, "ocean" ) )
{
RequestPlatformUnlock( FlipperReturnsAchievementId );
TryUnlock( FlipperReturnsAchievementId, FlipperCookieKey, FlipperTitle, FlipperBody );
}
if ( LiveContains( ids, labels, "dolphin" )
&& LiveContains( ids, labels, "ocean" )
&& LiveContains( ids, labels, "rain" ) )
{
UnlockSpecial( TripleThreatAchievementId );
}
if ( CountLiveFolder( ids, "arnold" ) >= 5 )
UnlockSpecial( FullStackArnoldAchievementId );
if ( CountLiveGas( ids, labels ) >= 5 )
UnlockSpecial( GasLeakAchievementId );
}
/// <summary>Lifetime pad presses across the whole board.</summary>
public static void OnTotalClicksChanged( long totalClicks )
{
if ( totalClicks < 1 )
return;
string toastTitle = null;
string toastBody = null;
foreach ( var milestone in ClickMilestones )
{
if ( totalClicks < milestone.Required )
continue;
RequestPlatformUnlock( milestone.Id );
if ( !TryUnlockLocal( milestone.Id, milestone.CookieKey ) )
continue;
if ( toastTitle is null )
{
toastTitle = milestone.Title;
toastBody = $"{milestone.Body} ({FormatCount( totalClicks )} total clicks.)";
}
}
if ( toastTitle is not null )
ShowToast( toastTitle, toastBody );
}
/// <summary>Lifetime LOOP layer re-fires (timer repeats while LOOP is on).</summary>
public static void OnLoopPlaysChanged( long totalLoopPlays )
{
if ( totalLoopPlays < 1 )
return;
string toastTitle = null;
string toastBody = null;
foreach ( var milestone in LoopMilestones )
{
if ( totalLoopPlays < milestone.Required )
continue;
// Always queue platform — independent of local toast (same as clicks / fifty_deep).
RequestPlatformUnlock( milestone.Id );
if ( !TryUnlockLocal( milestone.Id, milestone.CookieKey ) )
continue;
if ( toastTitle is null )
{
toastTitle = milestone.Title;
toastBody = $"{milestone.Body} ({FormatCount( totalLoopPlays )} loop plays.)";
}
}
if ( toastTitle is not null )
ShowToast( toastTitle, toastBody );
}
public static void OnCreatedError( string padLabel = null )
{
var body = string.IsNullOrWhiteSpace( padLabel )
? ErrorBody
: $"\"{padLabel}\" yeeted itself into the void. {ErrorBody}";
RequestPlatformUnlock( ErrorAchievementId );
TryUnlock( ErrorAchievementId, ErrorCookieKey, ErrorTitle, body );
}
public static void OnPadPressed( SoundPad pad )
{
if ( pad is null || string.IsNullOrWhiteSpace( pad.SoundId ) )
return;
// Arnold one-shots.
if ( MatchesPad( pad, "ill-be-back", "ill be back", "illbeback", "i'll be back", "i will be back" ) )
UnlockSpecial( IllBeBackAchievementId );
if ( MatchesPad( pad, "hasta-la-vista", "hasta la vista", "hastalavista" ) )
UnlockSpecial( HastaLaVistaAchievementId );
if ( MatchesPad( pad, "get-to-da-choppa", "get to da choppa", "choppa", "get-to-the-choppa" ) )
UnlockSpecial( ChoppaAchievementId );
if ( MatchesPad( pad, "its-not-a-tumor", "it's not a tumor", "not-a-tumor", "not a tumor", "tumor" ) )
UnlockSpecial( NotATumorAchievementId );
// You're fired (Trump / Apprentice memes).
if ( MatchesPad( pad, "youre-fired", "you're fired", "you-are-fired", "donald-trump-fired", "trump-fired" )
|| (PadHaystack( pad ).Contains( "fired", StringComparison.OrdinalIgnoreCase )
&& (PadHaystack( pad ).Contains( "trump", StringComparison.OrdinalIgnoreCase )
|| PadHaystack( pad ).Contains( "youre", StringComparison.OrdinalIgnoreCase )
|| PadHaystack( pad ).Contains( "you're", StringComparison.OrdinalIgnoreCase )
|| PadHaystack( pad ).Contains( "you are", StringComparison.OrdinalIgnoreCase ))) )
UnlockSpecial( YoureFiredAchievementId );
// Count-based (only re-sum when this press could advance the counter).
if ( MatchesPad( pad, "vine-boom", "vine boom", "vineboom" ) )
{
if ( SumStemContains( "vine-boom", "vine boom", "vineboom" ) >= VineBoomRequired )
UnlockSpecial( VineBoomAchievementId );
}
if ( MatchesPad( pad, "bruh" ) )
{
if ( SumStemContains( "bruh" ) >= BruhRequired )
UnlockSpecial( BruhAchievementId );
}
var idPath = pad.SoundId.Replace( '\\', '/' );
if ( idPath.Contains( "/politics/", StringComparison.OrdinalIgnoreCase )
|| idPath.StartsWith( "sounds/politics/", StringComparison.OrdinalIgnoreCase ) )
{
if ( SumFolderPlays( "politics" ) >= PoliticsJunkieRequired )
UnlockSpecial( PoliticsJunkieAchievementId );
}
if ( idPath.Contains( "/arnold/", StringComparison.OrdinalIgnoreCase )
|| idPath.StartsWith( "sounds/arnold/", StringComparison.OrdinalIgnoreCase ) )
{
if ( SumFolderPlays( "arnold" ) >= ArnoldForeverRequired )
UnlockSpecial( ArnoldForeverAchievementId );
}
if ( !IsStopItPad( pad ) )
return;
var count = SoundPlayTracker.GetCount( pad.SoundId );
count = Math.Max( count, SumStopItPlays() );
if ( count < StopItRequired )
return;
RequestPlatformUnlock( StopItAchievementId );
TryUnlock( StopItAchievementId, StopItCookieKey, StopItTitle, $"{StopItBody} ({count}× and counting.)" );
}
/// <summary>KILL ALL pressed — pass how many voices were silenced (0 = noop spam).</summary>
public static void OnKillAll( int silencedVoices )
{
if ( silencedVoices <= 0 )
return;
EnsureKillAllLoaded();
_killAllCount++;
try { Game.Cookies.Set( KillAllCountCookieKey, _killAllCount ); }
catch { /* session-only */ }
if ( _killAllCount >= 1 )
UnlockSpecial( PanicButtonAchievementId );
if ( _killAllCount >= KillAllSerialRequired )
UnlockSpecial( SerialSilencerAchievementId );
}
public static void Tick()
{
if ( !_started )
{
_started = true;
_sinceStart = 0;
_sincePeriodicResync = 0;
}
// Delayed boot resync — Live Services often aren't ready on the first frames.
if ( !_bootResyncDone && _sinceStart >= InitialSyncDelay )
{
_bootResyncDone = true;
FullSyncFromProgress( forceRequeue: true );
Log.Info( "[S&Soundboard] Achievement platform sync started." );
}
// Keep pushing any local unlocks that never got a platform ack this install.
if ( _bootResyncDone && _sincePeriodicResync >= PeriodicResyncInterval )
{
_sincePeriodicResync = 0;
FullSyncFromProgress( forceRequeue: false );
}
PumpPlatformUnlocks();
if ( !ToastVisible || ToastAge < 5.5f )
return;
ToastVisible = false;
StateChanged?.Invoke();
}
/// <summary>
/// Queue every achievement that local progress/cookies say is earned.
/// Safe to call multiple times; skips ones already platform-synced.
/// </summary>
public static void ResyncPlatformFromCookies()
{
FullSyncFromProgress( forceRequeue: false );
}
/// <summary>
/// Full catch-up from actual progress (clicks, peak voices, cookies).
/// forceRequeue=true clears session "sent" flags for unsynced items so boot retries work.
/// </summary>
public static void FullSyncFromProgress( bool forceRequeue )
{
// Re-evaluate live progress (not only cookies).
OnTotalClicksChanged( SoundPlayTracker.TotalClicks );
OnLoopPlaysChanged( SoundPlayTracker.TotalLoopPlays );
if ( PeakVoiceCount >= 5 )
OnVoiceCountChanged( PeakVoiceCount );
// Anything marked local-earned must still reach the platform.
foreach ( var milestone in VoiceMilestones )
SyncIfLocalEarned( milestone.Id, milestone.CookieKey, forceRequeue );
foreach ( var milestone in ClickMilestones )
SyncIfLocalEarned( milestone.Id, milestone.CookieKey, forceRequeue );
foreach ( var milestone in LoopMilestones )
SyncIfLocalEarned( milestone.Id, milestone.CookieKey, forceRequeue );
SyncIfLocalEarned( ErrorAchievementId, ErrorCookieKey, forceRequeue );
SyncIfLocalEarned( StopItAchievementId, StopItCookieKey, forceRequeue );
SyncIfLocalEarned( FlipperReturnsAchievementId, FlipperCookieKey, forceRequeue );
foreach ( var special in SpecialAchievements )
SyncIfLocalEarned( special.Id, special.CookieKey, forceRequeue );
// Progress-based re-check (no toast spam — UnlockSpecial is one-shot).
if ( SumStemContains( "vine-boom", "vine boom", "vineboom" ) >= VineBoomRequired )
RequestPlatformUnlock( VineBoomAchievementId, forceRequeue );
if ( SumStemContains( "bruh" ) >= BruhRequired )
RequestPlatformUnlock( BruhAchievementId, forceRequeue );
if ( SumFolderPlays( "politics" ) >= PoliticsJunkieRequired )
RequestPlatformUnlock( PoliticsJunkieAchievementId, forceRequeue );
if ( SumFolderPlays( "arnold" ) >= ArnoldForeverRequired )
RequestPlatformUnlock( ArnoldForeverAchievementId, forceRequeue );
EnsureKillAllLoaded();
if ( _killAllCount >= 1 )
RequestPlatformUnlock( PanicButtonAchievementId, forceRequeue );
if ( _killAllCount >= KillAllSerialRequired )
RequestPlatformUnlock( SerialSilencerAchievementId, forceRequeue );
// Stop-it from live count even without cookie yet.
var stopCount = Math.Max(
SoundPlayTracker.GetCount( "sounds/arnold/stopit" ),
Math.Max(
SoundPlayTracker.GetCount( "sounds/arnold/stop-it" ),
SoundPlayTracker.GetCount( "sounds/arnold/stop it" ) ) );
if ( stopCount >= StopItRequired )
RequestPlatformUnlock( StopItAchievementId, forceRequeue );
}
static void SyncIfLocalEarned( string id, string cookieKey, bool forceRequeue )
{
if ( !HasUnlockedLocal( id, cookieKey ) )
return;
// Already confirmed on platform for this install — leave it.
if ( IsPlatformSynced( id ) )
return;
RequestPlatformUnlock( id, forceRequeue );
}
static string FormatCount( long n ) => n.ToString( "N0" );
static void UnlockSpecial( string id )
{
foreach ( var special in SpecialAchievements )
{
if ( !special.Id.Equals( id, StringComparison.OrdinalIgnoreCase ) )
continue;
RequestPlatformUnlock( special.Id );
TryUnlock( special.Id, special.CookieKey, special.Title, special.Body );
return;
}
}
static void EnsureKillAllLoaded()
{
if ( _killAllCount >= 0 )
return;
try { _killAllCount = Game.Cookies.Get( KillAllCountCookieKey, 0L ); }
catch { _killAllCount = 0L; }
}
static int SumStopItPlays()
{
var total = 0;
total = Math.Max( total, SoundPlayTracker.GetCount( "sounds/arnold/stopit" ) );
total = Math.Max( total, SoundPlayTracker.GetCount( "sounds/arnold/stop-it" ) );
total = Math.Max( total, SoundPlayTracker.GetCount( "sounds/arnold/stop it" ) );
return total;
}
/// <summary>Sum play counts for every tracked sound id whose path/stem contains any needle.</summary>
static int SumStemContains( params string[] needles )
{
SoundPlayTracker.EnsureLoaded();
// Walk known pads via SoundPlayTracker cookie map is private — use folder scans of GetCount
// for common ids isn't enough. Use Total via public GetCount on AllUniquePads.
var total = 0;
foreach ( var pad in SoundBoardData.AllUniquePads )
{
if ( pad is null || string.IsNullOrWhiteSpace( pad.SoundId ) )
continue;
var hay = PadHaystack( pad );
var hit = false;
foreach ( var n in needles )
{
if ( string.IsNullOrWhiteSpace( n ) )
continue;
if ( hay.Contains( n, StringComparison.OrdinalIgnoreCase ) )
{
hit = true;
break;
}
}
if ( hit )
total += SoundPlayTracker.GetCount( pad.SoundId );
}
return total;
}
static int SumFolderPlays( string folder )
{
SoundPlayTracker.EnsureLoaded();
var prefix = $"sounds/{folder}/";
var total = 0;
foreach ( var pad in SoundBoardData.AllUniquePads )
{
if ( pad?.SoundId is null )
continue;
var id = pad.SoundId.Replace( '\\', '/' );
if ( id.StartsWith( prefix, StringComparison.OrdinalIgnoreCase ) )
total += SoundPlayTracker.GetCount( pad.SoundId );
}
return total;
}
static string PadHaystack( SoundPad pad )
{
var id = (pad.SoundId ?? "").Replace( '\\', '/' );
var label = pad.Label ?? "";
return $"{id} {label}";
}
static string PadStem( SoundPad pad )
{
var id = (pad.SoundId ?? "").Replace( '\\', '/' ).Trim();
var slash = id.LastIndexOf( '/' );
return slash >= 0 && slash < id.Length - 1 ? id[(slash + 1)..] : id;
}
static bool MatchesPad( SoundPad pad, params string[] needles )
{
var hay = PadHaystack( pad );
var stem = PadStem( pad );
var compactStem = stem.Replace( " ", "" ).Replace( "-", "" ).Replace( "_", "" );
foreach ( var n in needles )
{
if ( string.IsNullOrWhiteSpace( n ) )
continue;
if ( hay.Contains( n, StringComparison.OrdinalIgnoreCase ) )
return true;
var compact = n.Replace( " ", "" ).Replace( "-", "" ).Replace( "_", "" ).Replace( "'", "" );
if ( compactStem.Equals( compact, StringComparison.OrdinalIgnoreCase ) )
return true;
}
return false;
}
static bool LiveContains( IList<string> ids, IList<string> labels, string needle )
{
if ( string.IsNullOrWhiteSpace( needle ) )
return false;
if ( ids is not null )
{
foreach ( var id in ids )
{
if ( !string.IsNullOrWhiteSpace( id ) && id.Contains( needle, StringComparison.OrdinalIgnoreCase ) )
return true;
}
}
if ( labels is not null )
{
foreach ( var label in labels )
{
if ( !string.IsNullOrWhiteSpace( label ) && label.Contains( needle, StringComparison.OrdinalIgnoreCase ) )
return true;
}
}
return false;
}
static int CountLiveFolder( IList<string> ids, string folder )
{
if ( ids is null || string.IsNullOrWhiteSpace( folder ) )
return 0;
var token = $"/{folder}/";
var count = 0;
foreach ( var id in ids )
{
if ( string.IsNullOrWhiteSpace( id ) )
continue;
var path = id.Replace( '\\', '/' );
if ( path.Contains( token, StringComparison.OrdinalIgnoreCase )
|| path.StartsWith( $"sounds/{folder}/", StringComparison.OrdinalIgnoreCase ) )
count++;
}
return count;
}
static int CountLiveGas( IList<string> ids, IList<string> labels )
{
// Prefer sound ids (unique live pads). Labels are a fallback only.
var count = 0;
if ( ids is not null && ids.Count > 0 )
{
foreach ( var id in ids )
{
if ( string.IsNullOrWhiteSpace( id ) )
continue;
if ( IsGasText( id ) )
count++;
}
return count;
}
if ( labels is not null )
{
foreach ( var label in labels )
{
if ( IsGasText( label ) )
count++;
}
}
return count;
}
static bool IsGasText( string text )
{
if ( string.IsNullOrWhiteSpace( text ) )
return false;
return text.Contains( "fart", StringComparison.OrdinalIgnoreCase )
|| text.Contains( "burp", StringComparison.OrdinalIgnoreCase )
|| text.Contains( "poop", StringComparison.OrdinalIgnoreCase )
|| text.Contains( "flatul", StringComparison.OrdinalIgnoreCase )
|| text.Contains( "/gas/", StringComparison.OrdinalIgnoreCase )
|| text.Contains( "sounds/gas/", StringComparison.OrdinalIgnoreCase );
}
static bool IsStopItPad( SoundPad pad )
{
if ( string.IsNullOrWhiteSpace( pad.SoundId ) )
return false;
var stem = PadStem( pad );
if ( stem.Equals( "stopit", StringComparison.OrdinalIgnoreCase )
|| stem.Equals( "stop-it", StringComparison.OrdinalIgnoreCase )
|| stem.Equals( "stop_it", StringComparison.OrdinalIgnoreCase )
|| stem.Equals( "stop it", StringComparison.OrdinalIgnoreCase ) )
return true;
var label = pad.Label?.Trim() ?? "";
var compact = label.Replace( " ", "" ).Replace( "-", "" ).Replace( "_", "" );
return compact.Equals( "STOPIT", StringComparison.OrdinalIgnoreCase );
}
static void TryUnlock( string id, string cookieKey, string title, string body )
{
if ( TryUnlockLocal( id, cookieKey ) )
ShowToast( title, body );
}
static bool TryUnlockLocal( string achievementId, string cookieKey )
{
if ( HasUnlockedLocal( achievementId, cookieKey ) )
return false;
MarkUnlockedLocal( achievementId, cookieKey );
return true;
}
static bool HasUnlockedLocal( string achievementId, string cookieKey )
{
if ( _unlockedLocal.Contains( achievementId ) )
return true;
if ( CookieSaysUnlocked( cookieKey ) )
{
_unlockedLocal.Add( achievementId );
return true;
}
return false;
}
static bool CookieSaysUnlocked( string cookieKey )
{
try
{
return Game.Cookies.Get( cookieKey, false );
}
catch
{
return false;
}
}
static void MarkUnlockedLocal( string achievementId, string cookieKey )
{
_unlockedLocal.Add( achievementId );
try { Game.Cookies.Set( cookieKey, true ); }
catch { /* session-only */ }
}
static string PlatformCookieKey( string achievementId )
=> PlatformSyncedPrefix + achievementId;
static bool IsPlatformSynced( string achievementId )
{
if ( _platformSynced.Contains( achievementId ) )
return true;
try
{
if ( Game.Cookies.Get( PlatformCookieKey( achievementId ), false ) )
{
_platformSynced.Add( achievementId );
return true;
}
}
catch { /* ignore */ }
return false;
}
static void MarkPlatformSynced( string achievementId )
{
_platformSynced.Add( achievementId );
try { Game.Cookies.Set( PlatformCookieKey( achievementId ), true ); }
catch { /* session-only */ }
}
/// <summary>
/// Queue a platform unlock. Does nothing if already platform-synced (cookie).
/// forceRequeue resets attempt/backoff so a paused id can try again this session.
/// </summary>
static void RequestPlatformUnlock( string achievementId, bool forceRequeue = false )
{
if ( string.IsNullOrWhiteSpace( achievementId ) )
return;
// Only skip when Unlock already returned without error (cookie set).
// Local toast cookies never block this path — that was the fifty_deep bug.
if ( IsPlatformSynced( achievementId ) )
return;
if ( forceRequeue )
{
_platformAttempts.Remove( achievementId );
_platformNextTryAt.Remove( achievementId );
}
if ( _platformQueued.Contains( achievementId ) )
return;
_platformQueued.Add( achievementId );
_platformQueue.Enqueue( achievementId );
}
static void PumpPlatformUnlocks()
{
// Wait for services after boot.
if ( _sinceStart < InitialSyncDelay )
return;
if ( _platformQueue.Count == 0 )
return;
// Find next ready item (backoff).
var skipped = 0;
var maxSkip = _platformQueue.Count;
while ( skipped < maxSkip && _platformQueue.Count > 0 )
{
var id = _platformQueue.Dequeue();
_platformQueued.Remove( id );
if ( IsPlatformSynced( id ) )
continue;
if ( _platformNextTryAt.TryGetValue( id, out var nextAt ) && Time.Now < nextAt )
{
// Not ready yet — put back and try another.
_platformQueued.Add( id );
_platformQueue.Enqueue( id );
skipped++;
continue;
}
TryPlatformUnlockNow( id );
return; // one attempt per tick
}
}
static void TryPlatformUnlockNow( string id )
{
var attempts = _platformAttempts.TryGetValue( id, out var n ) ? n + 1 : 1;
_platformAttempts[id] = attempts;
try
{
Achievements.Unlock( id );
MarkPlatformSynced( id );
_platformAttempts.Remove( id );
_platformNextTryAt.Remove( id );
Log.Info( $"[S&Soundboard] Platform achievement unlock OK: {id}" );
}
catch ( Exception e )
{
var delay = PlatformRetryBaseSec * MathF.Min( attempts, 10 ); // 1.5s, 3s, … up to 15s
_platformNextTryAt[id] = Time.Now + delay;
Log.Warning( $"[S&Soundboard] Platform unlock failed ({attempts}/{MaxPlatformAttempts}): {id} — {e.GetType().Name}: {e.Message}" );
if ( attempts < MaxPlatformAttempts )
{
_platformQueued.Add( id );
_platformQueue.Enqueue( id );
}
else
{
// Don't mark synced — next session / periodic resync will try again.
_platformAttempts.Remove( id );
_platformNextTryAt.Remove( id );
Log.Warning( $"[S&Soundboard] Pausing platform unlock for '{id}' this session. Will retry on next resync. Confirm Manual ident '{id}' on the package dashboard." );
}
}
}
static void ShowToast( string title, string body )
{
ToastTitle = title;
ToastBody = body;
ToastVisible = true;
ToastAge = 0;
StateChanged?.Invoke();
}
readonly record struct VoiceMilestone( int Required, string Id, string CookieKey, string Title, string Body );
readonly record struct ClickMilestone( long Required, string Id, string CookieKey, string Title, string Body );
readonly record struct LoopMilestone( long Required, string Id, string CookieKey, string Title, string Body );
readonly record struct SpecialAchievement( string Id, string CookieKey, string Title, string Body );
}