use bevy_ecs::prelude::*;
#[derive(Debug, Clone)]
#[allow(dead_code)]
struct MockGraphicsData {
id: u32,
}
#[derive(Component, Debug)]
struct WindowGraphicsOptional {
inner: Option<MockGraphicsData>,
generation: u64,
}
impl WindowGraphicsOptional {
fn new(id: u32) -> Self {
Self {
inner: Some(MockGraphicsData { id }),
generation: 0,
}
}
fn is_valid(&self) -> bool {
self.inner.is_some()
}
fn invalidate(&mut self) {
self.inner = None;
}
fn reinitialize(&mut self, id: u32) {
self.inner = Some(MockGraphicsData { id });
self.generation += 1;
}
}
#[derive(Component, Debug)]
struct WindowGraphicsWithFlag {
data: MockGraphicsData,
needs_reinit: bool,
generation: u64,
}
impl WindowGraphicsWithFlag {
fn new(id: u32) -> Self {
Self {
data: MockGraphicsData { id },
needs_reinit: false,
generation: 0,
}
}
fn is_valid(&self) -> bool {
!self.needs_reinit
}
fn invalidate(&mut self) {
self.needs_reinit = true;
}
fn reinitialize(&mut self, id: u32) {
self.data = MockGraphicsData { id };
self.needs_reinit = false;
self.generation += 1;
}
}
#[derive(Component, Debug)]
struct WindowGraphics {
data: MockGraphicsData,
generation: u64,
}
#[derive(Component, Debug)]
struct NeedsReinitialize;
impl WindowGraphics {
fn new(id: u32) -> Self {
Self {
data: MockGraphicsData { id },
generation: 0,
}
}
fn reinitialize(&mut self, id: u32) {
self.data = MockGraphicsData { id };
self.generation += 1;
}
}
#[test]
fn test_pattern1_optional_lifecycle() {
let mut world = World::new();
let entity = world.spawn(WindowGraphicsOptional::new(1)).id();
{
let wg = world
.entity(entity)
.get::<WindowGraphicsOptional>()
.unwrap();
assert!(wg.is_valid(), "初期状態では有効");
assert_eq!(wg.generation, 0);
}
{
let mut wg = world.get_mut::<WindowGraphicsOptional>(entity).unwrap();
wg.invalidate();
}
{
let wg = world
.entity(entity)
.get::<WindowGraphicsOptional>()
.unwrap();
assert!(!wg.is_valid(), "無効化後は無効");
}
{
let mut wg = world.get_mut::<WindowGraphicsOptional>(entity).unwrap();
wg.reinitialize(2);
}
{
let wg = world
.entity(entity)
.get::<WindowGraphicsOptional>()
.unwrap();
assert!(wg.is_valid(), "再初期化後は有効");
assert_eq!(wg.generation, 1);
}
eprintln!("[Pattern1 Lifecycle] テスト成功");
}
#[test]
fn test_pattern2_flag_lifecycle() {
let mut world = World::new();
let entity = world.spawn(WindowGraphicsWithFlag::new(1)).id();
{
let wg = world
.entity(entity)
.get::<WindowGraphicsWithFlag>()
.unwrap();
assert!(wg.is_valid(), "初期状態では有効");
assert_eq!(wg.generation, 0);
}
{
let mut wg = world.get_mut::<WindowGraphicsWithFlag>(entity).unwrap();
wg.invalidate();
}
{
let wg = world
.entity(entity)
.get::<WindowGraphicsWithFlag>()
.unwrap();
assert!(!wg.is_valid(), "無効化後は無効");
}
{
let mut wg = world.get_mut::<WindowGraphicsWithFlag>(entity).unwrap();
wg.reinitialize(2);
}
{
let wg = world
.entity(entity)
.get::<WindowGraphicsWithFlag>()
.unwrap();
assert!(wg.is_valid(), "再初期化後は有効");
assert_eq!(wg.generation, 1);
}
eprintln!("[Pattern2 Flag Lifecycle] テスト成功");
}
#[test]
fn test_pattern3_separate_component_lifecycle() {
let mut world = World::new();
let entity = world.spawn(WindowGraphics::new(1)).id();
{
let has_marker = world.entity(entity).get::<NeedsReinitialize>().is_some();
assert!(!has_marker, "初期状態では無効化マーカーなし");
}
{
world.entity_mut(entity).insert(NeedsReinitialize);
}
{
let has_marker = world.entity(entity).get::<NeedsReinitialize>().is_some();
assert!(has_marker, "無効化後はマーカーあり");
}
{
let mut wg = world.get_mut::<WindowGraphics>(entity).unwrap();
wg.reinitialize(2);
world.entity_mut(entity).remove::<NeedsReinitialize>();
}
{
let has_marker = world.entity(entity).get::<NeedsReinitialize>().is_some();
assert!(!has_marker, "再初期化後はマーカー削除");
let wg = world.entity(entity).get::<WindowGraphics>().unwrap();
assert_eq!(wg.generation, 1);
}
eprintln!("[Pattern3 Separate Component Lifecycle] テスト成功");
}
#[test]
fn test_pattern1_changed_detection() {
let mut world = World::new();
let _e1 = world.spawn(WindowGraphicsOptional::new(1)).id();
let _e2 = world.spawn(WindowGraphicsOptional::new(2)).id();
let mut schedule = Schedule::default();
fn check_changed(query: Query<Entity, Changed<WindowGraphicsOptional>>) {
let count = query.iter().count();
eprintln!("[Changed Detection] {count} entities detected");
}
schedule.add_systems(check_changed);
eprintln!("=== 初回実行 ===");
schedule.run(&mut world);
eprintln!("=== 2回目実行(変更なし) ===");
schedule.run(&mut world);
{
let mut wg = world.get_mut::<WindowGraphicsOptional>(_e1).unwrap();
wg.invalidate();
}
eprintln!("=== 3回目実行(e1を無効化) ===");
schedule.run(&mut world);
eprintln!("[Pattern1 Changed Detection] テスト成功");
}
#[test]
fn test_pattern2_changed_detection() {
let mut world = World::new();
let _e1 = world.spawn(WindowGraphicsWithFlag::new(1)).id();
let _e2 = world.spawn(WindowGraphicsWithFlag::new(2)).id();
let mut schedule = Schedule::default();
fn check_changed(query: Query<Entity, Changed<WindowGraphicsWithFlag>>) {
let count = query.iter().count();
eprintln!("[Changed Detection] {count} entities detected");
}
schedule.add_systems(check_changed);
eprintln!("=== 初回実行 ===");
schedule.run(&mut world);
eprintln!("=== 2回目実行(変更なし) ===");
schedule.run(&mut world);
{
let mut wg = world.get_mut::<WindowGraphicsWithFlag>(_e1).unwrap();
wg.invalidate();
}
eprintln!("=== 3回目実行(e1を無効化) ===");
schedule.run(&mut world);
eprintln!("[Pattern2 Changed Detection] テスト成功");
}
#[test]
fn test_pattern3_marker_query() {
let mut world = World::new();
let _e1 = world.spawn(WindowGraphics::new(1)).id();
let e2 = world.spawn(WindowGraphics::new(2)).id();
let _e3 = world.spawn(WindowGraphics::new(3)).id();
world.entity_mut(e2).insert(NeedsReinitialize);
let mut schedule = Schedule::default();
fn check_needs_reinit(query: Query<Entity, With<NeedsReinitialize>>) {
let entities: Vec<_> = query.iter().collect();
eprintln!(
"[Needs Reinit Query] {} entities need reinit",
entities.len()
);
assert_eq!(entities.len(), 1, "e2のみマーカーあり");
}
schedule.add_systems(check_needs_reinit);
schedule.run(&mut world);
eprintln!("[Pattern3 Marker Query] テスト成功");
}