2 个版本
0.0.2 | 2024 年 3 月 19 日 |
---|---|
0.0.1 | 2024 年 2 月 18 日 |
#787 in 游戏开发
每月 100 次下载
68KB
1K SLoC
实体关系映射器(基于 bevy 构建)
一个 bevy 插件,旨在通过实体组件系统架构辅助数据库访问。
将单个用户请求传递到 ECS 作为事件。系统可以使用允许从数据库加载 ECS 中的实体的数据库查询。一旦实体现在内存中被修改,它们会在请求的刷新事件发生后刷新回数据库。每个请求都打开一个新的数据库事务,以保持请求之间的隔离。
┌────────────────────────────────────────────────────┐
│ │
│ Web Server │
│ │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Requests │ │ Responses │ │
│ │ │ │ │ │
│ │ ┌───────┐ │ │ ┌───────┐ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └───────┘ │ │ └───────┘ │ │
│ │ │ │ │ │
│ │ ┌───────┐ │ │ ┌───────┐ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └───────┘ │ │ └───────┘ │ │
│ │ │ │ │ │
│ │ ┌───────┐ │ │ ┌───────┐ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └───────┘ │ │ └───────┘ │ │
│ │ │ │ │ │
│ └───┬─────────────┘ └─────────────▲───┘ │
│ │ │ │
│ │ │ │
└────────┼──────────────────────────────────┼────────┘
│ │
Requests│ │Events
create │ ┌────────┐ │create
events │ │ │ │response
│ ┌─┴──────┐ │ │
│ │ │ │ │
└──────────► Event │ ├────────────┘
│ │ │
│ ├─┘
└───┬──▲─┘
Systems │ │
process │ │
events │ │
┌───▼──┴──────────┐
│ │
┌───┴───────────────┐ │
│ Business Logic │ │
│ Systems │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ │ │
│ ├─┘
└───┬─────────────▲─┘
│ │
Queries │ │ Queries
access the│ │ return
database │ │ components
┌─────────────▼┐ ┌┴─────────────────────────────────────┐
│ Database │ loaded │ Entities │
│ │ in as │ │
│ │ components│ ┌────────┐ ┌────────┐ │
│ ├───────────┤ Entity 1: │ Comp 1 │ │ Comp 2 │ │
│ │ │ ───────┴────────┴───┴────────┘ │
│ │ │ │
│ │ │ ┌────────┐ │
│ │ │ Entity 2: │ Comp 2 │ │
│ │ │ ─────────────────────┴────────┘ │
└──────────────┘ │ │
└──────────────────────────────────────┘
使用方法
目前仅开发了 SQLite 数据库作为 Database Resource
实现。因此,这仅适用于 SQLite 数据库。请随意为新的数据库资源添加问题。
使用 DBQueryDerive
派生宏来生成组件映射器,将数据库行映射到组件。结构体上的每个属性都被视为 SQLite 数据库中的列。
例如,创建一个用户组件
use async_trait::async_trait;
use bevy::prelude::*;
use bevy_erm::*;
use bevy_erm_derive::DBQueryDerive;
#[derive(Component, sqlx::FromRow, DBQueryDerive)]
#[table_name = "users"]
pub struct User {
pub name: String,
pub age: i32,
}
例如,如果您有一个网络服务器资源,则可以从中提取消息。然后开始一个新的事务以获取用户的名称。
DatabaseResource
特性定义了如何查询访问实际数据库。使用 sqlx 的 Sqlite 数据库连接器已在 SqlxSqliteDatabaseResource
下。
use bevy::prelude::*;
use bevy_erm::*;
pub fn handle_webserver_events(
db: Res<SqlxSqliteDatabaseResource>,
webserver: Res<WebServer>, // Your own defined resource
) {
while webserver.messages_to_handle() {
let http_request = webserver.pop();
let user_id = http_request.user_id;
if let Some(request) = db.try_start_new_transaction() {
let purchase_event = GetUserNameEvent {
user_id,
request,
};
// Forward the event on to the next system
purchase_events.send(purchase_event);
} else {
// All connections are used
// wait for next round
break;
}
}
}
添加一个系统来查询用户以处理 GetUserNameEvent
。打印用户名称。
use bevy::prelude::*;
use bevy_erm::*;
pub fn print_user_names(
users: DatabaseQuery<&User>,
mut get_user_names_events: EventReader<GetUserNameEvent>,
) {
for get_user_name_event in get_user_names_events.read() {
let request = get_user_name_event.request;
let user_id = get_user_name_event.user_id;
let user = users.get(&(user_id, request))
.await.unwrap();
println!("{}", user.name);
}
}
设置 bevy 应用
fn main() {
App::new()
.set_runner(runner)
.init_resource::<WebServer>()
.add_event::<GetUserNameEvent>()
// Add the bevy_erm plugin
.add_plugins(EntityRelationMapperPlugin)
// Specify how if components were created or updated how they
// would be flushed to the database
.add_systems(PostUpdate, flush_component_to_db::<Option<&User>, SqlxSqliteDatabaseResource>)
// Add the created systems above
.add_systems(Update, handle_webserver_events)
.add_systems(Update, print_user_names)
// Add other systems
// ...
.run();
}
示例
位于 ./examples 中
依赖关系
62MB
~1M SLoC