Token导航 LogoToken导航TokenDH.com
研究检索可写文件github未标认证来源可访问许可证需确认审计通过

unity-save-systemUnity save 系统

Agent Skill

unity-save-system 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

318

周安装

13

GitHub Stars

14

下载量

102
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:unity-save-system(Unity save 系统)
来源仓库:https://github.com/nice-wolf-studio/unity-claude-skills
仓库路径:skills/unity-save-system
安装命令:
npx skills add https://github.com/nice-wolf-studio/unity-claude-skills --skill unity-save-system
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/nice-wolf-studio/unity-claude-skills --skill unity-save-system

简介

unity-save-system 用于查找、检索和筛选相关信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中根据关键词或任务场景快速定位候选结果。
  • 支持存档系统与数据持久化相关的资源检索。
  • 安装前需确认权限范围、维护状态及是否涉及联网或文件操作。
  • 建议参考原始 README 了解具体使用场景与限制条件。

SKILL.md

Save/Load Systems -- Decision Patterns

Prerequisite skills: unity-lifecycle (OnApplicationPause, OnApplicationQuit, quit sequence), unity-data-driven (JSON serialization, versioning), unity-packages-services (Cloud Save API), unity-async-patterns (BackgroundThreadAsync)

These patterns address the most common save system failure: Claude uses PlayerPrefs for everything, produces brittle serialization with no versioning, and ignores mobile-specific persistence requirements.


PATTERN: Serialization Format Selection

WHEN: Choosing how to serialize save data to disk

DECISION:

  • JSON (JsonUtility) -- Human-readable, debuggable, small save files. No dictionary/polymorphism. Best default for most games.
  • JSON (Newtonsoft) -- Full JSON features (dictionaries, polymorphism, LINQ). Slightly larger dependency. Best when save data is complex.
  • Binary (custom or MessagePack) -- Performance-critical, large saves, anti-cheat (harder to edit). Not human-readable. Best for competitive games or very large worlds.
  • BinaryFormatter -- NEVER USE. Security vulnerability (arbitrary code execution on deserialization). Deprecated by Unity and Microsoft.

SCAFFOLD (JSON save/load):

using System.IO;
using UnityEngine;

public static class SaveFileIO
{
    public static void SaveJson<T>(T data, string fileName)
    {
        string path = GetSavePath(fileName);
        string json = JsonUtility.ToJson(data, prettyPrint: true);

        // Write to temp file first, then rename (atomic write)
        string tempPath = path + ".tmp";
        File.WriteAllText(tempPath, json);
        if (File.Exists(path))
            File.Replace(tempPath, path, path + ".bak");
        else
            File.Move(tempPath, path);
    }

    public static T LoadJson<T>(string fileName) where T : new()
    {
        string path = GetSavePath(fileName);
        if (!File.Exists(path)) return new T();

        string json = File.ReadAllText(path);
        return JsonUtility.FromJson<T>(json);
    }

    public static bool SaveExists(string fileName) =>
        File.Exists(GetSavePath(fileName));

    public static void DeleteSave(string fileName)
    {
        string path = GetSavePath(fileName);
        if (File.Exists(path)) File.Delete(path);
        if (File.Exists(path + ".bak")) File.Delete(path + ".bak");
    }

    static string GetSavePath(string fileName) =>
        Path.Combine(Application.persistentDataPath, fileName);
}

GOTCHA: BinaryFormatter is a security hole -- deserialization can execute arbitrary code. Unity and Microsoft have deprecated it. If you find it in existing code, replace it immediately. JsonUtility cannot serialize dictionaries -- convert to List<SerializableKeyValue<K,V>> or use Newtonsoft. The atomic write pattern (write to.tmp, rename) prevents data corruption if the app crashes mid-write.


PATTERN: Save Data Architecture (DTO Pattern)

WHEN: Deciding what to serialize and how to structure it

DECISION:

  • Single monolithic save -- One SaveData class with everything. Load/save is atomic. Best for small games with fast save/load.
  • Per-system save files -- PlayerSave.json, InventorySave.json, WorldSave.json. Partial load, smaller writes, easier to migrate individual systems.

SCAFFOLD (ISaveable interface):

// Save Data Transfer Object -- plain C# class, NOT MonoBehaviour
[System.Serializable]
public class GameSaveData
{
    public int version = 1;
    public PlayerSaveData player;
    public InventorySaveData inventory;
    public WorldSaveData world;
}

[System.Serializable]
public class PlayerSaveData
{
    public float[] position = new float[3]; // Vector3 as array for JSON compat
    public int health;
    public int level;
    public int xp;

    public void FromPlayer(Transform t, int hp, int lvl, int xp)
    {
        position[0] = t.position.x;
        position[1] = t.position.y;
        position[2] = t.position.z;
        health = hp; level = lvl; this.xp = xp;
    }

    public Vector3 GetPosition() => new(position[0], position[1], position[2]);
}

// Systems implement ISaveable to participate in save/load
public interface ISaveable
{
    void GatherSaveData(GameSaveData data);  // Write state to DTO
    void ApplySaveData(GameSaveData data);   // Read state from DTO
}

GOTCHA: Save DTOs must be plain C# classes with [System.Serializable], NOT MonoBehaviours or ScriptableObjects. They contain only serializable types (primitives, arrays, lists, nested [Serializable] classes). Unity types like Vector3 serialize fine with JsonUtility but NOT with Newtonsoft without a custom converter -- use float[] for portability.


PATTERN: Save File Location

WHEN: Choosing where to write save files

DECISION:

  • Application.persistentDataPath (correct default) -- Writable, survives app updates, platform-appropriate. Use for all save data.
  • Application.streamingAssetsPath -- READ-ONLY in builds. Never write here. For bundled read-only data only.
  • PlayerPrefs -- Key-value only. For settings/preferences. NOT for game state.

SCAFFOLD:

// Always use Path.Combine -- never concatenate with "/"
string savePath = Path.Combine(Application.persistentDataPath, "saves", "slot1.json");

// Ensure directory exists before writing
string dir = Path.GetDirectoryName(savePath);
if (!Directory.Exists(dir))
    Directory.CreateDirectory(dir);

GOTCHA: persistentDataPath locations differ per platform: AppData/LocalLow/<company>/<product> (Windows), ~/Library/Application Support/<bundleID> (macOS), internal storage (Android/iOS). On WebGL, it uses IndexedDB (async, may fail in private browsing). Always use Path.Combine -- forward slashes work on macOS/Linux but Path.Combine is cross-platform safe.


PATTERN: PlayerPrefs Scoping

WHEN: Using PlayerPrefs for settings and small persistent values

DECISION:

  • Direct PlayerPrefs calls -- Under 10 settings, minimal project. Simple.
  • Wrapper class -- 10+ settings, need type safety, change events, defaults. Prevents key collision.

SCAFFOLD (Settings wrapper):

public static class GameSettings
{
    // Prefixed keys prevent collision between systems
    private const string Prefix = "settings.";

    public static float MasterVolume
    {
        get => PlayerPrefs.GetFloat(Prefix + "masterVolume", 1f);
        set { PlayerPrefs.SetFloat(Prefix + "masterVolume", value); OnSettingsChanged?.Invoke(); }
    }

    public static bool Fullscreen
    {
        get => PlayerPrefs.GetInt(Prefix + "fullscreen", 1) == 1;
        set { PlayerPrefs.SetInt(Prefix + "fullscreen", value ? 1 : 0); OnSettingsChanged?.Invoke(); }
    }

    public static int QualityLevel
    {
        get => PlayerPrefs.GetInt(Prefix + "quality", QualitySettings.GetQualityLevel());
        set { PlayerPrefs.SetInt(Prefix + "quality", value); OnSettingsChanged?.Invoke(); }
    }

    public static event Action OnSettingsChanged;

    public static void Save() => PlayerPrefs.Save();

    public static void ResetToDefaults()
    {
        PlayerPrefs.DeleteKey(Prefix + "masterVolume");
        PlayerPrefs.DeleteKey(Prefix + "fullscreen");
        PlayerPrefs.DeleteKey(Prefix + "quality");
        OnSettingsChanged?.Invoke();
    }
}

GOTCHA: PlayerPrefs keys are global strings -- no namespacing. Use prefixed keys ("audio.masterVolume", "video.fullscreen") to prevent collisions. PlayerPrefs has no bool type -- use int (0/1). On Windows, PlayerPrefs stores to the Windows Registry -- avoid large values. PlayerPrefs.Save() is automatic on OnApplicationQuit but call it manually after important changes on mobile (app may be killed without quit).


PATTERN: Save Versioning and Migration

WHEN: Save format changes between game updates (fields added, renamed, restructured)

DECISION:

  • Version field + sequential migrators -- For breaking changes. Store int version in save. On load, run migration chain: v1 -> v2 -> v3 -> current.
  • Tolerant reader -- For additive-only changes. New fields get defaults, removed fields are ignored. Works with JsonUtility automatically.

SCAFFOLD (Migration chain):

public static class SaveMigrator
{
    private static readonly int CurrentVersion = 3;

    public static GameSaveData LoadAndMigrate(string json)
    {
        // Parse version from raw JSON first
        var versionCheck = JsonUtility.FromJson<VersionOnly>(json);
        int version = versionCheck.version;

        if (version == CurrentVersion)
            return JsonUtility.FromJson<GameSaveData>(json);

        // Sequential migration using Newtonsoft for raw JSON manipulation
        var jObj = Newtonsoft.Json.Linq.JObject.Parse(json);

        if (version < 2) MigrateV1ToV2(jObj);
        if (version < 3) MigrateV2ToV3(jObj);

        jObj["version"] = CurrentVersion;
        return Newtonsoft.Json.JsonConvert.DeserializeObject<GameSaveData>(jObj.ToString());
    }

    static void MigrateV1ToV2(Newtonsoft.Json.Linq.JObject data)
    {
        // v2 moved "playerX/Y/Z" into "player.position" array
        var player = (Newtonsoft.Json.Linq.JObject)data["player"];
        if (player != null && player["playerX"] != null)
        {
            float x = (float)player["playerX"];
            float y = (float)player["playerY"];
            float z = (float)player["playerZ"];
            player["position"] = new Newtonsoft.Json.Linq.JArray(x, y, z);
            player.Remove("playerX"); player.Remove("playerY"); player.Remove("playerZ");
        }
    }

    static void MigrateV2ToV3(Newtonsoft.Json.Linq.JObject data)
    {
        // v3 added inventory system (default to empty)
        if (data["inventory"] == null)
            data["inventory"] = Newtonsoft.Json.Linq.JObject.FromObject(new InventorySaveData());
    }

    [System.Serializable]
    private class VersionOnly { public int version; }
}

GOTCHA: Migration must work on raw JSON (before deserializing to the new C# type) because the old type definition may no longer exist in code. Use Newtonsoft JObject for structural changes. Each migration step is a function from version N to N+1 -- compose them sequentially. Test migrations with saved JSON from each version (store test fixtures).


PATTERN: Cloud Save Integration

WHEN: Save data should sync across devices or persist beyond local storage

DECISION:

  • Unity Cloud Save (UGS) -- Managed service, key-value or file storage, 200KB free per player. See unity-packages-services for API. Best for most indie/mid-size games.
  • Custom backend -- Full control, unlimited storage, custom conflict resolution. You build and maintain it.

SCAFFOLD (Local-first with cloud sync):

public class SaveManager : MonoBehaviour
{
    public async Awaitable Save(GameSaveData data)
    {
        // Always save locally first (fast, reliable)
        SaveFileIO.SaveJson(data, "savegame.json");

        // Then sync to cloud in background (best-effort)
        try
        {
            var cloudData = new Dictionary<string, object>
            {
                { "savegame", JsonUtility.ToJson(data) }
            };
            await Unity.Services.CloudSave.CloudSaveService.Instance
                .Data.Player.SaveAsync(cloudData);
        }
        catch (Exception e)
        {
            Debug.LogWarning($"Cloud save failed (local save preserved): {e.Message}");
        }
    }
}

GOTCHA: Cloud saves must handle offline play. Always save locally first, sync to cloud in the background. Handle CloudSaveException gracefully -- network failures should never prevent local play or crash the game. For conflict resolution, "last-write-wins" is simplest; use timestamps if you need merge logic.


PATTERN: Auto-Save Strategy

WHEN: Deciding when to trigger saves

DECISION:

  • Checkpoint-based -- Save at specific game events (level complete, rest point, manual save). Explicit, designer-controlled. Traditional approach.
  • Periodic auto-save -- Save every N seconds or on scene transition. Safety net against crashes. Can be combined with checkpoints.
  • Event-driven -- Save whenever significant state changes (item acquired, quest completed). Granular but more I/O.

SCAFFOLD (Auto-save + mobile safety):

public class AutoSaveManager : MonoBehaviour
{
    [SerializeField] private float autoSaveInterval = 60f; // seconds
    private float _timeSinceLastSave;

    void Update()
    {
        _timeSinceLastSave += Time.unscaledDeltaTime;
        if (_timeSinceLastSave >= autoSaveInterval)
        {
            _timeSinceLastSave = 0f;
            _ = PerformAutoSave(); // Fire-and-forget with error handling
        }
    }

    // Mobile: save on app background (OnApplicationQuit may not fire)
    void OnApplicationPause(bool paused)
    {
        if (paused)
            _ = PerformAutoSave();
    }

    void OnApplicationQuit()
    {
        // Synchronous save on quit (async may not complete)
        var data = GatherSaveData();
        SaveFileIO.SaveJson(data, "autosave.json");
    }

    async Awaitable PerformAutoSave()
    {
        try
        {
            await Awaitable.BackgroundThreadAsync();
            var data = GatherSaveData();
            SaveFileIO.SaveJson(data, "autosave.json");
            await Awaitable.MainThreadAsync();
        }
        catch (Exception e)
        {
            Debug.LogError($"Auto-save failed: {e.Message}");
        }
    }

    GameSaveData GatherSaveData()
    {
        var data = new GameSaveData();
        // Gather from all ISaveable systems
        return data;
    }
}

GOTCHA: Saving is I/O-bound. On mobile, use OnApplicationPause(true) -- OnApplicationQuit may not fire when the OS kills the app. In OnApplicationQuit, use synchronous I/O (async may not complete before the process exits). Never save in Update synchronously -- use BackgroundThreadAsync or a timer. Cross-ref: unity-lifecycle covers the quit sequence.


Anti-Patterns

Anti-PatternProblemFix
BinaryFormatterSecurity vulnerability, deprecatedUse JsonUtility or Newtonsoft
Game state in PlayerPrefsNo structure, no versioning, key collisionUse JSON files + persistentDataPath
Saving MonoBehaviour directlyNot serializable, couples save to sceneUse plain C# DTOs with [Serializable]
No version field in save dataCannot migrate when format changesAlways include int version
Synchronous save in UpdateFrame hitches, especially on mobileUse BackgroundThreadAsync or timer
No backup/atomic writeCrash during write corrupts saveWrite to.tmp, rename atomically

Related Skills

  • unity-lifecycle -- OnApplicationPause, OnApplicationQuit, quit sequence timing
  • unity-packages-services -- Unity Cloud Save API (do not duplicate)
  • unity-async-patterns -- BackgroundThreadAsync for async I/O
  • unity-data-driven -- JsonUtility vs Newtonsoft, versioning patterns for config data

Additional Resources

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.2%
按下载量换算37

Claude

28.97%
按下载量换算30

Cursor

20.16%
按下载量换算21

Gemini CLI

9.53%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

可写文件

该 Skill 可能写入或修改本地文件,使用前需要确认目标目录和修改范围。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills