Rust, I just wanted to spawn a Tank!

Sean Wragg
Sean’s Blog
Published in
5 min readMar 12, 2023
Bradley APC in Rust (via Rustified)

The goal and background

A few friends and I recently started playing Rust and it can certainly be a lot of fun. So long as you can manage to stay alive..

As we got further into the game, one friend decided to host a server — which has been great for learning more about the game! To add to the fun, he installed the Guarded Crate plugin by Bazz3l.

The plugin functionality is straight forward: it randomly spawns events throughout the map with Locked Crates. If you defeat the Guards (“Scientists”) protecting the Crate, you get the sweet, sweet loot locked inside.

Never satisfied, we wondered if it’d be possible to extend it with the following functionality:

  • Spawn BradleyAPC Tank to help protect the Crate (because why not?)

And while we’re there, a couple minor tweaks:

  • Event to spawn at Player’s current location (instead of only random)
  • Add Guard diversity (so they’re no longer all the same)

Simple, so let’s just modify the plugin!

Now that we have our scope defined, I quickly realized I know nothing about the following:

  • Rust plugin development
  • Unity
  • C#

Apparently, all important things when authoring or modifying Rust plugins.

Okay, well let’s start with the documentation!

Good luck. Rust plugin documentation is incredibly sparse!
— Some Random Developer

Seriously, this is probably an understatement. Most forums tell you to, “just look at other plugins”. While that certainly never hurts, here’s a few references that helped me along the way:

Decompiling Rust Server DLLs

If you’re starting out and curious about methods, capabilities, and default behaviors, you’ll need to decompile Assembly-CSharp.dll (one of Rust’s main server libraries)

You can get this DLL by completing the first step in Create a Rust server. You don’t need to run the server, just allow it to download the most recent DLL

It may sound like a daunting step (one that I put off WAY longer than I should have) but, incredibly insightful. And thankfully there’s many tools that make this easy.

Telerik’s JustDecompile is a great free tool (despite needing to sign up) and made reviewing Rust internals a breeze.

This step helped me feel much more prepared to dive into existing Plugin code, so let’s move on to the fun!

Allow Event to spawn at Player location

The plugin already has the ability to spawn at random locations, I figured it couldn’t be too difficult to spawn on the player instead and could serve as a good entry point into the existing Plugin code.

Thankfully, it turned out to be easier than I thought:

private Vector3 GetPlayerPosition(IPlayer player)
{
BasePlayer _player = player.Object as BasePlayer;
return _player.transform.position;
}

I simply created and basically referenced this method, wherever FindRandomPosition() was found

Sidenote: I don’t yet understand the relationship between IPlayer and BasePlayer. Almost everything extends from a “Base”-related class, so the type coercion may not be necessary. I also don’t yet fully understand Unity’s Vector3 outside of it being a representation of space or points on the map.

Success!! The event spawned on me instead of a random location!

Yup, lesson learned... enable God mode when testing 🤦‍♂️

Adding Guard diversity

After reviewing a few other plugins, I was able to find the prefab locations of the other Scientists.

I slung them into an array, then learned about Unity’s Random.Range(), and used this inside the existing NPC spawn method instead. Super Easy!

string[] NPC_PREFABS = {
"assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_roam.prefab",
"assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab",
"assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_oilrig.prefab",
"assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_patrol.prefab"
};

var prefab = NPC_PREFABS[Random.Range(0, NPC_PREFABS.Length - 1)];
var npc = (ScientistNPC)GameManager.server.CreateEntity(prefab, position, rotation);

To my delight, it cycled through the Scientist prefabs

Woot! They’re different now!

Spawn BradleyAPC Tank

Alright, different Guard prefabs was easy enough. Let’s try the Tank!

I added the following code to the NPC spawn method

string BRADLEY_PREFAB = "assets/prefabs/npc/m2bradley/bradleyapc.prefab";

var apc = (BradleyAPC)GameManager.server.CreateEntity(BRADLEY_PREFAB, position, rotation);
apc.enableSaving = false;
apc.Spawn();

Annnd…

Tank is running away, shooting his friends and doesn’t care about me... fail-tastic!

So apparently…the BradleyAPC has a mind of its own.

It may be hard to tell but, it’s opening fire on its NPC friends and trying to complete its predefined path 🤷‍♂️

This is where decompiling Assembly-CSharp.dll was incredibly helpful. I was able to understand which methods were available to control the APC (unfortunately, not many).

apc.targetList.Clear();
apc.ClearPath();

The two above though, help prevent the Tank from taking a casual stroll wherever it decides. It also removes all immediate targets. Now the end result is more inline with what we’d expect!

Diversity, at my location, and a Tank! Success!!

There’s probably far more sophisticated ways to control Tank NPC targets as I certainly don’t purport to be an expert but, this was an incredibly fun way to learn the Rust plugin ecosystem and complexities to “just” spawning any NPC!

Check out my (crude) changes to the GuardedCrate plugin below!

Happy Rust’ing!

--

--