William Hutchins
Backback

Minecraft server setup

This project was basically my "hello world" for Rust.

We have a local Minecraft server that me and my siblings use, and this was previously done by using a long bash command that would execute a .jar within a directory to run minecraft, however it was very messy and needed to be adjusted manually to change settings.

After reading up a decent chunk on the official Rust book and doing the tutorials I got into making the selector for settings to run the server (that had previously needed manual changing of the command run). Through this I learned about Rust's differences with how logic is done, due to variables being limited to the scope it is in I would put the user input into a seperate function as to not let the code balloon with loads of variables set exclusively to take an input.

// Takes a numerical input from the user and validates it
    fn path_input(x: u16) -> u16 {
        loop {
            println!("Which option do you choose [0 to exit]: ");
            
            let mut input: String = String::new();
            stdin().read_line(&mut input).expect("Did not enter a correct string");
            match input.trim().parse::<u16>() {
                Ok(o) => if o < x {return o} else {println!("Error: choose a number less than {}", x)},
                Err(e) => println!("Error: {}", e),
            }
        }
    }
An early iteration of the function used for inputs.

Once I had the selection system functional I began working on executing the .jar through Rust code. From looking online I came to the stdin library and implemented the command and voilà! the server was up and running with the settings I had selected, however I was not getting an interface and there was no way to input anything into the running server from the terminal. This was not good enough as I couldn't safely shut down the server without the command to do so, so I turned to stack overflow. I created this thread asking for solutions and got a very fast response letting me know how to put the instance on a child thread. I was also using the .output() function instead of the .spawn() function, which waits for the process to finish instead of allowing inputs. After this I got another suggestion that would help me use more Rust and less bash by navigating directories with the std::fs library in Rust - and after applying all of the code I ended up with a 1.0 version of the program. I've since fixed bugs and added more options but its less problem solving and logic to implement than the initial project.

// Runs the bash script to launch the server
    let mut server = Command::new("/bin/sh")
        .args(["-c", &command])
        .stdin(Stdio::piped())
        .spawn()
        .expect("failed to start process");
    
// Takes inputs for the server, kills the server without panic if the input does not go through correctly
    let mut server_command: String = String::new(); 
    while server_command.trim() != "stop" && server_command.trim() != "/stop" {
        server_command = input_string();
        if let Some(stdin) = server.stdin.as_mut() {
            match stdin.write_all(format!("{server_command}\n").as_bytes()) {
                Ok(_o) => (), 
                Err(_e) => return,
            };
        };
    };
A later iteration of the launch server code.

Conclusion

Overall I think this project really had more going on than it seemed on the surface, using threads, stdin and fs I think it was a really good introductory project to get me into the language and it is still getting the occasional tweak while being in use currently.