实现一个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>(); // 支持直接赋值新集合
体验了一下,效果非常不错。仅仅需要加特性即可体验到便利。