Cactus/
main.rs

1//! The servers's entrypoint file.
2mod args;
3mod commands;
4mod config;
5mod consts;
6mod fs_manager;
7mod logging;
8mod net;
9use log::{error, info, warn};
10use net::packet;
11use std::net::Ipv4Addr;
12mod greetings;
13mod handlers;
14mod player;
15mod shutdown;
16mod time;
17use config::Gamemode;
18use consts::messages;
19#[tokio::main]
20async fn main() {
21    if let Err(e) = early_init().await {
22        error!("Failed to start the server, error in early initialization: {e}. \nExiting...");
23        gracefully_exit(ExitCode::Failure);
24    }
25
26    if let Err(e) = init() {
27        error!("Failed to start the server, error in initialization: {e}. \nExiting...");
28        gracefully_exit(ExitCode::Failure);
29    }
30
31    if let Err(e) = start().await {
32        error!("Failed to start the server: {e}. \nExiting...");
33        gracefully_exit(ExitCode::Failure);
34    }
35
36    info!("{}", *messages::SERVER_SHUTDOWN_SUCCESS);
37}
38#[cfg(debug_assertions)]
39const DISABLE_LOGGING_COLOR_AND_SAVE_TO_FILE: bool = false;
40
41#[cfg(not(debug_assertions))]
42const DISABLE_LOGGING_COLOR_AND_SAVE_TO_FILE: bool = true;
43/// Logic that must executes as early as possibe
44async fn early_init() -> Result<(), Box<dyn std::error::Error>> {
45    // This must executes as early as possible
46    logging::init(
47        log::LevelFilter::Debug,
48        DISABLE_LOGGING_COLOR_AND_SAVE_TO_FILE,
49    );
50
51    args::init();
52
53    info!("{}", *messages::SERVER_STARTING);
54
55    // Adds custom behavior to CTRL + C signal
56    handlers::init_ctrlc_handler()?;
57    // A testing function, only in debug mode
58    #[cfg(debug_assertions)]
59    test();
60
61    // Listens for cli input commands
62    commands::listen_console_commands().await;
63    Ok(())
64}
65
66/// Essential server initialization logic.
67fn init() -> Result<(), Box<dyn std::error::Error>> {
68    // Printing a greeting message
69    greetings::greet();
70
71    vec![
72        || fs_manager::init(),
73        || Ok(fs_manager::create_dirs()),
74        || Ok(fs_manager::create_other_files()),
75    ]
76        .iter()
77        .try_for_each(|task| task())?;
78
79    let gamemode1 = match config::Settings::new().gamemode {
80        Gamemode::Survival => "Survival",
81        Gamemode::Adventure => "Adventure",
82        Gamemode::Creative => "Creative",
83        Gamemode::Spectator => "Spectator",
84    };
85    info!("Default game type: {}", gamemode1.to_uppercase());
86
87    Ok(())
88}
89
90/// Starts up the server.
91async fn start() -> Result<(), Box<dyn std::error::Error>> {
92    info!(
93        "Starting Minecraft server on {}:{}",
94        config::Settings::new()
95            .server_ip
96            .unwrap_or(Ipv4Addr::new(0, 0, 0, 0)), // 0.0.0.0
97        config::Settings::new().server_port
98    );
99    info!("{}", *messages::SERVER_STARTED);
100
101    net::listen().await?;
102
103    Ok(())
104}
105
106#[cfg(debug_assertions)]
107/// A test fonction that'll only run in debug-mode. (cargo run) and not (cargo run --release)
108fn test() {
109    info!("[ BEGIN test() ]");
110
111    // Do not remove this line, yet.
112    // Uh, why is that so?
113    let _ = packet::Packet::new(&[]);
114
115    info!("[ END test()]");
116}
117
118/// Enum representing standardized server exit codes.
119pub enum ExitCode {
120    Success,
121    Failure,
122    CtrlC,
123}
124
125/// Gracefully exits the server with an exit code.
126pub fn gracefully_exit(exit_code: ExitCode) -> ! {
127    let numerical_exit_code: i32 = match exit_code {
128        ExitCode::Success => {
129            info!("{}", *messages::SERVER_SHUTDOWN_SUCCESS);
130            // 0 means success
131            0
132        }
133        ExitCode::Failure => {
134            warn!("{}", *messages::SERVER_SHUTDOWN_ERROR);
135            // 1 mean general error
136            1
137        }
138        ExitCode::CtrlC => {
139            info!("{}", *messages::SERVER_SHUTDOWN_CTRL_C);
140            // 130 mean script terminated by Ctrl+C
141            130
142        }
143    };
144
145    // Well, for now it's not "gracefully" exiting.
146    std::process::exit(numerical_exit_code);
147}