1use netsblox_vm::real_time::*;
2use netsblox_vm::std_system::*;
3use netsblox_vm::std_util::*;
4use netsblox_vm::bytecode::*;
5use netsblox_vm::process::*;
6use netsblox_vm::runtime::*;
7use netsblox_vm::project::*;
8use netsblox_vm::gc::*;
9use netsblox_vm::ast;
10use netsblox_vm::compact_str::CompactString;
11
12use std::io::Read;
13use std::time::Duration;
14use std::sync::Arc;
15use std::rc::Rc;
16
17const BASE_URL: &'static str = "https://cloud.netsblox.org";
20
21const CLOCK_INTERVAL: Duration = Duration::from_millis(10);
22const COLLECT_INTERVAL: Duration = Duration::from_secs(60);
23
24const YIELDS_BEFORE_SLEEP: usize = 64;
25const IDLE_SLEEP_TIME: Duration = Duration::from_millis(1);
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30enum NativeType {} #[derive(Debug)]
33enum NativeValue {} impl GetType for NativeValue {
35 type Output = NativeType;
36 fn get_type(&self) -> Self::Output {
37 unreachable!() }
39}
40
41struct EntityState; impl From<EntityKind<'_, '_, C, StdSystem<C>>> for EntityState {
43 fn from(_: EntityKind<'_, '_, C, StdSystem<C>>) -> Self {
44 EntityState
45 }
46}
47
48struct ProcessState; impl From<ProcessKind<'_, '_, C, StdSystem<C>>> for ProcessState {
50 fn from(_: ProcessKind<'_, '_, C, StdSystem<C>>) -> Self {
51 ProcessState
52 }
53}
54impl Unwindable for ProcessState {
55 type UnwindPoint = (); fn get_unwind_point(&self) -> Self::UnwindPoint { }
57 fn unwind_to(&mut self, _: &Self::UnwindPoint) { }
58}
59
60struct C; impl CustomTypes<StdSystem<C>> for C {
62 type NativeValue = NativeValue; type Intermediate = SimpleValue; type EntityState = EntityState; type ProcessState = ProcessState; fn from_intermediate<'gc>(mc: &Mutation<'gc>, value: Self::Intermediate) -> Value<'gc, C, StdSystem<C>> {
70 Value::from_simple(mc, value)
71 }
72}
73
74#[derive(Collect)]
76#[collect(no_drop)]
77struct Env<'gc> {
78 proj: Gc<'gc, RefLock<Project<'gc, C, StdSystem<C>>>>,
79 #[collect(require_static)] locs: Locations, }
81type EnvArena = Arena<Rootable![Env<'_>]>;
82
83fn get_running_project(xml: &str, system: Rc<StdSystem<C>>) -> EnvArena {
85 EnvArena::new(|mc| {
86 let parser = ast::Parser::default();
87 let ast = parser.parse(xml).unwrap();
88 assert_eq!(ast.roles.len(), 1); let (bytecode, init_info, locs, _) = ByteCode::compile(&ast.roles[0]).unwrap();
91
92 let mut proj = Project::from_init(mc, &init_info, Rc::new(bytecode), Settings::default(), system);
93 proj.input(mc, Input::Start); Env { proj: Gc::new(mc, RefLock::new(proj)), locs }
96 })
97}
98
99fn main() {
100 let args = std::env::args().collect::<Vec<_>>();
102 if args.len() != 2 {
103 panic!("usage: {} [xml file]", &args[0]);
104 }
105 let mut xml = String::new();
106 std::fs::File::open(&args[1]).expect("failed to open file").read_to_string(&mut xml).expect("failed to read file");
107
108 let clock = Arc::new(Clock::new(UtcOffset::UTC, Some(Precision::Medium)));
110 let clock_clone = clock.clone();
111 std::thread::spawn(move || loop {
112 std::thread::sleep(CLOCK_INTERVAL);
113 clock_clone.update();
114 });
115
116 let config = Config::<C, StdSystem<C>> {
118 request: None,
119 command: Some(Rc::new(|_mc, key, command, _proc| match command {
120 Command::Print { style: _, value } => {
121 if let Some(value) = value {
122 println!("{value:?}");
123 }
124 key.complete(Ok(())); CommandStatus::Handled
126 }
127 _ => CommandStatus::UseDefault { key, command }, })),
129 };
130
131 let system = Rc::new(StdSystem::new_sync(CompactString::new(BASE_URL), None, config, clock.clone()));
133 let mut env = get_running_project(&xml, system);
134
135 let mut idle_sleeper = IdleAction::new(YIELDS_BEFORE_SLEEP, Box::new(|| std::thread::sleep(IDLE_SLEEP_TIME)));
137 let mut next_collect = clock.read(Precision::Medium) + COLLECT_INTERVAL;
138 loop {
139 env.mutate(|mc, env| {
140 let mut proj = env.proj.borrow_mut(mc);
141 for _ in 0..1024 {
142 let res = proj.step(mc);
144 if let ProjectStep::Error { error, proc } = &res {
145 let trace = ErrorSummary::extract(error, proc, &env.locs);
147 println!("error: {error:?}\ntrace: {trace:?}");
148 }
149 idle_sleeper.consume(&res);
151 }
152 });
153 if clock.read(Precision::Low) >= next_collect {
155 env.collect_all();
156 next_collect = clock.read(Precision::Medium) + COLLECT_INTERVAL;
157 }
158 }
159}