4 Hugues Ross - Blog: Capstone Update 13: Making a Monster
Hugues Ross

2/12/16

Capstone Update 13: Making a Monster

The time has come for me to return, take up my mantle as an AI programmer, and write a bait-and-switch post about Unix shell scripting. I did work on our buddy the shadow monster this week, but it's not in the game yet and I'll be making much more progress on it this weekend. In the meantime, I'm going to make a post about a specific problem, and how I solved it with a just a tiny bit of scripting.

If you've used Unreal Engine 4, you probably know about the Substance plugin. This plugin is useful for making materials, but also has some issues. First off, it absolutely does not run on Linux. Given that my primary dev machine exclusively runs Linux, this is a problem. If I try loading a project that contains the plugin without installing it, Unreal simply crashes. The second issue is that it spreads. For some reason, installing Substance in one project seems to make it quietly install itself into other projects. So, if a single member installs Substance, the rest of the team will have to install the plugin on every new computer that they load the project onto.
Clearly, we have a problem.

However, I'm not here to complain about a problem, but instead to describe how I solved it. As a linux user, I think I can safely say that I'm more comfortable with shell scripting than your average developer. I'm also quite comfortable with git's command-line interface as well. Lastly, I know that Unreal stores plugins in the its text-based .uproject file. Going with my knowledge and experience, I decided to try and create a script that could auto-remove Substance whenever it appeared, so that no-one would ever need to deal with it on this project again.

Search and Destroy

The first thing that I had to tackle was finding and removing Substance. After all, if I couldn't do that then there would be no point to this exercise. Here's an example of a .uproject file with Substance installed:
{
    "FileVersion": 3,
    "EngineAssociation": "4.9",
    "Category": "",
    "Description": "",
    "Modules": [
        {
            "Name": "MindTreeGames",
            "Type": "Runtime",
            "LoadingPhase": "Default",
            "AdditionalDependencies": [
                "Engine",
                "CoreUObject"
            ]
        }
    ],
    "Plugins": [
        {
            "Name": "Substance",
            "Enabled": true,
            "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/offers/2f6439c2f9584f49809d9b13b16c2ba4"
        }
    ]
}
Keeping in mind that the plugins section only appears if there are plugins installed, and that The Last Light doesn't make use of any plugins. In other words, we're free to simply wipe the Plugins section out entirely. Of course, we still need to find Substance, but we can easily fix that with a simple grep.
# Grep provides us with a line number at the start of the line, so we use cut
# to isolate it
substance_line=`grep -n "Substance" $project_file | cut -f1 -d:`

# Then, all we need to do is check if the resulting variable is empty or not
if [ -z $sub_line ]; then
    echo "No Substance here, but remain vigilant!"
else
    # The +/- parts here are hardcoded, based on the fact that our .uproject
    # file is relatively stable.
    start_l=$((sub_line - 3))
    end_l=$((sub_line + 3))

    # Delete the calculated lines, and get the resulting file
    result=`sed "$start_l,$end_l d" $project_file`

    # Now, just write out the result to the file. I take this extra step so that
    # I can provide a preview before making the change.
    echo -e "$result" > $project_file
fi
With this basic script, we can now find and remove the Substance plugin from a project with a single call!

Hooking it Up

I had a good start with my script, but I wanted a proper automated solution. Luckily, git provides us with the necessary tools to make this happen. By placing scripts in the .git/hooks directory, we can add scripts that are called on certain git-related events. If we add our script as a post-merge hook, then we can make our script run every time we pull changes from a remote.

In addition to adding a hook, we may want to commit our changes, and push them to save other team members the work of removing it themselves. As it turns out, we can simply call git commit and git push from a post-merge hook, and they work completely fine.
# Grep provides us with a line number at the start of the line, so we use cut
# to isolate it
substance_line=`grep -n "Substance" $project_file | cut -f1 -d:`

# Then, all we need to do is check if the resulting variable is empty or not
if [ -z $sub_line ]; then
    echo "No Substance here, but remain vigilant!"
else
    # The +/- parts here are hardcoded, based on the fact that our .uproject
    # file is relatively stable.
    start_l=$((sub_line - 3))
    end_l=$((sub_line + 3))

    # Delete the calculated lines, and get the resulting file
    result=`sed "$start_l,$end_l d" $project_file`

    # Now, just write out the result to the file. I take this extra step so that
    # I can provide a preview before making the change.
    echo -e "$result" > $project_file

    # Commit and push our changes immediately
    git commit -a -m "[bot] Removed Substance Plugin"
    git push origin master
fi
With these changes, all we have to do when we pull in the Substance Plugin is type in a password, and our script handles the rest.

No comments: