Learn By Example: Bash Script - Godot 4 Project Creator
Published at Sep 13, 2024
Total Views:
Bash scripting is a powerful way to automate workflows, build your own tools, and ultimately save a lot of time. In this blog post, we’ll dive into a real-world bash script I’ve created to automate the setup of new Godot projects. We’ll walk through this script step-by-step, explaining key concepts and how they come together to create a useful tool for your own projects.
Before we begin, if you’re new to bash scripting or need a refresher, feel free to check out my Bash Script Tool Kit for foundational concepts.
The Problem:
I love dabbling in game development on the side. It’s been a super fun hobby, and I find myself starting new projects all the time. However, as time went on, I accumulated a lot of assets and wrote various tools and utilities in C# that I like to add to each project. But here’s the issue—I don’t want to add all of them to every project. I have grouped my assets and tools into modules, and some projects need certain assets and tools while others don’t.
Manually adding these files and assets to each new project became incredibly cumbersome. So, I decided to write a bash script to automate the process!
Overview of the Script:
Here’s what I needed the script to do:
At its simplest, I wanted to run gdcreate "{name of project}"
and have it create a new Godot project. But I also wanted some additional options:
- Initialize a Git repository and push it to a remote (in this case, GitLab, because their free tier is great for private projects—especially when I have proprietary assets I don’t want the world downloading for free).
- Add specific asset packs from my collection, grouped into modules (e.g., dark fantasy assets, biomes, character controllers).
- Add common C# utilities that I use throughout my Godot projects.
For example, I wanted to run a command like this:
gdcreate ProjectName --assets "dfantasy,biomes,ccontrollers" --gitinit --utils
This command would:
- Create a new Godot 4 project.
- Add the asset packs I’ve grouped as
dfantasy
,biomes
, andccontrollers
to the project. - Add my favorite C# utilities.
- Initialize Git and push the project to my private GitLab group.
Now, let’s break everything down step by step!
Step 1: Script Usage Function
usage() {
echo "Usage: gdcreate ProjectName --assets "dfantasy,biomes,ccontrollers" --gitinit --utils"
exit 1
}
The usage
function defines how the script should be used. It helps guide the user by showing them the correct format for calling the script. If the script is run incorrectly, this function will display usage instructions and then exit
the script with a failure status (1
).
Key Bash Concepts:
function_name() {}
: Defines a bash function.echo
: Prints a string to the terminal.exit 1
: Terminates the script with an error code.
Step 2: Copying Assets Based on User Input
copy_assets() {
cp -r "$HOME/Documents/Godot/Template/src/Materials" "$PROJECT_DIR/src/Materials"
local project_dir=$1
IFS=',' read -ra ASSETS <<< "$2"
for asset in "${ASSETS[@]}"; do
case "$asset" in
dfantasy) src_path="$HOME/Documents/Godot/Template/src/DarkFantasy";;
biomes) src_path="$HOME/Documents/Godot/Template/src/Biomes";;
ccontrollers) src_path="$HOME/Documents/Godot/Template/src/CharacterControllers"
dest_path="$project_dir/src/CharacterControllers"
mkdir -p "$(dirname "$dest_path")"
cp -r "$src_path" "$dest_path"
update_namespace "$dest_path"
continue;;
*) echo "Unknown asset: $asset"; exit 1;;
esac
dest_path="$project_dir/src/$(basename "$src_path")"
mkdir -p "$(dirname "$dest_path")"
cp -r "$src_path" "$dest_path"
done
}
The copy_assets
function copies the specified assets (such as “Dark Fantasy” or “Biomes”) into the new project directory. Here’s a breakdown of what’s happening:
cp -r
: Copies files recursively (meaning it includes subdirectories).local
: Declares variables that are scoped only within the function.IFS=','
: Defines the delimiter used to split the asset list into an array. In this case, we’re splitting by commas.for asset in ...
: Loops through each asset provided by the user.case
: Evaluates the asset name and sets thesrc_path
accordingly.
Key Concepts:
- Arrays in Bash: The
IFS
andread
command allow us to split a string into an array and loop over it. - Switch-case: The
case
block allows for conditional logic based on the asset name.
Step 3: Updating Namespaces in .cs
Files
update_namespace() {
local directory=$1
local old_namespace="Template"
local new_namespace=$PROJECT_NAME
find "$directory" -type f -name "*.cs" -exec sed -i "s/namespace $old_namespace/namespace $new_namespace/g" {} +
find "$directory" -type f -name "*.cs" -exec sed -i "s/using $old_namespace/using $new_namespace/g" {} +
}
This function updates namespaces in all .cs
files within a given directory by replacing occurrences of Template
with the project’s name. It uses the powerful combination of find
and sed
.
Key Concepts:
find
command: Searches through directories to find files that match specific criteria (in this case,.cs
files).sed
command: A stream editor used to modify files. Here, it’s being used to replace text within the files.-exec
option: Executes a command on each file found byfind
.
Step 4: Creating GUIDs
generate_guid() {
uuidgen | tr '[:upper:]' '[:lower:]'
}
This function generates a unique identifier (GUID) and ensures it’s in lowercase. uuidgen
generates a UUID, and tr
translates uppercase letters to lowercase.
Key Concepts:
uuidgen
: A command-line tool for generating universally unique identifiers.tr
: A command used to translate characters in a string.
Step 5: Creating the Project Directory and Files
mkdir -p "$PROJECT_DIR/src"
cat > "$PROJECT_DIR/$PROJECT_NAME.csproj" <<EOL
<Project Sdk="Godot.NET.Sdk/4.2.2">
...
</Project>
EOL
This creates the project directory (mkdir -p
) and writes the .csproj
file using a heredoc
. A heredoc allows you to create multi-line strings in bash scripts, making it easier to write template files like this.
Key Concepts:
mkdir -p
: Creates a directory and any necessary parent directories.- Heredoc (
<<EOL
): A way to write multi-line strings in bash.
Step 6: Git Initialization and Repository Creation
if $GITINIT; then
cp "$HOME/Documents/Godot/Template/.gitignore" "$PROJECT_DIR/"
cd "$PROJECT_DIR"
glab repo create learning-godot-4/$PROJECT_NAME --private --group --source . --push
git init -b trunk
git add .
git commit -m "Initial commit"
git remote add origin "git@gitlab.com:learning-godot-4/$PROJECT_NAME.git"
git push -u origin trunk
fi
This section initializes a Git repository, creates a new project on GitLab using the glab
CLI, and pushes the project to the remote repository.
Key Concepts:
glab
: A CLI tool for GitLab that lets you manage repositories directly from the command line.git
commands: Initializes a repository, stages changes, commits them, and pushes to a remote repository.
Step 7: Final Touches
The script wraps up by copying utilities if the --utils
flag is provided and appending configurations to the Godot project’s configuration file (project.godot
).
Conclusion
This script demonstrates how you can use bash to automate repetitive tasks, making your workflow more efficient and freeing up time to focus on coding. It covers concepts like string manipulation, loops, conditionals, and file handling—core tools in any bash scripter’s toolkit.
If you’re wondering whether it’s worth building your own tools, I encourage you to check out my blog post on why writing your own tools matters.
I hope this breakdown has helped you understand the power of bash scripting and how you can leverage it to build tools that build tools! Feel free to share your thoughts or questions in the comments below. Until next time, happy scripting! 🧙
Comments
No comments yet.
You must be logged in to add a comment.