Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Engel Simulator 2020
Engel Simulator 2020
Commits
1aa9b988
Commit
1aa9b988
authored
Feb 24, 2021
by
Simon Goller
Committed by
Rahix
Apr 02, 2021
Browse files
Use more error handling
Replace most of the panic calls by error handling with anyhow.
parent
0218844a
Changes
26
Hide whitespace changes
Inline
Side-by-side
src/angel_shifts/bottle_angel.rs
View file @
1aa9b988
...
...
@@ -5,6 +5,7 @@ use crate::resources;
use
crate
::
sprites
;
use
crate
::
svg_loader
;
use
crate
::
utils
;
use
anyhow
::
Context
;
pub
struct
BottleAngelShift
{
hours
:
usize
,
...
...
@@ -12,26 +13,29 @@ pub struct BottleAngelShift {
}
impl
BottleAngelShift
{
pub
fn
generate
(
rng
:
&
mut
impl
rand
::
Rng
)
->
BottleAngelShift
{
pub
fn
generate
(
rng
:
&
mut
impl
rand
::
Rng
)
->
anyhow
::
Result
<
BottleAngelShift
>
{
use
rand
::
seq
::
SliceRandom
;
let
compatible_levels
=
[
"assembly-hall-1.svg"
,
"ccl-ground-level.svg"
];
BottleAngelShift
{
Ok
(
BottleAngelShift
{
hours
:
rng
.gen_range
(
1
,
3
),
level
:
compatible_levels
.choose
(
rng
)
.unwrap
()
.to_string
(),
}
level
:
compatible_levels
.choose
(
rng
)
.context
(
"Compatible level not found"
)
?
.to_string
(),
})
}
}
impl
super
::
AngelShiftImpl
for
BottleAngelShift
{
fn
metadata
(
&
self
)
->
super
::
ShiftMetadata
{
super
::
ShiftMetadata
{
fn
metadata
(
&
self
)
->
anyhow
::
Result
<
super
::
ShiftMetadata
>
{
Ok
(
super
::
ShiftMetadata
{
title
:
"Bottle Angel"
.to_owned
(),
description
:
"Collect bottles from all bottle drop points in the designated area."
.to_owned
(),
hours
:
self
.hours
,
}
}
)
}
fn
level_name
(
&
self
)
->
&
str
{
...
...
@@ -44,17 +48,16 @@ impl super::AngelShiftImpl for BottleAngelShift {
resources
:
&
mut
legion
::
Resources
,
schedule_builder
:
&
mut
legion
::
systems
::
Builder
,
level
:
&
svg_loader
::
SvgLevel
,
)
{
)
->
anyhow
::
Result
<
()
>
{
// Display objective
let
objective
=
utils
::
get_element_by_id
::
<
web_sys
::
Element
>
(
"ingame-objective"
)
.unwrap
()
;
let
objective
=
utils
::
get_element_by_id
::
<
web_sys
::
Element
>
(
"ingame-objective"
)
?
;
objective
.set_inner_html
(
r#"
<text x="30" y="0" class="stats-label">Collect drop points:</text>
<text id="ingame-bottle-angel-stats" x="430" y="0" class="stats-number">0/4</text>
"#
,
);
let
stats
=
utils
::
get_element_by_id
::
<
web_sys
::
Element
>
(
"ingame-bottle-angel-stats"
)
.unwrap
();
let
stats
=
utils
::
get_element_by_id
::
<
web_sys
::
Element
>
(
"ingame-bottle-angel-stats"
)
?
;
entities
::
create_drop_points
(
world
,
level
);
resources
.insert
(
BottleAngelState
::
new
(
4
,
stats
));
...
...
@@ -62,6 +65,7 @@ impl super::AngelShiftImpl for BottleAngelShift {
schedule_builder
.add_thread_local
(
collect_bottledrops_system
())
.add_thread_local
(
update_bottle_shift_system
(
self
.hours
));
Ok
(())
}
}
...
...
@@ -98,24 +102,29 @@ pub fn collect_bottledrops(
#[resource]
player
:
&
resources
::
Player
,
#[resource]
collision_world
:
&
colliders
::
CollisionWorld
,
#[resource]
bottle_angel_state
:
&
mut
BottleAngelState
,
)
{
)
->
anyhow
::
Result
<
()
>
{
use
legion
::
IntoQuery
;
let
collider
=
<&
colliders
::
Collider
>
::
query
()
.get
(
world
,
player
.0
)
.
unwrap
()
;
.
context
(
"Couldn't find player"
)
?
;
let
mut
bottledrops
=
<
(
&
components
::
Matebottledrop
,
&
mut
components
::
Sprite
)
>
::
query
();
for
pair
in
collision_world
.world
.proximities_with
(
collider
.handle
.
unwrap
()
,
false
)
.
unwrap
()
.proximities_with
(
collider
.handle
.
context
(
"No collider handler"
)
?
,
false
)
.
context
(
"Proximities not found"
)
?
{
if
pair
.3
!=
ncollide2d
::
query
::
Proximity
::
Intersecting
{
continue
;
}
let
entity
=
*
collision_world
.world.objects
.get
(
pair
.1
)
.unwrap
()
.data
();
let
entity
=
*
collision_world
.world
.objects
.get
(
pair
.1
)
.context
(
"Couldn't find counterpart"
)
?
.data
();
if
let
Ok
((
_
,
sprite
))
=
bottledrops
.get_mut
(
world
,
entity
)
{
*
sprite
=
components
::
Sprite
::
new
(
sprites
::
Sprite
::
BottleDropPointEmpty
);
cmd
.remove_component
::
<
components
::
Matebottledrop
>
(
entity
);
...
...
@@ -123,6 +132,7 @@ pub fn collect_bottledrops(
bottle_angel_state
.update_stats
();
}
}
Ok
(())
}
#[legion::system]
...
...
@@ -133,15 +143,16 @@ pub fn update_bottle_shift(
#[resource]
player
:
&
mut
resources
::
Player
,
#[resource]
bottle_angel_state
:
&
mut
BottleAngelState
,
#[resource]
game_manager
:
&
mut
resources
::
GameManager
,
)
{
)
->
anyhow
::
Result
<
()
>
{
use
legion
::
IntoQuery
;
if
bottle_angel_state
.collected_drops
>=
bottle_angel_state
.drops_in_map
{
let
player
=
<&
mut
components
::
Player
>
::
query
()
.get_mut
(
world
,
player
.0
)
.
unwrap
()
;
.
context
(
"Player not found"
)
?
;
player
.collected_hours
+=
*
hours_to_award
as
u32
;
*
hours_to_award
=
0
;
game_manager
.request_return_to_heaven
();
}
Ok
(())
}
src/angel_shifts/definitions.rs
View file @
1aa9b988
...
...
@@ -4,7 +4,7 @@ pub trait AngelShiftImpl {
/// Return metadata about this shift.
///
/// Used in heaven to display what task is up next.
fn
metadata
(
&
self
)
->
ShiftMetadata
;
fn
metadata
(
&
self
)
->
anyhow
::
Result
<
ShiftMetadata
>
;
/// Return name of the selected level for this shift.
fn
level_name
(
&
self
)
->
&
str
;
...
...
@@ -20,7 +20,7 @@ pub trait AngelShiftImpl {
resources
:
&
mut
legion
::
Resources
,
schedule_builder
:
&
mut
legion
::
systems
::
Builder
,
level
:
&
svg_loader
::
SvgLevel
,
);
)
->
anyhow
::
Result
<
()
>
;
}
pub
struct
ShiftMetadata
{
...
...
@@ -35,7 +35,7 @@ pub struct ShiftMetadata {
pub
struct
AngelShift
(
pub
Box
<
dyn
AngelShiftImpl
>
);
impl
AngelShift
{
pub
fn
metadata
(
&
self
)
->
ShiftMetadata
{
pub
fn
metadata
(
&
self
)
->
anyhow
::
Result
<
ShiftMetadata
>
{
self
.0
.metadata
()
}
...
...
@@ -49,8 +49,8 @@ impl AngelShift {
resources
:
&
mut
legion
::
Resources
,
schedule_builder
:
&
mut
legion
::
systems
::
Builder
,
level
:
&
svg_loader
::
SvgLevel
,
)
{
)
->
anyhow
::
Result
<
()
>
{
self
.0
.init_gameworld
(
world
,
resources
,
schedule_builder
,
level
)
;
.init_gameworld
(
world
,
resources
,
schedule_builder
,
level
)
}
}
src/angel_shifts/mod.rs
View file @
1aa9b988
...
...
@@ -6,10 +6,10 @@ pub use definitions::AngelShift;
pub
use
definitions
::
AngelShiftImpl
;
pub
use
definitions
::
ShiftMetadata
;
pub
fn
generate_random_shift
(
rng
:
&
mut
impl
rand
::
Rng
)
->
AngelShift
{
AngelShift
(
match
rng
.gen_range
(
0usize
,
2
)
{
0
=>
Box
::
new
(
bottle_angel
::
BottleAngelShift
::
generate
(
rng
)),
1
=>
Box
::
new
(
network_switch
::
NetworkSwitchShift
::
generate
(
rng
)),
pub
fn
generate_random_shift
(
rng
:
&
mut
impl
rand
::
Rng
)
->
anyhow
::
Result
<
AngelShift
>
{
Ok
(
AngelShift
(
match
rng
.gen_range
(
0usize
,
2
)
{
0
=>
Box
::
new
(
bottle_angel
::
BottleAngelShift
::
generate
(
rng
)
?
),
1
=>
Box
::
new
(
network_switch
::
NetworkSwitchShift
::
generate
(
rng
)
?
),
_
=>
unreachable!
(),
})
})
)
}
src/angel_shifts/network_switch.rs
View file @
1aa9b988
...
...
@@ -5,6 +5,7 @@ use crate::resources;
use
crate
::
sprites
;
use
crate
::
svg_loader
;
use
crate
::
utils
;
use
anyhow
::
Context
;
pub
struct
NetworkSwitchShift
{
hours
:
usize
,
...
...
@@ -12,15 +13,18 @@ pub struct NetworkSwitchShift {
}
impl
NetworkSwitchShift
{
pub
fn
generate
(
rng
:
&
mut
impl
rand
::
Rng
)
->
NetworkSwitchShift
{
pub
fn
generate
(
rng
:
&
mut
impl
rand
::
Rng
)
->
anyhow
::
Result
<
NetworkSwitchShift
>
{
use
rand
::
seq
::
SliceRandom
;
let
compatible_levels
=
[
"assembly-hall-1.svg"
];
NetworkSwitchShift
{
Ok
(
NetworkSwitchShift
{
hours
:
rng
.gen_range
(
1
,
3
),
level
:
compatible_levels
.choose
(
rng
)
.unwrap
()
.to_string
(),
}
level
:
compatible_levels
.choose
(
rng
)
.context
(
"Compatible level not found"
)
?
.to_string
(),
})
}
}
...
...
@@ -48,12 +52,12 @@ impl NetworkSwitchAngelState {
}
impl
super
::
AngelShiftImpl
for
NetworkSwitchShift
{
fn
metadata
(
&
self
)
->
super
::
ShiftMetadata
{
super
::
ShiftMetadata
{
fn
metadata
(
&
self
)
->
anyhow
::
Result
<
super
::
ShiftMetadata
>
{
Ok
(
super
::
ShiftMetadata
{
title
:
"Fix the internet"
.to_owned
(),
description
:
"Check what's wrong with the network switches."
.to_owned
(),
hours
:
self
.hours
,
}
}
)
}
fn
level_name
(
&
self
)
->
&
str
{
...
...
@@ -66,22 +70,23 @@ impl super::AngelShiftImpl for NetworkSwitchShift {
resources
:
&
mut
legion
::
Resources
,
schedule_builder
:
&
mut
legion
::
systems
::
Builder
,
level
:
&
svg_loader
::
SvgLevel
,
)
{
)
->
anyhow
::
Result
<
()
>
{
// Display objective
let
objective
=
utils
::
get_element_by_id
::
<
web_sys
::
Element
>
(
"ingame-objective"
)
.unwrap
()
;
let
objective
=
utils
::
get_element_by_id
::
<
web_sys
::
Element
>
(
"ingame-objective"
)
?
;
objective
.set_inner_html
(
r#"
<text x="30" y="0" class="stats-label">Switches online:</text>
<text id="ingame-network-stats" x="430" y="0" class="stats-number">0/4</text>
"#
,
);
let
stats
=
utils
::
get_element_by_id
::
<
web_sys
::
Element
>
(
"ingame-network-stats"
)
.unwrap
()
;
let
stats
=
utils
::
get_element_by_id
::
<
web_sys
::
Element
>
(
"ingame-network-stats"
)
?
;
entities
::
create_network_switches
(
world
,
level
);
resources
.insert
(
NetworkSwitchAngelState
::
new
(
4
,
stats
));
schedule_builder
.add_thread_local
(
reconnect_switches_system
())
.add_thread_local
(
update_network_switch_shift_system
(
self
.hours
));
Ok
(())
}
}
...
...
@@ -95,24 +100,32 @@ pub fn reconnect_switches(
#[resource]
player
:
&
resources
::
Player
,
#[resource]
collision_world
:
&
colliders
::
CollisionWorld
,
#[resource]
angel_state
:
&
mut
NetworkSwitchAngelState
,
)
{
)
->
anyhow
::
Result
<
()
>
{
use
legion
::
IntoQuery
;
let
collider
=
<&
colliders
::
Collider
>
::
query
()
.get
(
world
,
player
.0
)
.
unwrap
()
;
.
context
(
"Player not found"
)
?
;
let
mut
switches
=
<
(
&
components
::
NetworkSwitch
,
&
mut
components
::
Sprite
)
>
::
query
();
for
pair
in
collision_world
.world
.proximities_with
(
collider
.handle
.unwrap
(),
false
)
.unwrap
()
.proximities_with
(
collider
.handle
.context
(
"Collider handler not found"
)
?
,
false
,
)
.context
(
"Proximities not found"
)
?
{
if
pair
.3
!=
ncollide2d
::
query
::
Proximity
::
Intersecting
{
continue
;
}
let
entity
=
*
collision_world
.world.objects
.get
(
pair
.1
)
.unwrap
()
.data
();
let
entity
=
*
collision_world
.world
.objects
.get
(
pair
.1
)
.context
(
"Couldn't find counterpart"
)
?
.data
();
if
let
Ok
((
_
,
sprite
))
=
switches
.get_mut
(
world
,
entity
)
{
*
sprite
=
components
::
Sprite
::
new
(
sprites
::
Sprite
::
NetworkSwitchConnected
);
cmd
.remove_component
::
<
components
::
NetworkSwitch
>
(
entity
);
...
...
@@ -120,6 +133,7 @@ pub fn reconnect_switches(
angel_state
.update_stats
();
}
}
Ok
(())
}
#[legion::system]
...
...
@@ -130,15 +144,16 @@ pub fn update_network_switch_shift(
#[resource]
player
:
&
mut
resources
::
Player
,
#[resource]
angel_state
:
&
mut
NetworkSwitchAngelState
,
#[resource]
game_manager
:
&
mut
resources
::
GameManager
,
)
{
)
->
anyhow
::
Result
<
()
>
{
use
legion
::
IntoQuery
;
if
angel_state
.reconnected_switches
>=
angel_state
.switches_in_map
{
let
player
=
<&
mut
components
::
Player
>
::
query
()
.get_mut
(
world
,
player
.0
)
.
unwrap
()
;
.
context
(
"Player not found"
)
?
;
player
.collected_hours
+=
*
hours_to_award
as
u32
;
*
hours_to_award
=
0
;
game_manager
.request_return_to_heaven
();
}
Ok
(())
}
src/cheats.rs
View file @
1aa9b988
...
...
@@ -59,7 +59,7 @@ pub fn cheat_set_sanity(val: f32) -> Result<(), wasm_bindgen::JsValue> {
match
||
->
anyhow
::
Result
<
()
>
{
// this is nice
let
state
=
get_cheat_state
()
?
;
state
.do_cheat
(
CheatCommand
::
SetSanity
(
val
));
state
.do_cheat
(
CheatCommand
::
SetSanity
(
val
))
?
;
Ok
(())
}()
{
// this is not nice
...
...
@@ -72,7 +72,7 @@ pub fn cheat_set_sanity(val: f32) -> Result<(), wasm_bindgen::JsValue> {
pub
fn
cheat_set_shifts
(
val
:
u32
)
->
Result
<
(),
wasm_bindgen
::
JsValue
>
{
match
||
->
anyhow
::
Result
<
()
>
{
let
state
=
get_cheat_state
()
?
;
state
.do_cheat
(
CheatCommand
::
SetShifts
(
val
));
state
.do_cheat
(
CheatCommand
::
SetShifts
(
val
))
?
;
Ok
(())
}()
{
// this is not nice
...
...
@@ -84,7 +84,7 @@ pub fn cheat_set_shifts(val: u32) -> Result<(), wasm_bindgen::JsValue> {
pub
fn
cheat_get_player
()
->
Result
<
(),
wasm_bindgen
::
JsValue
>
{
match
||
->
anyhow
::
Result
<
()
>
{
let
state
=
get_cheat_state
()
?
;
state
.do_cheat
(
CheatCommand
::
GetPlayer
());
state
.do_cheat
(
CheatCommand
::
GetPlayer
())
?
;
Ok
(())
}()
{
// this is not nice
...
...
src/components/edge.rs
View file @
1aa9b988
...
...
@@ -20,12 +20,12 @@ impl Edge {
pub
fn
draw_edges
(
world
:
&
legion
::
world
::
SubWorld
,
#[resource]
rendering
:
&
mut
resources
::
Rendering
,
)
{
)
->
anyhow
::
Result
<
()
>
{
// TODO: Replace by proper API
for
edge
in
<&
Edge
>
::
query
()
.iter
(
world
)
{
let
mut
positions
=
<&
components
::
Position
>
::
query
();
let
pos1
=
positions
.get
(
world
,
edge
.node1
)
.unwrap
()
;
let
pos2
=
positions
.get
(
world
,
edge
.node2
)
.unwrap
()
;
let
pos1
=
positions
.get
(
world
,
edge
.node1
)
?
;
let
pos2
=
positions
.get
(
world
,
edge
.node2
)
?
;
rendering
.begin_path
();
rendering
.set_line_width
(
7.0
);
...
...
@@ -34,4 +34,6 @@ pub fn draw_edges(
rendering
.line_to
(
pos2
.0
.x
as
f64
,
pos2
.0
.y
as
f64
);
rendering
.stroke
();
}
Ok
(())
}
src/error.rs
0 → 100644
View file @
1aa9b988
use
anyhow
::
Result
;
use
wasm_bindgen
::
JsValue
;
use
web_sys
;
pub
trait
AnyhowWebExt
<
T
>
{
fn
to_anyhow
(
self
)
->
anyhow
::
Result
<
T
>
;
}
impl
<
T
>
AnyhowWebExt
<
T
>
for
Result
<
T
,
JsValue
>
{
fn
to_anyhow
(
self
)
->
anyhow
::
Result
<
T
>
{
self
.map_err
(|
js_value
|
{
let
error_message
=
match
js_value
.as_string
()
{
Some
(
string
)
=>
string
,
None
=>
"Unknown error"
.to_string
(),
};
anyhow
::
anyhow!
(
"{}"
,
error_message
)
})
}
}
impl
<
T
>
AnyhowWebExt
<
T
>
for
Result
<
T
,
web_sys
::
Element
>
{
fn
to_anyhow
(
self
)
->
anyhow
::
Result
<
T
>
{
self
.map_err
(|
js_value
|
{
let
error_message
=
match
js_value
.as_string
()
{
Some
(
string
)
=>
string
,
None
=>
"Unknown error"
.to_string
(),
};
anyhow
::
anyhow!
(
"{}"
,
error_message
)
})
}
}
src/gamestate.rs
View file @
1aa9b988
...
...
@@ -4,6 +4,10 @@ use std::rc::Rc;
use
crate
::
utils
;
use
wasm_bindgen
::
closure
;
use
crate
::
error
::
AnyhowWebExt
;
use
anyhow
::
Context
;
pub
enum
Transition
{
/// Schedule a call of [`State::update`] with `requestAnimationFrame`.
Loop
,
...
...
@@ -47,15 +51,17 @@ impl Transition {
}
pub
trait
State
{
fn
init
(
&
mut
self
,
init
:
StateInitializer
)
->
Transition
;
fn
deinit
(
&
mut
self
)
{}
fn
init
(
&
mut
self
,
init
:
StateInitializer
)
->
anyhow
::
Result
<
Transition
>
;
fn
deinit
(
&
mut
self
)
->
anyhow
::
Result
<
()
>
{
Ok
(())
}
fn
update
(
&
mut
self
,
_timestamp
:
f64
)
->
Transition
{
Transition
::
Keep
fn
update
(
&
mut
self
,
_timestamp
:
f64
)
->
anyhow
::
Result
<
Transition
>
{
Ok
(
Transition
::
Keep
)
}
#[allow(unused_variables)]
fn
event
(
&
mut
self
,
event
:
Event
)
->
Transition
{
Transition
::
Keep
fn
event
(
&
mut
self
,
event
:
Event
)
->
anyhow
::
Result
<
Transition
>
{
Ok
(
Transition
::
Keep
)
}
}
...
...
@@ -111,7 +117,10 @@ impl EventHandlers {
self
.mouse_handlers
.insert
(
id
.to_owned
(),
f
);
}
pub
fn
register_keyevents
<
F
:
FnMut
(
bool
,
&
web_sys
::
KeyboardEvent
)
+
'static
>
(
&
mut
self
,
f
:
F
)
{
pub
fn
register_keyevents
<
F
:
FnMut
(
bool
,
&
web_sys
::
KeyboardEvent
)
+
'static
>
(
&
mut
self
,
f
:
F
,
)
->
anyhow
::
Result
<
()
>
{
use
wasm_bindgen
::
JsCast
;
let
f
=
Rc
::
new
(
RefCell
::
new
(
f
));
...
...
@@ -136,16 +145,21 @@ impl EventHandlers {
f2
.borrow_mut
()(
false
,
event
)
})
as
Box
<
dyn
FnMut
(
wasm_bindgen
::
JsValue
)
>
);
let
body
=
utils
::
document
()
.body
()
.unwrap
();
let
body
=
utils
::
document
()
.body
()
.context
(
"document.body is undefined"
)
?
;
body
.set_onkeydown
(
Some
(
fdown
.as_ref
()
.unchecked_ref
()));
body
.set_onkeyup
(
Some
(
fup
.as_ref
()
.unchecked_ref
()));
self
.key_handlers
=
Some
((
fdown
,
fup
));
Ok
(())
}
pub
fn
deregister_all
(
&
mut
self
)
{
pub
fn
deregister_all
(
&
mut
self
)
->
anyhow
::
Result
<
()
>
{
if
self
.key_handlers
.is_some
()
{
let
body
=
utils
::
document
()
.body
()
.unwrap
();
let
body
=
utils
::
document
()
.body
()
.context
(
"document.body is undefined"
)
?
;
body
.set_onkeydown
(
None
);
body
.set_onkeyup
(
None
);
}
...
...
@@ -156,9 +170,10 @@ impl EventHandlers {
}
else
if
let
Ok
(
el
)
=
utils
::
get_element_by_id
::
<
web_sys
::
HtmlElement
>
(
id
)
{
el
.set_onclick
(
None
);
}
else
{
panic
!
(
"Cannot find appropriate element {:?}"
,
id
);
return
Err
(
anyhow
::
anyhow
!
(
"Cannot find appropriate element {:?}"
,
id
)
)
;
}
}
Ok
(())
}
}
...
...
@@ -170,16 +185,16 @@ impl StateMachineHandle {
StateMachineHandle
(
state_machine
.clone
())
}
pub
fn
do_transition
(
&
self
,
t
:
Transition
)
{
pub
fn
do_transition
(
&
self
,
t
:
Transition
)
->
anyhow
::
Result
<
()
>
{
StateMachine
::
do_transition
(
&
self
.0
,
t
)
}
pub
fn
do_event
(
&
self
,
event
:
Event
)
{
let
t
=
StateMachine
::
active
(
&
self
.0
)
.event
(
event
);
pub
fn
do_event
(
&
self
,
event
:
Event
)
->
anyhow
::
Result
<
()
>
{
let
t
=
StateMachine
::
active
(
&
self
.0
)
.event
(
event
)
?
;
self
.do_transition
(
t
)
}
pub
fn
do_cheat
(
&
self
,
cheat
:
crate
::
cheats
::
CheatCommand
)
{
pub
fn
do_cheat
(
&
self
,
cheat
:
crate
::
cheats
::
CheatCommand
)
->
anyhow
::
Result
<
()
>
{
self
.do_event
(
Event
::
Cheat
(
cheat
))
}
...
...
@@ -204,19 +219,22 @@ impl<'a> StateInitializer<'a> {
}
}
pub
fn
register_onclick
(
&
mut
self
,
id
:
&
str
)
{
pub
fn
register_onclick
(
&
mut
self
,
id
:
&
str
)
->
anyhow
::
Result
<
()
>
{
let
handle
=
self
.handle
.clone
();
let
id2
=
id
.to_owned
();
let
canvas
=
utils
::
get_element_by_id
::
<
web_sys
::
HtmlCanvasElement
>
(
"game-canvas"
)
.unwrap
()
;
let
canvas
=
utils
::
get_element_by_id
::
<
web_sys
::
HtmlCanvasElement
>
(
"game-canvas"
)
?
;
self
.event_handlers
.register_onclick
(
id
,
move
|
event
|
{
let
click
=
nalgebra
::
Point2
::
new
(
event
.client_x
()
as
f64
,
event
.client_y
()
as
f64
);
let
canvas_click
=
utils
::
screen_to_contain_canvas
(
&
canvas
,
click
);
let
canvas_click
=
nalgebra
::
Point2
::
new
(
canvas_click
.x
as
f32
,
canvas_click
.y
as
f32
);
handle
.do_event
(
Event
::
MouseClick
{
target
:
&
id2
,
coords
:
canvas_click
,
});
handle
.do_event
(
Event
::
MouseClick
{
target
:
&
id2
,
coords
:
canvas_click
,
})
.unwrap
();
// ignore-unwrap - unwrap inside a closure.
});
Ok
(())
}
pub
fn
register_keyevents
(
&
mut
self
)
{
...
...
@@ -224,11 +242,12 @@ impl<'a> StateInitializer<'a> {
self
.event_handlers
.register_keyevents
(
move
|
keydown
,
event
|
{
if
keydown
{
handle
.do_event
(
Event
::
KeyDown
(
&
event
.key
()))
;
handle
.do_event
(
Event
::
KeyDown
(
&
event
.key
()))
.unwrap
();
// ignore-unwrap - unwrap inside a closure
}
else
{
handle
.do_event
(
Event
::
KeyUp
(
&
event
.key
()))
;
handle
.do_event
(
Event
::
KeyUp
(
&
event
.key
()))
.unwrap
();
// ignore-unwrap - unwrap inside a closure
}
});
})
.unwrap
();
}
pub
fn
get_handle
(
&
self
)
->
StateMachineHandle
{
...
...
@@ -258,21 +277,22 @@ impl StateStorage {
// ----------
pub
fn
init
(
&
mut
self
,
sm
:
&
Rc
<
RefCell
<
StateMachine
>>
)
->
Transition
{
pub
fn
init
(
&
mut
self
,
sm
:
&
Rc
<
RefCell
<
StateMachine
>>
)
->
anyhow
::
Result
<
Transition
>
{
self
.state
.init
(
StateInitializer
::
new
(
sm
,
&
mut
self
.event_handlers
))
}
pub
fn
deinit
(
&
mut
self
)
{
self
.state
.deinit
();
self
.event_handlers
.deregister_all
();
pub
fn
deinit
(
&
mut
self
)
->
anyhow
::
Result
<
()
>
{
self
.state
.deinit
()
?
;
self
.event_handlers
.deregister_all
()
?
;
Ok
(())
}
pub
fn
update
(
&
mut
self
,
timestamp
:
f64
)
->
Transition
{
pub
fn
update
(
&
mut
self
,
timestamp
:
f64
)
->
anyhow
::
Result
<
Transition
>
{
self
.state
.update
(
timestamp
)
}
fn
event
(
&
mut
self
,
event
:
Event
)
->
Transition
{
fn
event
(
&
mut
self
,
event
:
Event
)
->
anyhow
::
Result
<
Transition
>
{
self
.state
.event
(
event
)
}
}
...
...
@@ -284,7 +304,7 @@ pub struct StateMachine {
}
impl
StateMachine
{
pub
fn
launch
<
S
:
State
+
'static
>
(
initial
:
S
)
{
pub
fn
launch
<
S
:
State
+
'static
>
(
initial
:
S
)
->
anyhow
::
Result
<
()
>
{
let
this
=
Rc
::
new
(
RefCell
::
new
(
StateMachine
{
states
:
vec!
[
StateStorage
::
new
(
initial
)],
loop_handler
:
None
,
...
...
@@ -315,28 +335,31 @@ impl StateMachine {
return
;
}
active
.update
(
timestamp
)
active
.update
(
timestamp
)
.unwrap
()
// ignore-unwrap - unwrap inside a closure
};
StateMachine
::
do_transition
(
&
this
,
t
);
StateMachine
::
do_transition
(
&
this
,
t
)
.unwrap
()
;
})
as
Box
<
dyn
FnMut
(
f64
)
>
)
};
this
.borrow_mut
()
.loop_handler
=
Some
(
loop_handler
);
let
t
=
StateMachine
::
active
(
&
this
)
.init
(
&
this
);
StateMachine
::
do_transition
(
&
this
,
t
);