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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! Starting point for the catgirl-engine as a library

#![warn(missing_docs)]

#[macro_use]
extern crate tracing;

/// Prepare the game engine for running
pub mod setup;

use core::ffi::{c_char, c_int};

#[cfg(target_os = "android")]
use winit::platform::android::activity::AndroidApp;

#[cfg(target_family = "wasm")]
use wasm_bindgen::prelude::wasm_bindgen;

extern crate wasm_bindgen;

// Run as Library
/// Catgirl Engine start
///
/// The starting point when calling as a generic library
#[no_mangle]
#[cfg_attr(target_family = "wasm", wasm_bindgen)]
pub extern "C" fn ce_start(argc: c_int, argv: *const *const c_char) -> c_int {
    #[cfg(feature = "tracing-subscriber")]
    setup::setup_tracer();

    // Setup logger for debugging
    setup::setup_logger();

    // Create a vector of args from C styled args
    // We create a new pointer so we guarantee the pointer we are passing is valid
    // This doesn't say anything about the underlying data, but that's the responsibility of
    //   parse_args_from_c(...) to validate
    let args: Option<Vec<String>>;
    unsafe {
        args = utils::args::parse_args_from_c(argc, argv.cast::<*const *const c_char>());
    }

    // Override Clap's args
    if let Some(args) = args {
        trace!("Args: {:?}", args);
        utils::args::set_parsed_args(args);
    }

    // Print version and copyright info
    if setup::get_args().version {
        setup::print_version();
        setup::print_dependencies();
        return 0;
    }

    // Process args for future use
    setup::process_args();
    debug!("Launched as library...");
    trace!("Built for Arch: {}", setup::build_info().target.cpu.arch);

    let results: Result<(), String> = setup::start();
    trace!(
        "Exit was called with code: {}",
        utils::setup::get_exit_code()
    );
    match results {
        Err(error) => {
            error!("{:?}", error);

            c_int::from(utils::setup::get_exit_code())
        }
        _ => 0,
    }
}

#[no_mangle]
#[cfg(all(target_os = "android", feature = "client"))]
/// The starting point when loaded as an Android app
///
/// # Panics
///
/// Could not get path for assets
pub extern "Rust" fn android_main(app: AndroidApp) {
    #[cfg(feature = "tracing-subscriber")]
    setup::setup_tracer();

    // Setup logger for debugging
    setup::setup_logger();

    // Store android app for later use
    utils::store_android_app(app.clone());

    // TODO: Detect when user grants storage permission
    // TODO: User internal app folder until permission is granted (app.internal_data_path())
    trace!(
        "Has Storage Permission (Rust): {}",
        utils::android::request_read_storage_permissions()
    );

    // Override Clap's Args
    let args: Vec<String> = vec![
        utils::get_own_path(),
        "--assets".to_string(),
        utils::android::get_assets_directory(),
    ]; // ["/system/bin/app_process64", "--assets", "/sdcard/assets"]
    trace!("Args: {:?}", args);
    utils::args::set_parsed_args(args);

    // Process args for future use
    setup::process_args();
    debug!("Launched as Android app...");
    trace!("Built for Arch: {}", setup::build_info().target.cpu.arch);

    // android_main is void, so there's no way to return a code
    let results: Result<(), String> = setup::start();
    trace!(
        "Exit was called with code: {}",
        utils::setup::get_exit_code()
    );
    if let Err(ref error) = results {
        error!("{:?}", error);
    }
}

#[no_mangle]
#[cfg(target_family = "wasm")]
#[wasm_bindgen(start)]
/// The starting point when loaded via wasm bindgen
pub extern "Rust" fn wasm_start() {
    // Temporary panic hook until logger is finished initializing
    std::panic::set_hook(Box::new(console_error_panic_hook::hook));

    #[cfg(feature = "tracing-subscriber")]
    setup::setup_tracer();

    // Setup logger for debugging
    setup::setup_logger();

    // TODO: Implement custom arg handling here

    // Process args for future use
    setup::process_args();
    debug!("Launched as Wasm library...");
    trace!("Built for Arch: {}", setup::build_info().target.cpu.arch);

    // This function exits immediately due to its async nature
    //   when built for wasm
    if let Err(ref error) = setup::start() {
        error!("{:?}", error);
    }
}