SkillAgentSearch skills...

ReplayLib

ReplayLib is a comprehensive utility library for Unity game development, providing core patterns, extensions, and systems used throughout "The Last Word" project. The library emphasizes memory management, performance optimization, and consistent coding patterns.

Install / Use

/learn @radif/ReplayLib
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

ReplayLib

ReplayLib is a comprehensive utility library for Unity game development, providing core patterns, extensions, and systems used throughout "The Last Word" project. The library emphasizes memory management, performance optimization, and consistent coding patterns.

About

This library is used in production by The Last Word, a real-time multiplayer word puzzle game developed by Replay Digital. The game features deterministic networking with Photon Quantum, multiple competitive game modes, and cross-platform play. ReplayLib has been battle-tested in a live production environment serving thousands of players on iOS.

Download: App Store

Table of Contents

Core Patterns

Singleton System

ReplayLib provides three types of singleton patterns for different use cases:

ComponentSingleton<T>

Addressable-aware singleton pattern for MonoBehaviour classes requiring Unity lifecycle management.

Key Features:

  • Automatic Addressables handle management
  • Resource loading support
  • Scene persistence with DontDestroyOnLoad
  • Automatic initialization and cleanup
  • Warmup support for smooth animations

Usage:

using Replay.Utils;

public class BackEndManager : ComponentSingleton<BackEndManager>
{
    protected override void OnSingletonInit()
    {
        // Initialization code
    }

    protected override void OnSingletonTeardown()
    {
        // Cleanup code
    }
}

// Access the singleton
BackEndManager.Instance.SomeMethod();

// Check if loaded without instantiation
if (BackEndManager.IsLoaded)
{
    // Safe to use
}

// Warm up prefab for faster instantiation
BackEndManager.WarmupPrefab();

Important Lifecycle Patterns:

  • Use Awake() for initialization instead of OnSingletonInit() override
  • Use protected void OnDestroy() without calling base.OnDestroy()
  • Check existence with IsLoaded property (not IsLoaded() method)
  • Never compare Instance to null (use IsLoaded or WeakInstance)

Automatic Serialization: When implementing IReplaySerialazable, Deserialize() is called automatically by the framework. Do NOT manually call it in Start() or Awake().

public class PlayerProfileManager : ComponentSingleton<PlayerProfileManager>, IReplaySerialazable
{
    // Deserialize() called automatically - no manual call needed
    public void Deserialize()
    {
        // Load data
    }

    public void Serialize()
    {
        // Save data - call manually as needed
    }
}

ScriptableObjectSingleton<T>

Singleton pattern for ScriptableObject-based configuration and data.

Usage:

public class GameSettings : ScriptableObjectSingleton<GameSettings>
{
    public float musicVolume;
    public float sfxVolume;
}

// Access settings
float volume = GameSettings.Instance.musicVolume;

Singleton<T>

Basic singleton pattern for pure C# classes without Unity dependencies.

Loadable System

Components implementing ILoadable can be dynamically loaded from Resources or Addressables:

public static string GetResourcePath() => "Prefabs/MyManager";
public static string GetAddressablesIdentifier() => "MyManagerAddressable";

Data Persistence

LocalSerializer

Wrapper around Unity's PlayerPrefs with iCloud support and type-safe operations.

Features:

  • Automatic iCloud synchronization on iOS
  • Type-safe get/set methods
  • Support for bool, int, long, float, double, string
  • Device account persistence option

Usage:

using Replay.Utils;

// Save data
LocalSerializer.Instance.SetInt("score", 100);
LocalSerializer.Instance.SetString("playerName", "Alice");

// Save to device account (iCloud on iOS)
LocalSerializer.Instance.SetString("profileId", "12345", saveToDeviceAccount: true);

// Load data
int score = LocalSerializer.Instance.GetInt("score");
string name = LocalSerializer.Instance.GetString("playerName", "DefaultName");

// Persist to disk
LocalSerializer.Instance.Serialize();

// Clear all data
LocalSerializer.Instance.DeleteAll();

IReplaySerialazable

Interface for objects that need serialization support with automatic deserialization when used with ComponentSingleton.

public interface IReplaySerialazable
{
    void Serialize();     // Called manually when needed
    void Deserialize();   // Called automatically by ComponentSingleton
}

Logging and Debugging

Dev (Debug Logging)

Conditional debug logging that only executes in debug builds.

Features:

  • Tagged logging for easy filtering
  • Method name tracking
  • Force logging option
  • Custom tag support

Usage:

using Replay.Utils;

// Basic logging
Dev.Log("Player spawned");

// With custom tag
Dev.Log("Connection established", "Network");

// Warnings and errors
Dev.LogWarning("Low memory detected");
Dev.LogError("Failed to load asset");

// Log method name with location
Dev.LogMethod("GameState");

// Force logging even in release builds
Dev.Log("Critical error", force: true);

Logger

Persistent file-based logging system with queue management.

Features:

  • Thread-safe logging
  • Automatic file management
  • Exception tracking
  • Log filtering by tag
  • Queue size management

Usage:

// Logger initializes automatically
// All Unity logs are captured

// Get logs
string logs = Logger.Instance.GetLogs();
string networkLogs = Logger.Instance.GetLogs("Network");

// Manage log file
Logger.Instance.FlushLogsToFile();
Logger.Instance.TrimLogFile();

// For debugging
string logPath = Logger.Instance.logFilePath;

IDebugLoggable

Interface for classes that need debug output with custom ToDebugString() pattern.

public class PlayerProfile : IDebugLoggable
{
    public string ToDebugString()
    {
        return $"PlayerProfile [ID: {id}, Name: {name}, Level: {level}]";
    }
}

Extensions

ReplayLib provides extensive extension methods for common Unity types and operations.

List Extensions

using Replay.Utils;

List<string> items = new List<string> { "a", "b", "c" };

// Shuffle list
items.Shuffle();

// Shuffle with seed for deterministic results
items.Shuffle(42);

// Rotate elements
items.RotateLeft();
items.RotateRight(2);

// Swap elements
items.Swap(0, 2);

// Clean up
items.RemoveNullEntries();
items.RemoveDefaultValues();

// Check index validity
if (items.HasIndex(5))
    Debug.Log(items[5]);

// Destroy MonoBehaviour list contents
List<Enemy> enemies = new List<Enemy>();
enemies.DestoryContentsAndClear();

String Extensions

using Replay.Utils;

string text = "hello world";

// Character shuffling
string shuffled = text.ShuffleCharacters();

// Null/empty checks
bool isEmpty = text.IsNullOrEmpty();
bool isWhitespace = text.IsNullOrWhiteSpace();

// Parsing with defaults
int number = "123".IntValue();
long bigNumber = "9999999999".LongValue(0L);
float decimal = "3.14".FloatValue();
double precise = "3.14159".DoubleValue();
bool flag = "true".BoolValue();

// Date parsing
DateTime? date = "2024-01-01".ToDateTime();

// Case conversions
string title = "hello world".ToTitleCase();
char upper = 'a'.ToUpper();

// URL encoding
string escaped = "hello world".ToEscapeURL();
string dataEscaped = "data string".ToEscapeDataString();

// Formatting
string bracketed = "Tag".ToBracketedString(); // "[Tag]"
string display = name.GetNAOrString(); // Returns "N/A" if null/empty

GameObject Extensions

using Replay.Utils;

GameObject obj = someGameObject;

// Scene management
obj.MoveToMainScene();
obj.MoveToActiveScene();

// Hierarchy navigation
GameObject root = obj.GetRootGameObject();
GameObject[] sceneRoots = GameObjectExtensions.GetRootGameObjectsInActiveScene();

// Check if in DontDestroyOnLoad
bool persistent = obj.isDontDestroyOnLoadActivated();

// Recursive operations
obj.SetActiveRecursively(false);

// Message broadcasting
obj.BroadcastMessageToRoot("OnGameStart");
GameObjectExtensions.BroadcastMessageToRootObjectsInActiveScene("OnLevelLoad");

// Hierarchy checks
bool isChild = parent.HasChildObject(child, recursive: true);

Enum Extensions

using Replay.Utils;

public enum GameMode { Menu, Playing, Paused, GameOver }

GameMode mode = GameMode.Playing;

// Navigation
GameMode next = mode.Next();
GameMode previous = mode.Previous();

// Position checks
bool isFirst = mode.IsFirst();
bool isLast = mode.IsLast();
int index = mode.ValueIndex();

// Conversion
string name = mode.ConvertToString();
GameMode parsed = "Playing".ConvertToEnum<GameMode>();
int value = mode.intValue();

Component Extensions

using Replay.Utils;

// Get or add component
AudioSource audio = gameObject.GetOrAddComponent<AudioSource>();

// Check component existence
bool hasRigidbody = gameObject.HasComponent<Rigidbody>();

// Fix prefab clone suffix
gameObject.FixOrAppendPrefabCloneSuffix("Singleton");

Transform Extensions

using Replay.Utils;

// Reset transformations
transform.ResetLocal();
transform.ResetWorld();

// Destroy children
transform.Dest
View on GitHub
GitHub Stars48
CategoryDevelopment
Updated2mo ago
Forks0

Languages

C#

Security Score

80/100

Audited on Jan 1, 2026

No findings