11#![ allow( clippy:: boxed_local) ]
22
3- use std:: time:: Duration ;
3+ use std:: { collections :: HashMap , time:: Duration } ;
44
55use embedded_graphics:: pixelcolor:: Rgb888 ;
66use embedded_graphics_web_simulator:: {
77 display:: WebSimulatorDisplay , output_settings:: OutputSettings ,
88} ;
9+ use js_sys:: JsString ;
910use mindy:: {
1011 parser:: LogicParser ,
1112 types:: { PackedPoint2 , ProcessorConfig , ProcessorLinkConfig , content} ,
1213 vm:: {
1314 Building , BuildingData , EmbeddedDisplayData , InstructionResult , LVar , LogicVM ,
14- LogicVMBuilder ,
1515 buildings:: { HYPER_PROCESSOR , LOGIC_PROCESSOR , MICRO_PROCESSOR , WORLD_PROCESSOR } ,
1616 variables:: Constants ,
1717 } ,
@@ -36,6 +36,18 @@ pub fn init() {
3636 console_error_panic_hook:: set_once ( ) ;
3737}
3838
39+ #[ wasm_bindgen]
40+ pub fn pack_point ( x : i16 , y : i16 ) -> u32 {
41+ ( ( y as u32 ) << 16 ) | ( x as u32 )
42+ }
43+
44+ fn unpack_point ( position : u32 ) -> PackedPoint2 {
45+ PackedPoint2 {
46+ x : position as i16 ,
47+ y : ( position >> 16 ) as i16 ,
48+ }
49+ }
50+
3951#[ wasm_bindgen]
4052pub struct WebLogicVM {
4153 vm : LogicVM ,
@@ -44,48 +56,90 @@ pub struct WebLogicVM {
4456 prev_timestamp : Option < f64 > ,
4557}
4658
59+ #[ wasm_bindgen]
4760impl WebLogicVM {
48- fn new ( vm : LogicVM , globals : Constants ) -> Self {
61+ #[ wasm_bindgen( constructor) ]
62+ pub fn new ( ) -> Self {
4963 Self {
50- vm,
51- globals,
64+ vm : LogicVM :: new ( ) ,
65+ globals : LVar :: create_global_constants ( ) ,
5266 logic_parser : LogicParser :: new ( ) ,
5367 prev_timestamp : None ,
5468 }
5569 }
56- }
5770
58- #[ wasm_bindgen]
59- impl WebLogicVM {
60- pub fn do_tick ( & mut self , timestamp : f64 ) {
61- // convert to seconds
62- let timestamp = timestamp / 1000. ;
63-
64- // nominal 60 ticks per second
65- let delta = match self . prev_timestamp {
66- Some ( prev_timestamp) => ( timestamp - prev_timestamp) * 60. ,
67- None => 1. ,
68- }
69- . min ( MAX_DELTA ) ;
71+ #[ wasm_bindgen( getter) ]
72+ pub fn time ( & self ) -> f64 {
73+ self . vm . time ( ) . as_secs_f64 ( )
74+ }
7075
71- self . prev_timestamp = Some ( timestamp) ;
76+ pub fn add_processor (
77+ & mut self ,
78+ position : u32 ,
79+ kind : ProcessorKind ,
80+ code : String ,
81+ ) -> Result < ( ) , String > {
82+ let position = unpack_point ( position) ;
7283 self . vm
73- . do_tick_with_delta ( Duration :: from_secs_f64 ( timestamp) , delta) ;
84+ . add_building (
85+ Building :: from_processor_config (
86+ kind. name ( ) ,
87+ position,
88+ & ProcessorConfig {
89+ code,
90+ links : vec ! [ ] ,
91+ } ,
92+ & self . vm ,
93+ )
94+ . map_err ( |e| e. to_string ( ) ) ?,
95+ & self . globals ,
96+ )
97+ . map_err ( |e| e. to_string ( ) )
7498 }
7599
76- #[ wasm_bindgen( getter) ]
77- pub fn time ( & self ) -> f64 {
78- self . vm . time ( ) . as_secs_f64 ( )
100+ pub fn add_display (
101+ & mut self ,
102+ position : u32 ,
103+ width : u32 ,
104+ height : u32 ,
105+ parent : & Element ,
106+ ) -> Result < ( ) , String > {
107+ let display = WebSimulatorDisplay :: < Rgb888 > :: new (
108+ ( width, height) ,
109+ & OutputSettings :: default ( ) ,
110+ Some ( parent) ,
111+ ) ;
112+
113+ let display_data = EmbeddedDisplayData :: new (
114+ display,
115+ Some ( Box :: new ( |display| {
116+ display. flush ( ) . expect ( "failed to flush display" ) ;
117+ InstructionResult :: Ok
118+ } ) ) ,
119+ )
120+ . expect ( "failed to initialize display" ) ;
121+
122+ self . vm
123+ . add_building (
124+ Building :: new (
125+ content:: blocks:: FROM_NAME [ "tile-logic-display" ] ,
126+ unpack_point ( position) ,
127+ display_data. into ( ) ,
128+ ) ,
129+ & self . globals ,
130+ )
131+ . map_err ( |e| e. to_string ( ) )
79132 }
80133
81134 pub fn set_processor_config (
82135 & mut self ,
83- position : PackedPoint2 ,
136+ position : u32 ,
84137 code : & str ,
85- links : Option < Box < [ PackedPoint2 ] > > ,
86- ) -> Result < ( ) , String > {
138+ links : Box < [ u32 ] > ,
139+ ) -> Result < LinkNames , String > {
87140 let ast = self . logic_parser . parse ( code) . map_err ( |e| e. to_string ( ) ) ?;
88141
142+ let position = unpack_point ( position) ;
89143 let building = self
90144 . vm
91145 . building ( position)
@@ -101,88 +155,60 @@ impl WebLogicVM {
101155 processor
102156 . update_config (
103157 ast,
104- links
105- . map ( |v| {
106- v . iter ( )
107- . map ( |p| {
108- ProcessorLinkConfig :: unnamed ( p . x - position . x , p . y - position . y )
109- } )
110- . collect :: < Vec < _ > > ( )
111- } )
112- . as_deref ( ) ,
158+ Some (
159+ & links
160+ . iter ( )
161+ . map ( |p| {
162+ let p = unpack_point ( * p ) ;
163+ ProcessorLinkConfig :: unnamed ( p . x - position . x , p . y - position . y )
164+ } )
165+ . collect :: < Vec < _ > > ( ) ,
166+ ) ,
113167 & self . vm ,
114168 building,
115169 & self . globals ,
116170 )
117- . map_err ( |e| e. to_string ( ) )
171+ . map_err ( |e| e. to_string ( ) ) ?;
172+
173+ Ok ( LinkNames (
174+ processor
175+ . state
176+ . links ( )
177+ . iter ( )
178+ . map ( |l| {
179+ (
180+ pack_point ( l. building . position . x , l. building . position . y ) ,
181+ l. name . clone ( ) ,
182+ )
183+ } )
184+ . collect ( ) ,
185+ ) )
118186 }
119- }
120187
121- #[ wasm_bindgen]
122- pub struct WebLogicVMBuilder {
123- builder : LogicVMBuilder ,
124- }
125-
126- #[ wasm_bindgen]
127- impl WebLogicVMBuilder {
128- #[ wasm_bindgen( constructor) ]
129- pub fn new ( ) -> Self {
130- Self {
131- builder : LogicVMBuilder :: new ( ) ,
132- }
133- }
134-
135- pub fn add_processor ( & mut self , position : PackedPoint2 , kind : ProcessorKind ) {
136- self . builder . add_building (
137- Building :: from_processor_config (
138- kind. name ( ) ,
139- position,
140- & ProcessorConfig :: default ( ) ,
141- & self . builder ,
142- )
143- . expect ( "failed to create processor" ) ,
144- ) ;
188+ pub fn building_name ( & self , position : u32 ) -> Option < JsString > {
189+ self . vm
190+ . building ( unpack_point ( position) )
191+ . map ( |b| JsString :: from_char_code ( b. block . name . as_u16str ( ) . as_slice ( ) ) )
145192 }
146193
147- pub fn add_display (
148- & mut self ,
149- position : PackedPoint2 ,
150- width : u32 ,
151- height : u32 ,
152- parent : & Element ,
153- ) {
154- let display = WebSimulatorDisplay :: < Rgb888 > :: new (
155- ( width, height) ,
156- & OutputSettings :: default ( ) ,
157- Some ( parent) ,
158- ) ;
159-
160- let display_data = EmbeddedDisplayData :: new (
161- display,
162- Some ( Box :: new ( |display| {
163- display. flush ( ) . expect ( "failed to flush display" ) ;
164- InstructionResult :: Yield
165- } ) ) ,
166- )
167- . expect ( "failed to initialize display" ) ;
168-
169- self . builder . add_building ( Building :: new (
170- content:: blocks:: FROM_NAME [ "tile-logic-display" ] ,
171- position,
172- display_data. into ( ) ,
173- ) ) ;
174- }
194+ pub fn do_tick ( & mut self , timestamp : f64 ) {
195+ // convert to seconds
196+ let timestamp = timestamp / 1000. ;
175197
176- pub fn build ( self ) -> Result < WebLogicVM , String > {
177- let globals = LVar :: create_global_constants ( ) ;
178- match self . builder . build_with_globals ( & globals) {
179- Ok ( vm) => Ok ( WebLogicVM :: new ( vm, globals) ) ,
180- Err ( e) => Err ( e. to_string ( ) ) ,
198+ // nominal 60 ticks per second
199+ let delta = match self . prev_timestamp {
200+ Some ( prev_timestamp) => ( timestamp - prev_timestamp) * 60. ,
201+ None => 1. ,
181202 }
203+ . min ( MAX_DELTA ) ;
204+
205+ self . prev_timestamp = Some ( timestamp) ;
206+ self . vm
207+ . do_tick_with_delta ( Duration :: from_secs_f64 ( timestamp) , delta) ;
182208 }
183209}
184210
185- impl Default for WebLogicVMBuilder {
211+ impl Default for WebLogicVM {
186212 fn default ( ) -> Self {
187213 Self :: new ( )
188214 }
@@ -206,3 +232,14 @@ impl ProcessorKind {
206232 }
207233 }
208234}
235+
236+ #[ wasm_bindgen]
237+ pub struct LinkNames ( HashMap < u32 , String > ) ;
238+
239+ #[ wasm_bindgen]
240+ impl LinkNames {
241+ #[ wasm_bindgen( indexing_getter) ]
242+ pub fn get ( & self , position : u32 ) -> Option < String > {
243+ self . 0 . get ( & position) . cloned ( )
244+ }
245+ }
0 commit comments