azure - 存储重播数据的最佳方式

标签 azure database-design azure-cosmosdb

我目前正在分析一个游戏重播文件,并且想知道存储数据的最佳方式,以便我可以快速创建复杂的查询。例如,分析器每 50 毫秒返回一个数据结构,您可以在其中访问当前回合详细信息和游戏中当前玩家状态的快照,例如他持有什么武器、他有多少生命值、他当前射击了哪些玩家等等。我想要能够说:从重播文件开始到 10000 毫秒,玩家“Micheal”的位置是什么。从 10000 毫秒到 20000 毫秒,玩家“凯尔”对其他玩家造成了多少伤害。我希望能够存储正在分析的所有数据,并使用 API 在前端重播它,以便您可以直观地重播它。

我可以将有关重播的元数据存储到数据库中,例如:(第 1 轮,开始时间:10000,结束时间:30000),(第 2 轮,开始时间:31000,结束时间:37000)。我还可以存储玩家被杀时的元数据(Kyle,DeathTime:31000,KilledBy:Micheal)或玩家受伤时的元数据(Kyle,HurtBy:Micheal,伤害:10,武器:x)。

为了实现我想要为不同情况创建复杂查询的目标,我是否需要将两者结合起来?例如,将逐毫秒的数据存储在 NoSql 数据库/文档中,然后解析整个文件并将元数据存储在第二段中提到的另一个数据库中。仅存储逐毫秒的数据,然后能够创建快速查询来解析我想要的内容,这是不可行的吗?

最佳答案

听起来您正在开发一款很酷的游戏。 Microsoft Azure Table Storage (NoSQL 数据库)非常快,非常适合您的游戏。您可以使用Slazure (我编码为 Slazure BTW),其中包含查询语言(自定义 LINQ 提供程序),并且还将数据存储在 Azure 表存储中。如果我在游戏中使用 Slazure 和 Microsoft Azure Table Storage NoSQL 数据库,我将按照以下方式进行操作。我建议您在每个事件的 PlayersTable 表中存储一行,其中 PartitionKey 是玩家姓名,RowKey 是您进入游戏回合的毫秒数 - 因为每个表都在PartitionKey 列并按 RowKey 列排序,使用这些列的所有查询确实都非常快。还为所使用的武器、屏幕上的位置、生命值、回合数以及哪个玩家被谁杀死创建了列。您可以使用与下面相同的建议方法创建一个表来保存损坏数据:

using SysSurge.Slazure;
using SysSurge.Slazure.Linq;
using SysSurge.Slazure.Linq.QueryParser;

namespace TableOperations
{
    public class PlayerInfo
    {
        // List of weapons
        public enum WeaponList {
            Axe, Arrow, Knife, Sling
        };

        // Update a player with some new data
        public void UpdatePlayerData(dynamic playersTable, DateTime gameStartedTime, int round, string playerName, WeaponList weapon, int healthPoints, int xPos, int yPos)
        {
            // Create an entity in the Players table using the player name as the PartitionKey, the entity is created if it doesn't already exist
            var player = playersTable.Entity(playerName);

            // Store the time the event was recorded for later as milliseconds since the game started. 
            // This means there is one row for each stored player event
            player.Rowkey = ((DateTime.UtcNow.Ticks - gameStartedTime.Ticks)/10000).ToString("d19");

            player.Round = round; // Round number
            player.Weapon = (int)weapon; // Weapon carried by player. Example Axe

            // Store player X and Y position coordinates on the screen
            player.X = xPos;
            player.Y = yPos;

            // Number of health points, zero means player is dead
            player.HealthPoints = healthPoints; 

            // Save the entity to the Azure Table Service storage
            player.Save()
       }

        // Update a player with some new data
        public void PlayerKilled(dynamic playersTable, DateTime gameStartedTime, int round, string playerName, string killedByPlayerName)
        {
            // Create an entity in the Players table using the player name as the PartitionKey, the entity is created if it doesn't already exist
            var player = playersTable.Entity(playerName);

            // Store the time the event was recorded for later as milliseconds since the game started. 
            // This means there is one row for each stored player event
            player.Rowkey = ((DateTime.UtcNow.Ticks - gameStartedTime.Ticks)/10000).ToString("d19");

            player.Round = round; // Round number

            // Number of health points, zero means player is dead
            player.HealthPoints = 0;    

            player.KilledByPlayerName = killedByPlayerName; // Killed by this player, example "Kyle"

            // Save the entity to the Azure Table Service storage
            player.Save()
       }

        // Get all the player positions between two time intervals
        public System.Linq.IQueriable GetPlayerPositions(dynamic playersTable, string playerName, int fromMilliseconds, int toMilliseconds, int round)
        {
            return playersTable.Where("PrimaryKey == @0 && RowKey >= @1 && RowKey <= @2 && Round == @3", 
                playerName, fromMilliseconds.ToString("d19"), toMilliseconds.ToString("d19"), round).Select("new(X, Y)");
        }      

    }
}

首先你需要记录比赛开始的时间和轮数:

var gameStartedTime = DateTime.UtcNow;
var round = 1;  // Round #1

,并在NoQL数据库中创建一个表:

// Get a reference to the Table Service storage
dynamic storage = new DynStorage("UseDevelopmentStorage=true");

// Get reference to the Players table, it's created if it doesn't already exist
dynamic playersTable = storage.Players;

现在,在游戏过程中您可以不断更新玩家信息,如下所示:

UpdatePlayerData(playersTable, gameStartedTime, round, "Micheal", WeaponList.Axe, 45, 12313, 2332);
UpdatePlayerData(playersTable, gameStartedTime, round, "Kyle", WeaponList.Knife, 100, 13343, 2323);

如果您需要在每个存储事件之间等待 50 毫秒,您可以执行以下操作:

System.Threading.Thread.Sleep(50);

,然后存储更多的玩家事件数据:

UpdatePlayerData(playersTable, gameStartedTime, round, "Micheal", WeaponList.Axe, 12, 14555, 1990);
UpdatePlayerData(playersTable, gameStartedTime, round, "Kyle", WeaponList.Sling, 89, 13998, 2001);

当其中一名玩家死亡时,您可以使用零生命值和杀死他/她的玩家的名字来调用相同的方法:

PlayerKilled(playersTable, gameStartedTime, round, "Micheal", "Kyle");

现在,稍后在游戏分析器中,您可以查询从游戏开始(0 毫秒)到游戏进入 10,000 毫秒的所有位置,如下所示:

// Get a reference to the table storage and the table
dynamic queryableStorage = new QueryableStorage<DynEntity>("UseDevelopmentStorage=true");
QueryableTable<DynEntity> queryablePlayersTable = queryableStorage.PlayersTable;

var playerPositionsQuery = GetPlayerPositions(queryablePlayersTable, "Micheal", 0, 10000, round);

// Cast the query result to a dynamic so that we can get access its dynamic properties
foreach (dynamic player in playerPositionsQuery)
{
    // Show player positions in the console
    Console.WriteLine("Player position: Name=" + player.PrimaryKey + ", Game time MS " + player.RowKey + ", X-position=" + player.X  + ", Y-position=" + player.Y;
}

关于azure - 存储重播数据的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32403547/

相关文章:

node.js - azure 中的前端和后端分离

mysql - 如何跟踪谁添加/编辑了当前信息

Azure 流分析不提供 DocumentDB 输出接收器

Azure Cosmos 数据库 - 在没有数据的情况下克隆 Cosmos 数据库帐户?

asp.net - 我无法使用 "host.docker.internal:some-port"将我的 ASP .NET 应用程序从 Docker 容器连接到我的计算机主机数据库

azure - 发布具有多种功能的Azure App功能项目

azure - Azure Pipeline 完成后无法看到我的构建工件

linux - Azure Docker Web App - 无法更新容器设置的数据

python - db中memoization的数据结构

mysql - 关系表的复合索引