Architecture/Implementation 使用本地和远程数据进行身份验证

Architecture/Implementation of authentication with local and remote data

我正在开发一款用户可以离线匿名玩的游戏。只要他们愿意,他们就可以通过 Facebook 进行身份验证,并可以 post 将他们的分数提交到排行榜并参与挑战。它看起来很简单。不是!

现在我遇到了一个我没想到的架构问题,我想问一下是否已经有一个标准的方法来解决它。

假设: 用户在本地存储他们的个人分数,直到他们进行身份验证。 当它们连接时,在线服务会在线存储分数。 设备和服务器要同步,让用户通过不同设备尽可能保持分数,服务器可以用他的分数来匹配和排行榜。

现在,如果发生什么情况:

  1. 之前认证过的玩家,离线玩?新的分数会在第一次连接客户端=>服务器同步。

  2. 一位玩家更改了 facebook 个人资料。分数存储在本地,所以新用户使用旧分数进行游戏,当用户连接服务时,根据1,同步客户端=>服务器将玩家1的分数推送给新玩家。错了!

  3. 一名玩家保持相同的 facebook 个人资料,但更换了设备。新设备上的分数是0,所以同步应该是server => client而不是client => server。另外,每当他回到以前的设备时,同步应该是服务器 => 客户端而不是客户端 => 服务器。

实际上,结合这三个方面会出现很多其他问题:更改用户、更改设备、离线播放。

考虑可能的解决方案我考虑过对 fb id、分数、简单的数字计数器或保存日期执行的可能检查,本地和远程,但没有完整的解决方案,并且总是有条件玩家可能会失去他们的分数,或者新玩家可以获得更强玩家的分数。

是否有一些算法、最佳实践、体系结构或任何可以帮助我解决这个(奇怪的)问题的东西?

这不是一个完美的解决方案,而是我在玩游戏时观察到的一种行为,它使用 google 玩游戏服务来同步数据。

当我在不同的设备上离线玩一段时间然后上线时,这些游戏会提示我对话。

此对话框告诉我服务器上有不同的配置文件可用,我是要加载该配置文件(保存状态)还是继续使用当前配置文件。

  1. 如果我 select 继续使用当前配置文件,我当前的配置文件将上传到服务器上,而之前的配置文件将丢失。
  2. 如果我select从服务器加载配置文件,我的当前配置文件会丢失,我的游戏会与服务器同步。

此外,如果我更改我的 google 帐户,我也会丢失所有已保存的配置文件。(之前同步的配置文件在较早的帐户上仍然可用)

这不是一个完美的解决方案,但它有效并让用户可以选择如何处理 his/her 游戏数据。

还要注意,考虑到用户可以使用多个连接不稳定的设备,任何解决方案都不可能是完美的。

我想我得出了一个部分的结论,也许以后会更好。

我将 FBid 和序列号与分数一起存储。为了涵盖最常见的情况 我们需要两者

这是我认为同步过程需要的初始方案:

 public void Sync()
{
if (local.FBid == null)
    // there's no FBid stored locally, so it's the first connection to
    // an online profile from this device.
    // The user might have used his profile before, so we cannot trust
    // a simple client-> server sync that would wipe the online score.
    // On the other hand, the user could have played a lot offline and
    // now decided to finally go online and export his score, that would
    // be lost with a server -> client sync.
    // To decide which profile is better we must trust the serial, considering
    // that a empty profile has serial 0.
    // We must understand if there is already a online profile.
    // If there is not, create it, otherwise take the one with the highest serial.
    // To do that we initialize and simply fall in the successive case.
{
    local.FBid = used.FBid;
}

if (local.FBid == used.FBid)
    // the local user is the same as the online user, we have to check if the player has advanced
    // the score playing offline. In that case the server will be updated.
    // Instead if the player is on a new device or increased the score using a different device,
    // the client will be updated.
    // there's no way to guarantee coherence if the player uses two devices on the same time, obviously.
{
    if (local.serial > server.serial) // supposing that a non-existant profile has serial == 0
        SyncClientToServer(); // update or create
    else
        SyncServerToClient();

} else // if (local.FBid != used.FBid)
    // the local stored user is not the same that has been used for the authentication.
    // the player is asked two options:
    // 1. wipe the local score and get the currently authenticated user from the server (that may be empty)
    // 2. keep the local score as it is, but play offline (without any sync) until the correct authentication is done
{
    if (AskWipeData())
        SyncServerToClient();
    else
        logoff(); // allow user to change the profile or go on playing offline
}

}