【问题标题】:Unity JSON: Is there a way if the player goes to the save file, and corrupts the file, a way to detect that?Unity JSON:如果玩家进入保存文件并损坏文件,有没有办法检测到?
【发布时间】:2019-02-17 18:39:44
【问题描述】:

在我的项目中,我将播放器信息保存到 JSON 文件中。我在保存之前对信息进行了加密,但是如果玩家进入文件并碰巧删除了文件的一个字符,那么当游戏加载时,因为它依赖于该文件,游戏就会冻结。我确实有它,以便在未检测到文件时创建新的玩家信息,但如果文件在那里并且他们弄乱了它,有没有办法在游戏尝试加载它之前检测并纠正它。我正在使用 Unity 内置的 JSONUtility。

【问题讨论】:

  • 只是尝试/捕获错误并像其他 IO 操作一样处理它?
  • 使用 PlayerPrefs 保存,它在文件夹中有点下,所以不太容易找到。您可以保存为二进制文件,甚至可以加密,这样玩家就更难做某事了。如果用户搞砸了文件,那么您的代码就不够安全。您应该检查解析是否正常等等。终极解决方案,如果可以的话,将信息存储在服务器上。如今,游戏将数据保存在服务器上,因为它允许更安全的流程和分析。
  • 您可以使用md5指纹来检查数据是否正确。将指纹保存在 PlayerPrefs 或其他位置。无论如何,如果他们故意编辑弄乱了文件,你为什么要关心?

标签: json unity3d save loading


【解决方案1】:

在加载 JSON 文件时使用 try/catch

        try
    {
        JsonUtility.FromJSON(...)
    }
    catch (FileNotFoundException e)
    {
        Print("The file was not found: '{e}'");
    }
    catch (DirectoryNotFoundException e)
    {
        Print("The directory was not found: '{e}'");
    }
    catch (IOException e)
    {
        Print("The file could not be opened: '{e}'");
    }

但是,这不应该那么重要。如果玩家试图弄乱游戏文件并且您担心程序崩溃,那么您不应该这样做,因为该玩家不应该一直在编辑游戏文件。

【讨论】:

  • 我最终还是使用了 try catch 来解决问题。是的,我希望播放器不要尝试更改文件,但我只是在寻找故障保险,以防播放器这样做。
【解决方案2】:

我认为同时使用散列和 try/catch 检查会是更好的解决方案 您可以尝试打开文件,然后将其哈希值与您在上次游戏会话中保存的哈希值进行比较:

private void LoadSave()
{
    try
    {
        JsonUtility.FromJson("filename", ...);
        string oldHash = PlayerPrefs.GetString("importantSaveFileHash");
        string newHash = CalculateMd5("filename");
        if (oldHash == null || oldHash == newHash)
        {
            //recalculate hash every time you change the save file
            //you can also encrypt this hash for better security
            PlayerPrefs.SetString("importantSaveFileHash", newHash); 
            //RESULT: Save file is cool!
        }
        else
        {
            //RESULT: Save file was modified!
        }
    }
    catch (Exception e)
    {
        //RESULT: broken file
    }
}

private static string CalculateMd5(string filename)
{
    using (var md5 = MD5.Create())
    {
        using (var stream = File.OpenRead(filename))
        {
            var hash = md5.ComputeHash(stream);
            return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
        }
    }
}

顺便说一句,您可以只使用 PlayerPrefs 来存储所有游戏状态(我知道有时拥有可见且可读的保存文件很重要) - 选择您需要的内容)

UPD:在 PlayerPrefs 中存储游戏状态不好 - 使用任何其他方式代替(读取 cmets)

【讨论】:

  • 不,不要在 PlayerPrefs 中保存东西!停下来! Player Prefs 从未打算保存游戏状态,因为它的大小有限、允许的数据类型有限且不安全。
  • 你是对的,这并不好,但它只是无服务器游戏的简单解决方法。至于我,我永远不会保护离线游戏状态,它没用)
  • 仅仅因为它对保护离线游戏状态无用并不是使用从未用于保存游戏状态的系统的理由。
  • docs.unity3d.com/ScriptReference/PlayerPrefs.html 说:“存储和访问游戏会话之间的玩家偏好。”所以,是的,我的错,偏好!= 游戏状态。
  • 宾果游戏。它意味着诸如“音量级别”“输入模式(鼠标或键盘?)”等。程序应该在会话之间记住的东西,但与游戏状态无关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
  • 2011-01-23
  • 2020-12-18
  • 2021-12-18
  • 1970-01-01
相关资源
最近更新 更多