持久化

保存玩家的进度,用两个动词而不是十六种方法,时机上的坑也替你处理好了。

更新于 2026-09-08

VRChat 可以在两次到访之间记住关于一个玩家的事情。它为此给你的 API 是一个按类型分方法的键值存储:SetIntGetIntTryGetInt,同样的三个又为十六种类型各来一遍。

其中有三件事会悄悄出错。

你得记住是哪个方法写了这个键。SetInt 写的 "level" 再用 GetString 去读,不会有任何抱怨:你拿到一个空字符串,然后照常往下走。

对没人写过的键,GetInt 返回零,而保存下来的零也长这样。一个给新玩家发起始资金的商店,分不出第一次来的人和把钱花光的人。

Start 里保存的数据还没到。 它在玩家进来之后一小会儿才到。读得太早不会报错,只会拿到默认值,所以在没有东西可恢复的编辑器里世界表现得完美无缺,然后把一个带着进度的真玩家当成陌生人接待。

这个包是两个动词和一个基类:

public class Shop : SaveBehaviour
{
    private int coins;

    public override void OnSaveReady()
    {
        coins = Save.Get("coins", 100);
    }

    public void Buy(int price)
    {
        coins = coins - price;
        Save.Set("coins", coins);
    }
}

其余的由值来决定。Save.Set("name", "ada") 存字符串,Save.Set("coins", 5) 存整数,你都不必点名是哪一种。读取时要一并给出"什么都没存时该拿到的值",那正是你本来会写在 TryGet 下面那个 if 里的值——而强制你写出它,正是把"从未保存"和"保存成了零"分开的东西。

OnSaveReady 在读取唯一有意义的那一刻运行。把加载放在那里而不是 Start,顺序就不再是你需要记住的事。

里面有什么

Save Set 与 Get,覆盖 VRChat 能保存的每一种类型
SaveBehaviour 在数据成真的那一刻运行的 OnSaveReady
PlayerObjects 找到属于某个玩家的那份副本
Storage 世界为这个玩家用掉了多少配额
出了点问题 重新加载