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.