1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
pub use lotus_bindgen_macros::lotus_bindgen;

use message::Message;
use serde::{de::DeserializeOwned, Serialize};

pub mod action;
pub mod event;
pub(crate) mod ffi;
pub mod gizmos;
pub mod log;
pub mod macros;
pub mod message;
pub mod public_vars;
pub mod rand;
#[doc(hidden)]
pub mod settings;
pub mod var;
pub mod prelude {
    pub use crate::log;
    pub use crate::message::{Message, MessageType};
}

pub mod input {
    pub use lotus_shared::input::*;
}

pub trait Script {
    fn init(&mut self) {}
    fn actions() -> Vec<action::RegisterAction> {
        Default::default()
    }

    fn tick(&mut self) {}

    #[allow(unused_variables)]
    fn on_message(&mut self, msg: Message) {}
}

/// Get the current delta time in seconds.
pub fn delta() -> f32 {
    unsafe { ffi::time::delta_f64() as f32 }
}

/// Get the current delta time in seconds.
pub fn delta_f64() -> f64 {
    unsafe { ffi::time::delta_f64() }
}

/// Returns true if the object the script is attached to is remote controlled.
pub fn is_rc() -> bool {
    unsafe { ffi::is_rc() }
}

#[doc(hidden)]
pub struct FfiObject {
    data: Box<[u8]>,
}

impl FfiObject {
    pub fn new<T: Serialize>(value: &T) -> Self {
        let data = rmp_serde::to_vec_named(value)
            .expect("Failed to serialize value")
            .into_boxed_slice();

        Self { data }
    }

    pub fn deserialize<T: DeserializeOwned>(&self) -> T {
        rmp_serde::from_slice(&self.data).expect("Failed to deserialize value")
    }

    pub fn packed(&self) -> u64 {
        let ptr = self.data.as_ptr() as u32;
        let len = self.data.len() as u32;

        let mut packed = [0u8; 8];
        packed[..4].copy_from_slice(&ptr.to_be_bytes());
        packed[4..].copy_from_slice(&len.to_be_bytes());

        u64::from_be_bytes(packed)
    }

    pub fn packed_forget(self) -> u64 {
        let packed = self.packed();
        std::mem::forget(self);
        packed
    }

    pub fn from_packed(packed: u64) -> Self {
        let packed = packed.to_be_bytes();
        let ptr = u32::from_be_bytes(packed[..4].try_into().unwrap());
        let len = u32::from_be_bytes(packed[4..].try_into().unwrap());

        let data = unsafe { std::slice::from_raw_parts(ptr as *const u8, len as usize) };
        Self { data: data.into() }
    }
}