tirbofish/dropbear · diff
still broken, soon to be fixed :(
note: fuck its a mess
Signature present but could not be verified.
Unverified
@@ -6,7 +6,7 @@ package.repository = "https://github.com/4tkbytes/dropbear-engine" package.readme = "README.md" resolver = "3" -members = ["dropbear-engine", "eucalyptus", "gleek", "redback-runtime"] +members = ["dropbear-engine", "eucalyptus", "redback-runtime"] [workspace.dependencies] anyhow = { version = "1.0", features = ["backtrace"] } @@ -43,11 +43,13 @@ rfd = "0.15.4" rhai = "1.22" ron = "0.10.1" russimp-ng = { version = "3.2.4", features = ["static-link"] } +rustyscript = { version = "0.12" } serde = { version = "1.0.219", features = ["derive"] } spin_sleep = "1.3" +specta = { version = "=2.0.0-rc.22", features = ["glam", "derive", "export"] } +specta-typescript = "0.0.9" tokio = { version = "1", features = ["full"] } transform-gizmo-egui = { git = "https://github.com/4tkbytes/transform-gizmo"} -ts-rs = "10.1" wgpu = "26" winit = { version = "0.30", features = [] } zip = "4.3" @@ -34,7 +34,7 @@ hecs.workspace = true once_cell.workspace = true parking_lot.workspace = true lazy_static.workspace = true -ts-rs.workspace = true +specta.workspace = true [target.'cfg(not(target_os = "android"))'.dependencies] rfd.workspace = true @@ -42,7 +42,10 @@ clap = { workspace = true, optional = true } walkdir = { workspace = true, optional = true } zip = { workspace = true, optional = true } bytemuck = "1.23.2" -ts-rs.workspace = true + +rustyscript.workspace = true +specta.workspace = true +specta-typescript.workspace = true [target.'cfg(not(target_os = "android"))'.dependencies] rfd = { workspace = true, optional = true } @@ -108,4 +111,4 @@ data-only = [ anyhow = "1.0" app_dirs2 = "2.5" reqwest = { version = "0.12", features = ["blocking"] } -zip = "4.3" +zip = "4.3" @@ -2,6 +2,7 @@ use std::fs::{self, File}; use std::io::Cursor; fn main() -> anyhow::Result<()> { + // todo: move this into the "setup" process let repo_zip_url = "https://github.com/4tkbytes/dropbear/archive/refs/heads/main.zip"; let response = reqwest::blocking::get(repo_zip_url) .map_err(|e| anyhow::anyhow!("Failed to download repo zip: {}", e))? @@ -1,61 +1,8 @@ -use rhai::*; -use rhai::plugin::*; +use rustyscript::{Module, Runtime}; -#[rhai::export_module] -pub mod math_functions { - // Basic math - pub fn abs(x: f64) -> f64 { x.abs() } - pub fn sqrt(x: f64) -> f64 { x.sqrt() } - pub fn pow(x: f64, y: f64) -> f64 { x.powf(y) } - pub fn min(x: f64, y: f64) -> f64 { x.min(y) } - pub fn max(x: f64, y: f64) -> f64 { x.max(y) } - pub fn clamp(x: f64, min: f64, max: f64) -> f64 { x.clamp(min, max) } - - // Trig functions - pub fn sin(x: f64) -> f64 { x.sin() } - pub fn cos(x: f64) -> f64 { x.cos() } - pub fn tan(x: f64) -> f64 { x.tan() } - pub fn asin(x: f64) -> f64 { x.asin() } - pub fn acos(x: f64) -> f64 { x.acos() } - pub fn atan(x: f64) -> f64 { x.atan() } - pub fn atan2(y: f64, x: f64) -> f64 { y.atan2(x) } - - // Hyperbolic functions - pub fn sinh(x: f64) -> f64 { x.sinh() } - pub fn cosh(x: f64) -> f64 { x.cosh() } - pub fn tanh(x: f64) -> f64 { x.tanh() } - - // Logarithmic and exponential - pub fn exp(x: f64) -> f64 { x.exp() } - pub fn ln(x: f64) -> f64 { x.ln() } - pub fn log10(x: f64) -> f64 { x.log10() } - pub fn log2(x: f64) -> f64 { x.log2() } - - // Rounding functions - pub fn floor(x: f64) -> f64 { x.floor() } - pub fn ceil(x: f64) -> f64 { x.ceil() } - pub fn round(x: f64) -> f64 { x.round() } - pub fn trunc(x: f64) -> f64 { x.trunc() } - pub fn fract(x: f64) -> f64 { x.fract() } - - // Conversion - pub fn to_radians(degrees: f64) -> f64 { degrees.to_radians() } - pub fn to_degrees(radians: f64) -> f64 { radians.to_degrees() } - - // Utility functions - pub fn lerp(a: f64, b: f64, t: f64) -> f64 { a + (b - a) * t } - pub fn smoothstep(edge0: f64, edge1: f64, x: f64) -> f64 { - let t = ((x - edge0) / (edge1 - edge0)).clamp(0.0, 1.0); - t * t * (3.0 - 2.0 * t) - } - - // Consts - pub const PI: f64 = std::f64::consts::PI; - pub const E: f64 = std::f64::consts::E; - pub const TAU: f64 = std::f64::consts::TAU; -} - -pub fn register_math_functions(engine: &mut Engine) { - engine.register_static_module("math", exported_module!(math_functions).into()); +pub fn register_math_functions(runtime: &mut Runtime) -> anyhow::Result<()> { + // runtime.load_module_async(module) + let module = Module::load_dir("typescript")?; + runtime.load_modules(module, side_modules) log::info!("[Script] Initialised math module"); } @@ -2,16 +2,19 @@ pub mod entity; pub mod math; pub mod input; +use chrono::DateTime; use dropbear_engine::entity::{AdoptedEntity, Transform}; use glam::{DQuat, DVec3}; use hecs::World; -use rhai::*; +use rustyscript::{Runtime, RuntimeOptions}; +use specta::{Type, TypeCollection}; +use specta_typescript::Typescript; use std::path::PathBuf; use std::{collections::HashMap, fs}; use crate::states::{EntityNode, ModelProperties, ScriptComponent, PROJECT, SOURCE}; -pub const TEMPLATE_SCRIPT: &'static str = include_str!("../template.rhai"); +pub const TEMPLATE_SCRIPT: &'static str = include_str!("../template.ts"); pub enum ScriptAction { AttachScript { @@ -156,79 +159,117 @@ pub fn attach_script_to_entity( Ok(()) } +// #[cfg(feature = "editor")] +// pub fn generate_ts() -> anyhow::Result<()> { +// let mut types = TypeCollection::default(); +// types.register::<Transform>(); + +// let utc: DateTime<Utc> = Utc::now(); +// let header = format!(" +// // @generated by dropbear-engine on {} UTC time +// // Hello there! This is the generated stubs for the Eucalyptus Editor scripting component. +// // This file purely exists for the LSP and for TypeScripts type safety. Running this library +// // most likely won't do anything, but go ahead and be my guest. +// // EDIT THIS LIBRARY AT YOUR OWN WILL. IT IS RECOMMENDED TO NOT TOUCH THIS FILE +// ", utc); + +// if let Ok(project) = PROJECT.read() { +// Typescript::new().header(header).export_to(project.project_path.clone().join("src/dropbear-engine.d.ts"), types)?; +// } else { +// anyhow::bail!("Unable to retain Project Config lock, could not generate typescript bindings"); +// } +// Ok(()) +// } + pub struct ScriptManager { - pub engine: rhai::Engine, + pub runtime: Runtime, compiled_scripts: HashMap<String, AST>, script_scopes: HashMap<hecs::Entity, Scope<'static>>, } impl ScriptManager { - pub fn new() -> Self { - let mut engine = rhai::Engine::new(); - - // REGISTER FUNCTIONS HERE - math::register_math_functions(&mut engine); - input::InputState::register_input_modules(&mut engine); - entity::register_model_props_module(&mut engine); + pub fn new() -> anyhow::Result<Self> { + let mut runtime = Runtime::new(RuntimeOptions::default())?; - engine.register_type_with_name::<Transform>("Transform"); - engine.register_type_with_name::<DQuat>("Quaternion"); - - // transform - engine.register_fn("new_transform", Transform::new); - engine.register_get_set( - "position", - |t: &mut Transform| t.position, - |t: &mut Transform, pos: DVec3| t.position = pos, - ); - engine.register_get_set( - "rotation", - |t: &mut Transform| t.rotation, - |t: &mut Transform, rot: DQuat| t.rotation = rot, - ); - engine.register_get_set( - "scale", - |t: &mut Transform| t.scale, - |t: &mut Transform, scale: DVec3| t.scale = scale, - ); - // vector methods - engine.register_type_with_name::<DVec3>("Vector3"); - engine.register_fn("vec3", |x: f64, y: f64, z: f64| DVec3::new(x, y, z)); - engine.register_get_set("x", |v: &mut DVec3| v.x, |v: &mut DVec3, x: f64| v.x = x); - engine.register_get_set("y", |v: &mut DVec3| v.y, |v: &mut DVec3, y: f64| v.y = y); - engine.register_get_set("z", |v: &mut DVec3| v.z, |v: &mut DVec3, z: f64| v.z = z); - - // utils - engine.register_fn("log", |msg: &str| { - println!("[Script] {}", msg); - }); - engine.register_fn("time", || { - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_secs_f64() - }); - - // operators - engine.register_fn("<", |a: f64, b: f32| a < b as f64); - engine.register_fn("<=", |a: f64, b: f32| a <= b as f64); - engine.register_fn(">", |a: f64, b: f32| a > b as f64); - engine.register_fn(">=", |a: f64, b: f32| a >= b as f64); - engine.register_fn("==", |a: f64, b: f32| a == b as f64); - engine.register_fn("!=", |a: f64, b: f32| a != b as f64); - - engine.register_fn("<", |a: f32, b: f64| (a as f64) < b); - engine.register_fn("<=", |a: f32, b: f64| (a as f64) <= b); - engine.register_fn(">", |a: f32, b: f64| (a as f64) > b); - engine.register_fn(">=", |a: f32, b: f64| (a as f64) >= b); - engine.register_fn("==", |a: f32, b: f64| (a as f64) == b); - engine.register_fn("!=", |a: f32, b: f64| (a as f64) != b); - - // input + // // REGISTER FUNCTIONS HERE + // math::register_math_functions(&mut runtime); + // input::InputState::register_input_modules(&mut runtime); + // entity::register_model_props_module(&mut runtime); + + // // register types used by scripts + // runtime.register_type_with_name::<Transform>("Transform"); + // runtime.register_type_with_name::<DQuat>("Quaternion"); + // runtime.register_type_with_name::<DVec3>("Vector3"); + + // runtime.mod + + // // constructors / helpers (alias names to match helper.ts) + // runtime.register_function("createTransform", Transform::new); + // runtime.register_function("createVec3", |x: f64, y: f64, z: f64| DVec3::new(x, y, z)); + // // keep the original alias if you used "vec3" elsewhere + // runtime.register_function("vec3", |x: f64, y: f64, z: f64| DVec3::new(x, y, z)); + + // runtime.register_function("createQuatIdentity", || DQuat::IDENTITY); + // // from-euler: adapt to your exact DQuat API if different + // runtime.register_function("createQuatFromEuler", |x: f64, y: f64, z: f64| { + // // uses EulerRot::XYZ — adjust if your glam API differs + // DQuat::from_euler(glam::EulerRot::XYZ, x, y, z) + // }); + + // // transform helpers: simple implementations that return an updated Transform + // runtime.register_function( + // "transformTranslate", + // |mut t: Transform, v: DVec3| { + // t.position += v; + // t + // }, + // ); + // runtime.register_function( + // "transformScale", + // |mut t: Transform, s: DVec3| { + // t.scale *= s; + // t + // }, + // ); + // runtime.register_function( + // "transformMatrix", + // |t: Transform| { + // // return whatever representation your scripts expect (e.g. a 4x4 matrix type) + // t.matrix() // replace with actual method if different + // }, + // ); + + // // axis rotations — simple wrappers that multiply quaternions + // runtime.register_function("transformRotateX", |mut t: Transform, a: f64| { + // let r = DQuat::from_rotation_x(a); + // t.rotation = r * t.rotation; + // t + // }); + // runtime.register_function("transformRotateY", |mut t: Transform, a: f64| { + // let r = DQuat::from_rotation_y(a); + // t.rotation = r * t.rotation; + // t + // }); + // runtime.register_function("transformRotateZ", |mut t: Transform, a: f64| { + // let r = DQuat::from_rotation_z(a); + // t.rotation = r * t.rotation; + // t + // }); + + // // utils already in your file — log and time + // runtime.register_function("log", |msg: String| { + // println!("[Script] {}", msg); + // }); + // runtime.register_function("time", || { + // std::time::SystemTime::now() + // .duration_since(std::time::UNIX_EPOCH) + // .unwrap() + // .as_secs_f64() + // }); Self { - engine, + runtime, compiled_scripts: HashMap::new(), script_scopes: HashMap::new(), } @@ -1,20 +0,0 @@ -// Docs: -// https://github.com/4tkbytes/dropbear/blob/main/docs/README.md - -fn init() { - print("Script initialised!"); - // Access the entity's transform - // transform.position.x = 0.0; -} - -fn update(dt) { - // Example: rotate the entity - // let rotation_speed = 1.0; - // transform.position.x = sin(time()) * 2.0; - // transform.position.y = cos(time()) * 2.0; - - // Example: log every second - // if (time() % 1.0 < dt) { - // print("Entity position: " + transform.position.x + ", " + transform.position.y + ", " + transform.position.z); - // } -} @@ -0,0 +1 @@ +// todo @@ -0,0 +1,46 @@ +// Modules for the dropbear-engine scripting component + +type TransformT = any; +type Vec3T = any; +type QuatT = any; + +function hostFn(name: string) { + const fn = (globalThis as any)[name]; + if (typeof fn !== "function") { + throw new Error(`Host function ${name}() is not available. Make sure the runtime exposes it.`); + } + return fn; +} + +const Transform = { + create: (): TransformT => hostFn("createTransform")(), + translate: (transform: TransformT, translation: [number, number, number] | number[]): TransformT => + hostFn("transformTranslate")(transform, translation), + rotateX: (transform: TransformT, angle: number): TransformT => + hostFn("transformRotateX")(transform, angle), + rotateY: (transform: TransformT, angle: number): TransformT => + hostFn("transformRotateY")(transform, angle), + rotateZ: (transform: TransformT, angle: number): TransformT => + hostFn("transformRotateZ")(transform, angle), + scale: (transform: TransformT, scale: number | [number, number, number]): TransformT => + hostFn("transformScale")(transform, scale), + matrix: (transform: TransformT): TransformT => hostFn("transformMatrix")(transform), +}; + +const Vec3 = { + create: (x = 0, y = 0, z = 0): Vec3T => hostFn("createVec3")(x, y, z), + zero: (): Vec3T => hostFn("createVec3")(0, 0, 0), + one: (): Vec3T => hostFn("createVec3")(1, 1, 1), +}; + +const Quaternion = { + identity: (): QuatT => hostFn("createQuatIdentity")(), + fromEuler: (x: number, y: number, z: number): QuatT => hostFn("createQuatFromEuler")(x, y, z), +}; + +// make global +export { Transform, Vec3, Quaternion }; + +globalThis.Transform = Transform; +globalThis.Vec3 = Vec3; +globalThis.Quaternion = Quaternion;