Skip to content

Commit 7743b2e

Browse files
committed
Implement ScriptValue things
1 parent 8bfd501 commit 7743b2e

File tree

15 files changed

+691
-475
lines changed

15 files changed

+691
-475
lines changed

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,11 @@
2323
"/home/makspll/git/bevy_mod_scripting/check.sh"
2424
],
2525
"rust-analyzer.showUnlinkedFileNotification": false,
26+
"rust-analyzer.runnables.extraTestBinaryArgs": [
27+
"--show-output",
28+
],
29+
"rust-analyzer.runnables.extraArgs": [
30+
"--profile=release-with-debug",
31+
],
2632
// "rust-analyzer.semanticHighlighting.operator.enable": false
2733
}

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ codegen-units = 8
105105
incremental = false
106106
debug = false
107107

108+
[profile.release-with-debug]
109+
inherits = "release"
110+
debug = true
111+
108112
[[example]]
109113
name = "console_integration_lua"
110114
path = "examples/lua/console_integration.rs"

assets/scripts/bevy_api.lua

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,22 @@ end
99

1010
function on_event()
1111

12-
world:spawn()
12+
print(entity)
13+
print(script)
14+
print(world)
1315

14-
world:exit()
1516

16-
-- print(entity)
17-
-- print(script)
18-
-- print(world)
17+
local my_component_type = world:get_type_by_name("MyComponent")
1918

19+
local comp = world:get_component(entity, my_component_type)
20+
print("Before script: ", comp:print_value())
2021

21-
-- local my_component_type = world:get_type_by_name("MyComponent")
22-
23-
-- local comp = world:get_component(entity, my_component_type)
24-
-- print("Before script: ", comp)
25-
26-
-- print("\noption")
27-
-- print(comp.option_usize)
28-
-- comp.option_usize = 69
29-
-- print(comp.option_usize)
30-
-- comp.option_usize = nil
31-
-- print(comp.option_usize)
22+
print("\noption")
23+
print(comp.option_usize)
24+
comp.option_usize = 69
25+
print(comp.option_usize)
26+
comp.option_usize = nil
27+
print(comp.option_usize)
3228

3329
-- print("\nvec")
3430
-- print(table_to_string(comp.vec_of_usize))

crates/bevy_mod_scripting_core/src/bindings/function.rs

Lines changed: 86 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
use std::{borrow::Cow, sync::Arc};
2-
3-
use bevy::reflect::func::{
4-
args::{Arg, ArgInfo, Ownership},
5-
ArgList, ArgValue, DynamicFunction, FunctionResult, Return,
1+
use std::{borrow::Cow, ops::Deref, sync::Arc};
2+
3+
use bevy::reflect::{
4+
func::{
5+
args::{Arg, ArgInfo, Ownership},
6+
ArgList, ArgValue, DynamicFunction, FunctionResult, Return,
7+
},
8+
PartialReflect,
69
};
710

8-
use crate::error::{ScriptError, ScriptResult};
11+
use crate::error::{ScriptError, ScriptResult, ValueConversionError};
912

1013
use super::{
11-
access_map::ReflectAccessId, pretty_print::DisplayWithWorld, script_val::ScriptValue,
14+
access_map::ReflectAccessId,
15+
pretty_print::DisplayWithWorld,
16+
script_val::{FromScriptValue, IntoScriptValue, ScriptValue},
1217
ReflectBase, ReflectReference, WorldAccessGuard, WorldCallbackAccess, WorldGuard,
1318
};
1419

@@ -22,6 +27,18 @@ pub trait CallableWithAccess {
2227
world: Arc<WorldAccessGuard>,
2328
f: F,
2429
) -> ScriptResult<O>;
30+
31+
fn dynamic_call<I: IntoIterator<Item = ScriptValue>>(
32+
&self,
33+
args: I,
34+
world: Arc<WorldAccessGuard>,
35+
) -> ScriptResult<ScriptValue> {
36+
self.with_call(args, world.clone(), |r| match r {
37+
Return::Owned(partial_reflect) => partial_reflect.as_ref().into_script_value(world),
38+
Return::Ref(ref_) => ref_.into_script_value(world),
39+
Return::Mut(mut_ref) => mut_ref.into_script_value(world),
40+
})?
41+
}
2542
}
2643

2744
impl CallableWithAccess for DynamicFunction<'_> {
@@ -33,14 +50,6 @@ impl CallableWithAccess for DynamicFunction<'_> {
3350
) -> ScriptResult<O> {
3451
let info = self.info().args();
3552

36-
// if info.len() != args.len() {
37-
// return Err(ScriptError::new_reflection_error(format!(
38-
// "Expected {} arguments, got {}",
39-
// info.len(),
40-
// args.len()
41-
// )));
42-
// }
43-
4453
// We need to:
4554
// 1. Claim the correct access for each argument
4655
// 2. Convert to ArgsList for the function call
@@ -50,10 +59,28 @@ impl CallableWithAccess for DynamicFunction<'_> {
5059
// 6. Return the result
5160
let arg_iter = args.into_iter();
5261

53-
let (args_list, mut accesses) = arg_iter.into_args_list_with_access(info, world.clone())?;
54-
// let arc_world = &arc_world;
62+
let (mut args_list, mut accesses) =
63+
arg_iter.into_args_list_with_access(info, world.clone())?;
5564

56-
let return_val = match self.call(args_list) {
65+
let mut final_args_list = ArgList::default();
66+
// we sometimes want to use the boxed value in the arg instead of allocating and refing to it.
67+
// for this reason let's be lenient in calling functions. Allow passing owned values as refs
68+
for (arg, info) in args_list.iter_mut().zip(info.iter()) {
69+
let next_arg = match (arg, info.ownership()) {
70+
(ArgValue::Owned(r), Ownership::Ref) => {
71+
ArgValue::Ref((r as &Box<dyn PartialReflect>).as_ref())
72+
}
73+
(ArgValue::Owned(r), Ownership::Mut) => ArgValue::Mut(r.as_mut()),
74+
(v, _) => {
75+
// muahaha, shouldn't allocate due to ZST
76+
let a = std::mem::replace(v, ArgValue::Owned(Box::new(())));
77+
a
78+
}
79+
};
80+
final_args_list = final_args_list.push_arg(next_arg);
81+
}
82+
83+
let return_val = match self.call(final_args_list) {
5784
Ok(return_val) => return_val,
5885
Err(e) => {
5986
// Safety: we have not generated any unsafe aliases
@@ -85,7 +112,7 @@ pub trait IntoArgsListWithAccess {
85112
self,
86113
arg_info: &[ArgInfo],
87114
world: WorldGuard<'w>,
88-
) -> ScriptResult<(ArgList<'w>, Vec<(ReflectAccessId, Ownership)>)>;
115+
) -> ScriptResult<(Vec<ArgValue<'w>>, Vec<(ReflectAccessId, Ownership)>)>;
89116
}
90117

91118
impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
@@ -97,17 +124,16 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
97124
self,
98125
arg_info: &[ArgInfo],
99126
world: WorldGuard<'w>,
100-
) -> ScriptResult<(ArgList<'w>, Vec<(ReflectAccessId, Ownership)>)> {
101-
// if self.len() != arg_info.len() {
102-
// return Err(ScriptError::new_reflection_error(format!(
103-
// "Expected {} arguments, got {}",
104-
// arg_info.len(),
105-
// self.len()
106-
// )));
107-
// }
108-
127+
) -> ScriptResult<(Vec<ArgValue<'w>>, Vec<(ReflectAccessId, Ownership)>)> {
109128
let mut accesses = Vec::default();
110-
let mut arg_list = ArgList::new();
129+
let mut arg_list = Vec::default();
130+
131+
let release_accesses = |accesses: &mut Vec<(ReflectAccessId, Ownership)>| {
132+
accesses.iter().for_each(|(id, _)| {
133+
// Safety: we have not generated any unsafe aliases
134+
unsafe { world.release_access(*id) };
135+
});
136+
};
111137

112138
for (value, arg_info) in self.zip(arg_info.iter()) {
113139
match value {
@@ -116,7 +142,7 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
116142
ReflectAccessId::for_reference(arg_ref.base.base_id.clone()).ok_or_else(|| {
117143
ScriptError::new_reflection_error(format!(
118144
"Could not call function, argument: {:?}, with type: {} is not a valid reference. Have you registered the type?",
119-
arg_info.name(),
145+
arg_info.name().map(str::to_owned).unwrap_or_else(|| arg_info.index().to_string()),
120146
arg_ref.display_with_world(world.clone())
121147
))
122148
})?;
@@ -130,10 +156,7 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
130156
};
131157

132158
if !success {
133-
accesses.drain(..).for_each(|(id, _)| {
134-
// Safety: we have not generated any unsafe aliases
135-
unsafe { world.release_access(id) };
136-
});
159+
release_accesses(&mut accesses);
137160
return Err(ScriptError::new_reflection_error(format!(
138161
"Could not claim access for argument {}",
139162
arg_ref.display_with_world(world.clone())
@@ -146,22 +169,43 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
146169
let val = match val {
147170
Ok(v) => v,
148171
Err(e) => {
172+
release_accesses(&mut accesses);
173+
return Err(e);
174+
}
175+
};
176+
arg_list.push(val);
177+
}
178+
ScriptValue::World => {
179+
arg_list.push(ArgValue::Owned(Box::new(WorldCallbackAccess::from_guard(
180+
world.clone(),
181+
))));
182+
}
183+
value => {
184+
let value = match <dyn PartialReflect>::from_script_value(
185+
value,
186+
world.clone(),
187+
arg_info.type_id(),
188+
) {
189+
Some(Ok(v)) => v,
190+
Some(Err(e)) => {
149191
// Safety: Same as above
150-
151192
accesses.iter().for_each(|(id, _)| {
152193
unsafe { world.release_access(*id) };
153194
});
154195
return Err(e);
155196
}
197+
None => {
198+
release_accesses(&mut accesses);
199+
return Err(ValueConversionError::TypeMismatch {
200+
expected_type: arg_info.type_path().into(),
201+
actual_type: None,
202+
}
203+
.into());
204+
}
156205
};
157-
arg_list = arg_list.push_arg(val);
158-
}
159-
ScriptValue::World => {
160-
arg_list = arg_list.push_arg(ArgValue::Owned(Box::new(
161-
WorldCallbackAccess::from_guard(world.clone()),
162-
)));
206+
207+
arg_list.push(ArgValue::Owned(value));
163208
}
164-
v => todo!(),
165209
}
166210
}
167211

crates/bevy_mod_scripting_core/src/bindings/query.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ use crate::{
77
use bevy::{
88
ecs::{component::ComponentId, entity::Entity},
99
prelude::{EntityRef, QueryBuilder},
10-
reflect::TypeRegistration,
10+
reflect::{Reflect, TypeRegistration},
1111
};
1212
use std::{any::TypeId, collections::VecDeque, sync::Arc};
1313

1414
/// A wrapper around a `TypeRegistration` that provides additional information about the type.
1515
///
1616
/// This is used as a hook to a rust type from a scripting language. We should be able to easily convert between a type name and a [`ScriptTypeRegistration`].
17-
#[derive(Clone)]
17+
#[derive(Clone, Reflect)]
18+
#[reflect(opaque)]
1819
pub struct ScriptTypeRegistration {
1920
pub(crate) registration: Arc<TypeRegistration>,
2021
pub component_id: Option<ComponentId>,

crates/bevy_mod_scripting_core/src/bindings/reference.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,13 +277,10 @@ impl ReflectReference {
277277
/// # Safety
278278
/// - The caller must ensure this reference has permission to access the underlying value
279279
pub unsafe fn into_arg_value<'w>(self, world: WorldGuard<'w>, arg_info: &ArgInfo) -> ScriptResult<ArgValue<'w>> {
280-
println!("A {}", Arc::strong_count(&world));
281-
println!("{:?}", self);
282280
if ReflectBase::World == self.base.base_id {
283281
// Safety: we already have an Arc<WorldAccessGuard<'w>> so creating a new one from the existing one is safe
284282
// as the caller of this function will make sure the Arc is dropped after the lifetime 'w is done.
285283
let new_guard = WorldCallbackAccess::from_guard(world.clone());
286-
println!("B {}", Arc::strong_count(&world));
287284
new_guard.read().unwrap();
288285
return Ok(ArgValue::Owned(Box::new(WorldCallbackAccess::from_guard(world))));
289286
}
@@ -573,6 +570,23 @@ impl ReflectionPathElem {
573570
pub fn new_deferred<I: Into<DeferredReflection>>(defref: I) -> Self {
574571
Self::DeferredReflection(defref.into())
575572
}
573+
574+
/// Assumes the accesses are 1 indexed and converts them to 0 indexed
575+
pub fn convert_to_0_indexed(&mut self){
576+
match self {
577+
ReflectionPathElem::Reflection(path) => {
578+
path.0.iter_mut().for_each(|a| match a.access {
579+
bevy::reflect::Access::FieldIndex(ref mut i) => *i -= 1,
580+
bevy::reflect::Access::TupleIndex(ref mut i) => *i -= 1,
581+
bevy::reflect::Access::ListIndex(ref mut i) => *i -= 1,
582+
_ => {}
583+
});
584+
},
585+
ReflectionPathElem::DeferredReflection(_) => {},
586+
ReflectionPathElem::MapAccess(_) => {},
587+
ReflectionPathElem::Identity => {},
588+
};
589+
}
576590
}
577591

578592
impl<A: 'static, B: 'static> From<(A, B)> for DeferredReflection

0 commit comments

Comments
 (0)