实现一个ECS+Actor游戏服务器框架(3) 数据落库脏标记模块

在修改完玩家的数据后,需要将修改的数据进行保存。 有几种方式

  • 玩家离线后保存全量数据
  • 定时保存脏数据

一般的项目都是定时保存脏数据的,脏数据何时标记为脏,以及哪些字段为脏需要开发者处理。

脏数据的标记方式

在平时的开发中碰到了这几种脏数据的标记方式

set访问器

在C#中可以将脏标记处理逻辑放到set访问器中实现精准定位哪些字段被改变。

public class Player
{
    private int _health;

    public int Health
    {
        get => _health;
        set
        {
            if (_health != value)
            {
                ... 脏标记处理
                _health = value;
            }
        }
    }
}

当然set访问器这种方式是最精准的知晓数据是否有改动,但是手写get/set很烦人

基础类型int、string等可以通过set访问器去判断是否有修改,但是如果字段是Dictionary、List,此时调用了Add/Remove方法照样能避开set访问器,更不用提如果字段是用户自定义的引用类型。

ET框架中GetComponent触发事件

在ET框架中,Entity调用GetComponent方法时,会触发一个事件,在事件的处理逻辑中可将Get的组件放到待处理列表,表示这个组件被修改,需要被保存。

这个做法并不好,有很多时候GetComponent并不会修改里面的数据,不仅会导致序列化浪费CPU,如果没有进行处理还会执行很多不必要的逻辑。

Lua

通过 __newindex和 __index元方法拦截所有读写操作。

设计目标

用C#实现一个脏标记系统,用于游戏服务器中数据落地模块。

  • 支持跟踪基础类型如int,string
  • 支持跟踪集合如Dictionary,List,HashSet
  • 用户不用手写多余代码,只需要定义model,在model类上加特性即可使用脏标记系统。可在字段上加特性,跟踪指定字段。
  • 支持跟踪用户自定义类型字段
  • 支持序列化,反序列化

C#的高级开发者,看到设计目标,基本上就知道怎么实现了。如果看不出来,说明不够高级: )

支持以下用法的脏标记检测

[DirtyTrackable]
public partial class Player
{
    [DirtyTrack] private int _health;
    [DirtyTrack] private string _name;
    [DirtyTrack] private List<Item> _inventory = new List<Item>();
    [DirtyTrack] private Item _item;
}
[DirtyTrackable]
public partial class Item
{
    [DirtyTrack] private string _itemId;
    [DirtyTrack] private int _quantity;  
}

var player = new Player();

player.Health -= 10; // 基础类型修改检测
player.Inventory.Add(new Item() { ItemId = "sword", Quantity = 1 }); // 集合本身修改检测
player.Item.ItemId = "IsDirty"; // 自定义嵌套类型检测
player.Inventory[0].Quantity--; // 集合中的可追踪类型检测
player.Inventory = new List<Item>(); // 支持直接赋值新集合

体验了一下,效果非常不错。仅仅需要加特性即可体验到便利。

返回顶部