Skip to content

Commit 4b91ac6

Browse files
committed
finalize game of life for both languages
1 parent 4315964 commit 4b91ac6

File tree

10 files changed

+171
-79
lines changed

10 files changed

+171
-79
lines changed

Cargo.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,15 @@ debug = true
111111
inherits = "release"
112112
debug = true
113113

114-
# [[example]]
115-
# name = "game_of_life"
116-
# path = "examples/game_of_life.rs"
117-
# required-features = ["lua54", "bevy/file_watcher", "bevy/multi_threaded"]
114+
[[example]]
115+
name = "game_of_life"
116+
path = "examples/game_of_life.rs"
117+
required-features = [
118+
"lua54",
119+
"rhai",
120+
"bevy/file_watcher",
121+
"bevy/multi_threaded",
122+
]
118123

119124
[workspace.lints.clippy]
120125
panic = "deny"

assets/scripts/game_of_life.lua

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
LifeState = world.get_type_by_name("LifeState")
22
Settings = world.get_type_by_name("Settings")
33

4-
world.info("Lua: The game_of_life.lua script just got loaded")
4+
info("Lua: The game_of_life.lua script just got loaded")
55

66
math.randomseed(os.time())
77

@@ -12,8 +12,8 @@ function fetch_life_state()
1212
end
1313

1414
function on_script_loaded()
15-
world.info("Lua: Hello! I am initiating the game of life simulation state with randomness!")
16-
world.info("Lua: Click on the screen to set cells alive after running the `gol start` command")
15+
info("Lua: Hello! I am initiating the game of life simulation state with randomness!")
16+
info("Lua: Click on the screen to set cells alive after running the `gol start` command")
1717

1818
local life_state = fetch_life_state()
1919
local cells = life_state.cells
@@ -27,8 +27,7 @@ end
2727

2828
function on_click(x,y)
2929
-- get the settings
30-
world.info("Lua: Clicked at x: " .. x .. " y: " .. y)
31-
print(entity)
30+
info("Lua: Clicked at x: " .. x .. " y: " .. y)
3231
local life_state = fetch_life_state()
3332
local cells = life_state.cells
3433

@@ -110,7 +109,7 @@ function on_update()
110109
end
111110

112111
function on_script_unloaded()
113-
world.info("Lua: I am being unloaded, goodbye!")
112+
info("Lua: I am being unloaded, goodbye!")
114113

115114
-- set state to 0's
116115
local life_state = fetch_life_state()

assets/scripts/game_of_life.rhai

Lines changed: 91 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,100 @@
1+
info.call("Rhai: the game_of_life.rhai script just got loaded");
2+
3+
4+
fn fetch_life_state() {
5+
let LifeState = world.get_type_by_name.call("LifeState");
6+
let Settings = world.get_type_by_name.call("Settings");
7+
for (v,i) in world.query.call().component.call(LifeState).build.call(){
8+
return v.components.call()[0]
9+
}
10+
}
11+
12+
113
fn on_script_loaded() {
2-
world.info("Game of Life script loaded");
3-
// let LifeState = world.get_type_by_name("LifeState");
4-
// let life_state = world.get_component(entity,LifeState);
5-
// let cells = life_state.cells;
6-
7-
// // set some cells alive
8-
// for x in 1..10000 {
9-
// let index = rand(0..cells.len());
10-
// cells[index] = 255;
11-
// }
14+
let LifeState = world.get_type_by_name.call("LifeState");
15+
let Settings = world.get_type_by_name.call("Settings");
16+
17+
info.call("Rhai: Hello! I am initiating the game of life simulation state with randomness!");
18+
info.call("Rhai: Click on the screen to set cells alive after running the `gol start` command");
19+
20+
let life_state = fetch_life_state!();
21+
let cells = life_state.cells;
22+
let cells_len = cells.len.call();
23+
let x = 0;
24+
while x < 1000 {
25+
let index = to_int(floor(rand.call()*cells_len)) ;
26+
cells[index] = 255;
27+
x += 1;
28+
}
1229
}
1330

14-
fn on_update() {
31+
fn on_click(x,y) {
32+
let Settings = world.get_type_by_name.call("Settings");
33+
let LifeState = world.get_type_by_name.call("LifeState");
34+
35+
info.call("Rhai: Clicked at x: "+ x + ", y: " + y );
36+
let life_state = fetch_life_state!();
37+
let cells = life_state.cells;
38+
39+
let settings = world.get_resource.call(Settings);
40+
let dimensions = settings.physical_grid_dimensions;
41+
let screen = settings.display_grid_dimensions;
42+
43+
let dimension_x = dimensions["_0"];
44+
let dimension_y = dimensions["_1"];
1545

16-
let LifeState = world.get_type_by_name("LifeState");
17-
let Settings = world.get_type_by_name("Settings");
46+
let screen_x = screen["_0"];
47+
let screen_y = screen["_1"];
1848

19-
let life_state = world.get_component(entity,LifeState);
49+
let cell_width = screen_x / dimension_x;
50+
let cell_height = screen_y / dimension_y;
51+
52+
let cell_x = to_int(x / cell_width);
53+
let cell_y = to_int(y / cell_height);
54+
55+
let index = cell_y * dimension_x + cell_x;
56+
let cell_offsets_x = [0, 1, 0, 1, -1, 0, -1, 1, -1];
57+
let cell_offsets_y = [0, 0, 1, 1, 0, -1, -1, -1, 1];
58+
for (v,i) in cell_offsets_x {
59+
let offset_x = cell_offsets_x[i];
60+
let offset_y = cell_offsets_y[i];
61+
let new_index = index + offset_x + offset_y * dimension_x;
62+
if new_index >= 0 && new_index < (dimension_x * dimension_y) {
63+
cells[new_index] = 255;
64+
}
65+
}
66+
67+
}
68+
69+
fn on_update() {
70+
let LifeState = world.get_type_by_name.call("LifeState");
71+
let Settings = world.get_type_by_name.call("Settings");
72+
73+
let life_state = fetch_life_state!();
2074
let cells = life_state.cells;
2175

2276

2377
// note that here we do not make use of RhaiProxyable and just go off pure reflection
24-
let settings = world.get_resource(Settings);
78+
let settings = world.get_resource.call(Settings);
2579
let dimensions = settings.physical_grid_dimensions;
26-
80+
let dimension_x = dimensions["_0"];
81+
let dimension_y = dimensions["_1"];
2782

2883
// primitives are passed by value to rhai, keep a hold of old state but turn 255's into 1's
2984
let prev_state = [];
3085
for (v,k) in life_state.cells {
3186
prev_state.push(life_state.cells[k] != 0);
3287
}
3388

34-
for i in 0..(dimensions[0] * dimensions[1]) {
35-
let north = prev_state.get(i - dimensions[0]);
36-
let south = prev_state.get(i + dimensions[0]);
89+
for i in 0..(dimension_x * dimension_y) {
90+
let north = prev_state.get(i - dimension_x);
91+
let south = prev_state.get(i + dimension_x);
3792
let east = prev_state.get(i + 1);
3893
let west = prev_state.get(i - 1);
39-
let northeast = prev_state.get(i - dimensions[0] + 1);
40-
let southeast = prev_state.get(i + dimensions[0] + 1);
41-
let northwest = prev_state.get(i - dimensions[0] - 1);
42-
let southwest = prev_state.get(i + dimensions[0] - 1);
94+
let northeast = prev_state.get(i - dimension_x + 1);
95+
let southeast = prev_state.get(i + dimension_x + 1);
96+
let northwest = prev_state.get(i - dimension_x - 1);
97+
let southwest = prev_state.get(i + dimension_x - 1);
4398

4499
let neighbours = 0;
45100
if north == () || north {neighbours+=1}
@@ -60,5 +115,18 @@ fn on_update() {
60115
cells[i] = 0;
61116
}
62117
}
118+
}
119+
120+
fn on_script_unloaded() {
121+
let LifeState = world.get_type_by_name.call("LifeState");
122+
let Settings = world.get_type_by_name.call("Settings");
63123

124+
info.call("Rhai: I am being unloaded, goodbye!");
125+
126+
// set state to 0's
127+
let life_state = fetch_life_state();
128+
let cells = life_state.cells;
129+
for i in 0..cells.len.call() {
130+
cells[i] = 0;
131+
}
64132
}

crates/bevy_mod_scripting_core/src/handler.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use bevy::{
1616
system::{Resource, SystemState},
1717
world::World,
1818
},
19-
log::{debug, trace},
19+
log::trace,
2020
prelude::{EventReader, Events, Query, Ref},
2121
};
2222

@@ -127,15 +127,18 @@ pub(crate) fn event_handler_internal<L: IntoCallbackLabel, P: IntoScriptPluginPa
127127
}
128128
_ => (),
129129
}
130-
debug!(
131-
"Handling event for script {} on entity {:?}",
132-
script_id, entity
130+
trace!(
131+
"{}: Handling event for script {} on entity {:?}",
132+
P::LANGUAGE,
133+
script_id,
134+
entity
133135
);
134136
let script = match res_ctxt.scripts.scripts.get(script_id) {
135137
Some(s) => s,
136138
None => {
137139
trace!(
138-
"Script `{}` on entity `{:?}` is either still loading or doesn't exist, ignoring.",
140+
"{}: Script `{}` on entity `{:?}` is either still loading or doesn't exist, ignoring.",
141+
P::LANGUAGE,
139142
script_id, entity
140143
);
141144
continue;

crates/languages/bevy_mod_scripting_lua/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,14 @@ pub fn lua_handler(
209209
let handler: Function = match context.globals().raw_get(callback_label.as_ref()) {
210210
Ok(handler) => handler,
211211
// not subscribed to this event type
212-
Err(_) => return Ok(ScriptValue::Unit),
212+
Err(_) => {
213+
bevy::log::trace!(
214+
"Script {} is not subscribed to callback {}",
215+
script_id,
216+
callback_label.as_ref()
217+
);
218+
return Ok(ScriptValue::Unit);
219+
}
213220
};
214221

215222
let input = MultiValue::from_vec(

crates/languages/bevy_mod_scripting_rhai/src/lib.rs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use bevy_mod_scripting_core::{
1818
};
1919
use bindings::{
2020
reference::{ReservedKeyword, RhaiReflectReference, RhaiStaticReflectReference},
21-
script_value::IntoDynamic,
21+
script_value::{FromDynamic, IntoDynamic},
2222
};
23-
use rhai::{CallFnOptions, Engine, FnPtr, Scope, AST};
23+
use rhai::{CallFnOptions, Dynamic, Engine, EvalAltResult, Scope, AST};
2424

2525
pub use rhai;
2626
pub mod bindings;
@@ -224,23 +224,38 @@ pub fn rhai_callback_handler(
224224
.iter()
225225
.try_for_each(|init| init(script_id, entity, context))?;
226226

227-
if context
228-
.scope
229-
.get_value::<FnPtr>(callback.as_ref())
230-
.is_none()
231-
{
232-
// not subscribed to this handler
233-
return Ok(ScriptValue::Unit);
234-
};
235-
236227
// we want the call to be able to impact the scope
237228
let options = CallFnOptions::new().rewind_scope(false);
238-
let out = runtime.call_fn_with_options::<ScriptValue>(
229+
let args = args
230+
.into_iter()
231+
.map(|v| v.into_dynamic())
232+
.collect::<Result<Vec<_>, _>>()?;
233+
234+
bevy::log::trace!(
235+
"Calling callback {} in script {} with args: {:?}",
236+
callback,
237+
script_id,
238+
args
239+
);
240+
match runtime.call_fn_with_options::<Dynamic>(
239241
options,
240242
&mut context.scope,
241243
&context.ast,
242244
callback.as_ref(),
243245
args,
244-
)?;
245-
Ok(out)
246+
) {
247+
Ok(v) => Ok(ScriptValue::from_dynamic(v)?),
248+
Err(e) => {
249+
if let EvalAltResult::ErrorFunctionNotFound(_, _) = e.unwrap_inner() {
250+
bevy::log::trace!(
251+
"Script {} is not subscribed to callback {} with the provided arguments.",
252+
script_id,
253+
callback
254+
);
255+
Ok(ScriptValue::Unit)
256+
} else {
257+
Err(ScriptError::from(e))
258+
}
259+
}
260+
}
246261
}

crates/xtask/src/main.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,6 @@ impl Features {
138138
)
139139
}
140140

141-
fn non_exclusive_features() -> Self {
142-
Self(
143-
<Feature as strum::VariantArray>::VARIANTS
144-
.iter()
145-
.filter(|f| !f.to_feature_group().is_exclusive())
146-
.cloned()
147-
.collect(),
148-
)
149-
}
150-
151141
fn to_cargo_args(&self) -> Vec<String> {
152142
if self.0.is_empty() {
153143
vec![]

examples/game_of_life.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ use bevy_console::{make_layer, AddConsoleCommand, ConsoleCommand, ConsoleOpen, C
1515
use bevy_mod_scripting::ScriptFunctionsPlugin;
1616
use bevy_mod_scripting_core::{
1717
asset::ScriptAsset,
18-
bindings::{function::namespace::NamespaceBuilder, script_value::ScriptValue},
18+
bindings::{
19+
function::namespace::{GlobalNamespace, NamespaceBuilder},
20+
script_value::ScriptValue,
21+
},
1922
callback_labels,
2023
event::ScriptCallbackEvent,
2124
handler::event_handler,
2225
script::ScriptComponent,
2326
};
2427
use bevy_mod_scripting_lua::LuaScriptingPlugin;
25-
// use bevy_mod_scripting_rhai::RhaiScriptingPlugin;
28+
use bevy_mod_scripting_rhai::RhaiScriptingPlugin;
2629
use clap::Parser;
2730

2831
// CONSOLE SETUP
@@ -98,7 +101,7 @@ fn game_of_life_app(app: &mut App) -> &mut App {
98101
.add_plugins((
99102
// for scripting
100103
LuaScriptingPlugin::default(),
101-
// RhaiScriptingPlugin::default(),
104+
RhaiScriptingPlugin::default(),
102105
ScriptFunctionsPlugin,
103106
))
104107
.register_type::<LifeState>()
@@ -114,9 +117,9 @@ fn game_of_life_app(app: &mut App) -> &mut App {
114117
send_on_update.after(update_rendered_state),
115118
(
116119
event_handler::<OnUpdate, LuaScriptingPlugin>,
117-
// event_handler::<OnUpdate, RhaiScriptingPlugin>,
120+
event_handler::<OnUpdate, RhaiScriptingPlugin>,
118121
event_handler::<OnClick, LuaScriptingPlugin>,
119-
// event_handler::<OnClick, RhaiScriptingPlugin>,
122+
event_handler::<OnClick, RhaiScriptingPlugin>,
120123
)
121124
.after(send_on_update),
122125
),
@@ -168,9 +171,11 @@ pub fn load_script_assets(
168171

169172
pub fn register_script_functions(app: &mut App) -> &mut App {
170173
let world = app.world_mut();
171-
NamespaceBuilder::<World>::new_unregistered(world).register("info", |s: String| {
172-
bevy::log::info!(s);
173-
});
174+
NamespaceBuilder::<GlobalNamespace>::new_unregistered(world)
175+
.register("info", |s: String| {
176+
bevy::log::info!(s);
177+
})
178+
.register("rand", || rand::random::<f32>());
174179
app
175180
}
176181

@@ -274,10 +279,7 @@ callback_labels!(
274279

275280
/// Sends events allowing scripts to drive update logic
276281
pub fn send_on_update(mut events: EventWriter<ScriptCallbackEvent>) {
277-
events.send(ScriptCallbackEvent::new_for_all(
278-
OnUpdate,
279-
vec![ScriptValue::Unit],
280-
));
282+
events.send(ScriptCallbackEvent::new_for_all(OnUpdate, vec![]));
281283
}
282284

283285
pub fn send_on_click(

0 commit comments

Comments
 (0)