pite-script 0.3.0

Embedded Python 3.12 scripting bridge (PyO3) and game API for Pite.
Documentation
// SPDX-License-Identifier: MIT OR Apache-2.0
//! `pite-script`: `ScriptBackend` trait. PyO3 is the only impl;
//! future backends (or a mock for tests) plug in without touching runtime.

mod audio;
pub mod descriptor;
mod host;
mod input;
pub mod physics_bridge;
mod python;
pub mod vec2;

use anyhow::Result;

pub use descriptor::{child, node, PyChildDescriptor, PyNodeDescriptor};
pub use host::{
    fire_area_entered, fire_area_exited, fire_body_entered, fire_body_exited, fire_pressed,
    fire_timeout, proxy_for, resolve_caller, resolve_caller_py, set_current_host, NodeProxy,
    ScriptHost,
};
pub use input::{
    input_begin_frame, input_clear, input_held, input_mouse, input_pressed, input_released,
    input_set_key, input_set_mouse,
};
pub use physics_bridge::{current_physics, set_current_physics, with_physics};
pub use pyo3;
pub use python::{is_stdlib_module, InputQueryKind, PyInputQuery, Pyo3Backend, ScriptError};
pub use vec2::Vec2;

pub const RESERVED_METHODS: &[&str] = &["emit", "connect"];

/// Project root used to resolve `res://` asset refs from Python.
static PROJECT_DIR: std::sync::Mutex<Option<std::path::PathBuf>> = std::sync::Mutex::new(None);

pub fn set_project_dir(dir: Option<std::path::PathBuf>) {
    *PROJECT_DIR.lock().expect("project dir lock") = dir;
}

pub fn project_dir() -> Option<std::path::PathBuf> {
    PROJECT_DIR.lock().expect("project dir lock").clone()
}

pub fn is_reserved(name: &str) -> bool {
    RESERVED_METHODS.contains(&name)
}

pub trait ScriptBackend {
    fn load(&mut self, path: &str, class: &str) -> Result<()>;
    fn call_ready(&mut self) -> Result<()>;
    fn call_process(&mut self, delta: f64) -> Result<()>;
    fn call_physics_process(&mut self, _delta: f64) -> Result<()> {
        Ok(())
    }
    fn reload(&mut self) -> Result<()>;

    fn position(&self) -> Option<(f64, f64)> {
        None
    }

    fn set_position(&mut self, _x: f64, _y: f64) {}

    fn velocity(&self) -> Option<(f64, f64)> {
        None
    }

    fn set_velocity(&mut self, _vx: f64, _vy: f64) {}

    fn set_on_floor(&mut self, _on_floor: bool) {}
    fn set_on_wall(&mut self, _on_wall: bool) {}
    fn set_on_ceiling(&mut self, _on_ceiling: bool) {}

    fn text(&self) -> Option<String> {
        None
    }

    fn set_text(&mut self, _text: &str) {}

    fn size(&self) -> Option<(f64, f64)> {
        None
    }

    fn set_size(&mut self, _w: f64, _h: f64) {}

    fn wait_time(&self) -> Option<f64> {
        None
    }

    fn set_wait_time(&mut self, _wait: f64) {}

    fn last_error(&self) -> Option<String> {
        None
    }

    fn last_script_error(&self) -> Option<ScriptError> {
        None
    }
}

#[derive(Debug, Default)]
pub struct NoopBackend;

impl ScriptBackend for NoopBackend {
    fn load(&mut self, _path: &str, _class: &str) -> Result<()> {
        Ok(())
    }

    fn call_ready(&mut self) -> Result<()> {
        Ok(())
    }

    fn call_process(&mut self, _delta: f64) -> Result<()> {
        Ok(())
    }

    fn reload(&mut self) -> Result<()> {
        Ok(())
    }
}