1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! Lua Entity UserData
//!
//! Provides Lua bindings for Bevy Entity with lifetime safety.
use bevy::prelude::*;
use mlua::{prelude::*, UserData};
/// Lua wrapper for Bevy Entity with World access
///
/// This is passed to Lua scripts to represent an entity.
/// All operations check entity lifetime safety via SafeEntityRef.
#[derive(Clone)]
pub struct LuaEntity {
entity: Entity,
// TODO: Add World access (via Arc<RwLock<World>> or similar)
}
impl LuaEntity {
/// Create a new LuaEntity
pub fn new(entity: Entity) -> Self {
Self { entity }
}
/// Get the underlying Entity
pub fn entity(&self) -> Entity {
self.entity
}
}
impl UserData for LuaEntity {
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
// entity:has_component(type_name) -> bool
methods.add_method("has_component", |_lua, this, type_name: String| {
// TODO: Implement with World access and SafeEntityRef
tracing::warn!(
"has_component('{}') called on entity {:?} - not yet implemented",
type_name,
this.entity
);
Ok(false)
});
// entity:get_component(type_name) -> table | error
methods.add_method(
"get_component",
|_lua, this, type_name: String| -> LuaResult<LuaTable> {
// TODO: Implement with Reflection
tracing::warn!(
"get_component('{}') called on entity {:?} - not yet implemented",
type_name,
this.entity
);
Err(LuaError::RuntimeError(
"get_component not yet implemented".to_string(),
))
},
);
// entity:set_component(type_name, data) -> () | error
methods.add_method(
"set_component",
|_lua, this, (type_name, _data): (String, LuaTable)| -> LuaResult<()> {
// TODO: Implement with Reflection
tracing::warn!(
"set_component('{}') called on entity {:?} - not yet implemented",
type_name,
this.entity
);
Err(LuaError::RuntimeError(
"set_component not yet implemented".to_string(),
))
},
);
// entity:despawn() -> () | error
methods.add_method("despawn", |_lua, this, ()| -> LuaResult<()> {
// TODO: Implement with Commands
tracing::warn!(
"despawn() called on entity {:?} - not yet implemented",
this.entity
);
Err(LuaError::RuntimeError(
"despawn not yet implemented".to_string(),
))
});
// entity:id() -> number (for debugging)
methods.add_method("id", |_lua, this, ()| Ok(this.entity.to_bits()));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lua_entity_creation() {
let mut world = World::new();
let entity = world.spawn_empty().id();
let lua_entity = LuaEntity::new(entity);
assert_eq!(lua_entity.entity(), entity);
}
#[test]
fn test_lua_entity_methods_available() {
let lua = Lua::new();
let mut world = World::new();
let entity = world.spawn_empty().id();
let lua_entity = LuaEntity::new(entity);
// Test that methods are available
lua.globals().set("entity", lua_entity).unwrap();
// Test id() method
let entity_bits: u64 = lua.load(r#"return entity:id()"#).eval().unwrap();
assert_eq!(entity_bits, entity.to_bits());
// Test has_component() stub (returns false for now)
let has_component: bool = lua
.load(r#"return entity:has_component("Health")"#)
.eval()
.unwrap();
assert!(!has_component);
// Test get_component() stub (returns error)
let result = lua
.load(r#"return entity:get_component("Health")"#)
.eval::<LuaValue>();
assert!(result.is_err());
// Test set_component() stub (returns error)
let result = lua
.load(r#"return entity:set_component("Health", {current = 100})"#)
.eval::<LuaValue>();
assert!(result.is_err());
// Test despawn() stub (returns error)
let result = lua.load(r#"return entity:despawn()"#).eval::<LuaValue>();
assert!(result.is_err());
}
}