#save-load #game-state #atomic #world #system #game-engine #entities

bevy_atomic_save

Bevy游戏引擎的原子保存/加载系统

5个版本

0.2.2 2023年2月8日
0.2.1 2023年1月30日
0.2.0 2023年1月19日
0.1.1 2023年1月18日
0.1.0 2022年12月23日

#1814 in 游戏开发

26 每月下载量

自定义许可证

29KB
254

☢️ Bevy Atomic Save

Bevy的原子保存/加载系统。

特性

  • World保存到磁盘上的RON文件中
  • 控制哪些实体应参与保存/加载操作
  • 操作是同步的,可以精确控制保存/加载发生的时间
  • 用于在文本格式中检查世界而无需任何样板代码的实用功能。

概述

使用最新的Bevy版本,可以将世界的状态保存到DynamicScene(见示例)。虽然这种方法对场景管理和编辑很有用,但将相同的方法用于保存和加载游戏状态并不实用。

在大多数典型情况下,游戏只需保存世界的一小部分,以便可以从磁盘恢复其状态。游戏的可视和美学元素,如UI、模型、精灵、相机或逻辑系统,通常在游戏启动时初始化,因此不需要序列化。

此crate通过提供标记需要保存和加载的实体的框架以及将实体保存到/从磁盘的功能来解决这个问题。

使用方法

保存

  1. 确保将SavePlugin添加到您的App中。
use bevy_atomic_save::SavePlugin;
...
app.add_plugin(SavePlugin);
  1. 使用Save组件标记任何需要保存的实体。这可以是Bundle,也可以像普通组件一样插入。标记为保存的实体应具有派生自Reflect的组件。任何未派生自Reflect的组件都不会被保存。
use bevy::prelude::*;
use bevy_atomic_save::Save;

#[derive(Bundle)]
struct PlayerBundle {
    /* ... Serializable Player Data ... */
    save: Save,
}
  1. 使用SaveWorld通过&mut World&mut Commands将世界保存到磁盘。
use bevy::prelude::*;
use bevy_atomic_save::SaveWorld;

fn trigger_save(mut commands: Commands) {
    commands.save("world.ron");
}

加载

  1. 使用Unload标记在加载之前需要卸载的任何实体。
use bevy::prelude::*;
use bevy_atomic_save::Unload;

#[derive(Bundle)]
struct PlayerModelBundle {
    /* ... Player Transform, Mesh, Sprite, etc. ... */
    unload: Unload,
}
  1. 使用 LoadWorld 通过一个 &mut World&mut Commands 加载之前保存的文件。
    这会启动一个加载过程,首先反序列化给定的文件,然后递归销毁所有带有 SaveUnload 组件的实体。最后,生成新的实体并开始 SaveStage::PostLoad
use bevy::prelude::*;
use bevy_atomic_save::LoadWorld;

fn trigger_load(mut commands: Commands) {
    commands.load("world.ron");
}
  1. SaveStage::PostLoad 期间更新实体引用。
    在加载过程中,不能保证保存的实体索引得到保留。这是因为当前世界中可能已经有实体占用了这些索引,而这些实体在加载之前无法被销毁。因此,任何引用实体的组件应在 SaveStage::PostLoad 期间更新其引用实体。
    这可以通过为任何引用实体的组件实现 FromLoaded 特性,然后使用 RegisterLoaded 在你的 app 中注册这些组件来实现。
    有关如何实现此操作的具体示例,请参阅 ./examples/pawn.rs
    或者,也可以通过在 SaveStage::PostLoad 中添加一个系统并直接读取 Loaded 资源来手动实现。
use bevy::prelude::*;
use bevy_atomic_save::{FromLoaded, RegisterLoaded};

#[derive(Component)]
struct SomeEntity(Entity);
impl FromLoaded for SomeEntity {
    fn from_loaded(&mut self, loaded: &Loaded) {
        self.0.from_loaded(loaded);
    }
}

...

app.register_loaded::<SomeEntity>();

注意

资源

目前,Bevy 中的 DynamicScene 不会保存 Resource 项。为了保存/加载资源,建议将保存的资源作为带有 Save 组件的实体生成。这也让你可以精确控制哪些资源应该被保存。

Bevy 组件和实体引用

Bevy 中的一些组件引用实体(例如 ParentChildren),它们需要在 SaveStage::PostLoad 期间更新其引用。此crate提供此功能。在大多数情况下,您不需要保存此类组件,因为它们通常属于可能从加载的游戏数据生成的场景实体。

世界转储

在开发过程中,可能需要检查特定帧中的原始文本格式下的世界,用于诊断目的。此crate提供了一种简单的函数来执行此操作,它使用底层的保存系统将世界状态转储到RON文件。有关详细信息,请参阅 SaveWorld::dump

转储和保存请求之间的唯一区别是,转储保存所有实体,而保存只保存具有 Save 组件的实体。

转储的结果不应加载,因为它可能导致实体重复。

未来计划

  • 提供异步选项

依赖项

~17-32MB
~515K SLoC