dreamwell-runtime 1.0.0

Dreamwell Runtime — cross-platform GPU-accelerated game client
Documentation
// Dreamwell Runtime entry point.

// Keep console visible for diagnostics. Production builds can re-enable:
// #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use clap::Parser;

/// Dreamwell Runtime — cross-platform GPU-accelerated game client.
#[derive(Parser)]
#[command(name = "dreamwell-runtime")]
struct Args {
    /// Waymark pack JSON file to load.
    #[arg(long)]
    pack_file: Option<String>,
    /// Tapestry lock file for play mode.
    #[arg(long)]
    lock_file: Option<String>,
    /// Scene name within the pack.
    #[arg(long, default_value = "default")]
    scene_name: String,
    /// SpacetimeDB host (enables remote authority).
    #[arg(long)]
    host: Option<String>,
    /// SpacetimeDB database name.
    #[arg(long, default_value = "dreamwell")]
    db_name: String,
    /// Window title.
    #[arg(long, default_value = "Dreamwell")]
    title: String,
    /// Window width.
    #[arg(long, default_value_t = 1920)]
    width: u32,
    /// Window height.
    #[arg(long, default_value_t = 1080)]
    height: u32,
}

/// Main thread stack size: 8 MB.
/// DreamFabric holds ~30 GPU pass structs inline. Combined with wgpu internals,
/// the default 1 MB Windows stack is insufficient. 8 MB matches Unreal/Unity defaults.
const MAIN_STACK_SIZE: usize = 8 * 1024 * 1024;

fn main() {
    // Spawn the real entry point on a thread with a larger stack.
    let builder = std::thread::Builder::new()
        .name("dreamwell-main".into())
        .stack_size(MAIN_STACK_SIZE);
    let handler = builder.spawn(run).expect("failed to spawn main thread");
    if let Err(e) = handler.join() {
        eprintln!("runtime thread panicked: {e:?}");
        std::process::exit(1);
    }
}

fn run() {
    env_logger::init();

    // Panic hook: write crash info to log file before abort.
    std::panic::set_hook(Box::new(|info| {
        let msg = format!("{info}");
        eprintln!("PANIC: {msg}");
        let _ = std::fs::write("dreamwell-runtime.panic.log", &msg);
    }));

    let args = Args::parse();

    log::info!("Dreamwell Runtime starting");

    let authority_mode = if args.host.is_some() {
        dreamwell_runtime::AuthorityMode::Remote
    } else {
        dreamwell_runtime::AuthorityMode::Local
    };

    let config = dreamwell_runtime::RuntimeConfig {
        title: args.title,
        width: args.width,
        height: args.height,
        authority_mode,
        pack_file: args.pack_file,
        lock_file: args.lock_file,
        db_host: args.host,
        db_name: args.db_name,
        ..Default::default()
    };

    let runtime = match dreamwell_runtime::Runtime::new(config) {
        Ok(r) => r,
        Err(e) => {
            log::error!("Failed to create runtime: {e}");
            std::process::exit(1);
        }
    };
    if let Err(e) = runtime.run() {
        log::error!("Runtime exited with error: {e}");
        std::process::exit(1);
    }
}