/Universal-Unity-ESP

This is a guide to creating an ESP for any unity game.

Primary LanguageC#MIT LicenseMIT

Universal-Unity-ESP

This is a guide to creating an Internal ESP for any Unity Engine game. (Source included in the Universal-Unity-ESP folder, video guide here)

If you plan to just use the source, make sure you change the DLLs (Project References), and change to your gameobject :)

NOTICE: If you have not created a Unity Internal before, I suggest you watch my tutorial that will introduce you to the basics, and give you knowledge that will be needed for this guide (ex: creating a class library, reversing gameobjects, adding references, setting up loader, etc.)

Example

What Is Unity Engine?

Unity Engine is one of the worlds most popular game engines, supporting a large array of platforms including Mobile, Desktop, and Console. Due to its success, many of the games you play are made in Unity, examples including Rust, Escape from Tarkov, Totally Accurate Battlegrounds, and Muck just to name a few.

Unity Engine is built on GameObjects and Components. To understand the basics of how the engine works, please refer to this slideshow

Creating an ESP

Getting the Player GameObject


In a regular memory based ESP, the first step is to find the Entity List. The Entity List contains information on each player in the game, such as positional data, health, ammo, and more.

In our case since we are making an Internal ESP we have access to the game's GameObjects, and we can find the player GameObject and manipulate its Components directly, creating an entity loop by finding every gameobject of a type in the game scene. To find the player gameobject we need to use the software dnSpy, which will allow us to view Unity Assemblies. We simply drag in our Assembly-CSharp and Assembly-CSharp-firstpass DLLs and we can view the games classes. Then trial-and-error your way through finding the right Player class (usually it will be called something along the lines of player), as pictured below I found it for Muck. All we need is the name of the class, so once you have found it you are ready for the next step.

OnlinePlayer

Getting GameObject Position


Instead of having to find pointers in memory to the entitylist and then getting the entity position from there, we can simply use the Transform component to get the position of the gameobject as a Vector3.

Vector3 gameObjectPosition = gameObject.transform.position;

Entity Loop


Now that we know how to get a GameObject's position, and what GameObject is our player, we can start writing our ESP. Inside of the OnGui() function we are putting our Entity Loop, which is a foreach loop that finds loaded objects of the type OnlinePlayer in the scene.

void OnGUI() 
{
  foreach (OnlinePlayer player in FindObjectsOfType(typeof(OnlinePlayer)) as OnlinePlayer[])
  {
  

  }
}

From here we can implement the player position, but before we do so we need to distinguish the difference between the pivot point of a gameObject and the origin point.

Pivot Point and Origin Point


In Unity, when you are getting the transform.position of a gameObject, you are getting the location of the pivot point, not the location of the origin point. What is the difference, and why does this matter?

As you can see above to the left, the pivot point is in the middle of the player gameObject on the Y (up/down) axis; with the player model being 2 Units tall, the pivot point is at Y:1. This causes issues once we start rendering our ESP, because we want the ESP box to start at the bottom of the player and end at the head. So to fix this we need to offset the player position on the Y axis to get it to be at where the origin point should be. Some games will fix their pivot points and make them set to the feet of the player, but more often than not, you will find that the pivot point is in the center of the player, not at the origin.

Player Position inside Entity Loop and Player Height


Now that you understand the pivot point dilemma, we can add onto our entity loop.

Vector3 pivotPos = player.transform.position; //Pivot point NOT at the origin, at the center
Vector3 playerFootPos; playerFootPos.x = pivotPos.x; playerFootPos.z = pivotPos.z; playerFootPos.y = pivotPos.y - 2f; //At the feet
Vector3 playerHeadPos; playerHeadPos.x = pivotPos.x; playerHeadPos.z = pivotPos.z; playerHeadPos.y = pivotPos.y + 2f; //At the head

In the pivotPos Vector3 we are setting it to the pivot position (gameObject.transform.position), and using that to get the playerFootPos / origin position by offsetting the pivotPos by -2f on the Y Axis (this WILL vary depending on the height of the player model in YOUR game, but for Muck, 2 works for me.) We are then doing the same for the playerHeadPos but instead of subtracting to get the feet, we are adding to the pivot position to get the head position. The Image below should visualize what is being offset, with the total height being roughly 4 Units, and from the pivot point down or up is 2 units.

Offsetting

WorldToScreen


A WorldToScreen function is used for converting in-game coordinates (X,Y,Z) to screen coordinates (X,Y). In memory based ESPs, you need to get the viewmatrix, and use that in the WorldToScreen function. Fortunately, Unity has a WorldToScreenPoint function that allows you to get the screenpoint of a Vector3 from a Camera component.

Camera.main.WorldToScreenPoint(Vector3 pos);

Time to implement it!

Inside our Entity Loop, under the player position code we wrote previously, we will create two Vector3's, that will be getting the screen position of the head and foot positions.

Vector3 w2s_footpos = Camera.main.WorldToScreenPoint(playerFootPos);
Vector3 w2s_headpos = Camera.main.WorldToScreenPoint(playerHeadPos);

Rendering


To render our ESP, we need to add the Render.cs class to our project, provided in the source. This will allow us to simply draw lines, boxes, and text on the screen (the functions simplify Unity's GUI functions).

We will now create a new function called DrawBoxESP() that we can call to draw the box esp from the OnGUI() function. We need to input our screen position Vector3s for our head and foot, and we will also include a Color.

public void DrawBoxESP(Vector3 footpos, Vector3 headpos, Color color)
{

}

Inside our newly created function we will create three floats. Height is for the height of our player, width offset is the width of our player, and width is the width of the esp box.

float height = headpos.y - footpos.y;
float widthOffset = 2f;
float width = height / widthOffset;

Now we can call DrawBox() and DrawLine() from our Render class to draw our ESP Box, and (optional) Snapline.

//ESP BOX
Render.DrawBox(footpos.x - (width / 2), (float)Screen.height - footpos.y - height, width, height, color, 2f);

//Snapline
Render.DrawLine(new Vector2((float)(Screen.width / 2), (float)(Screen.height / 2)), new Vector2(footpos.x, (float)Screen.height - footpos.y), color, 2f);

To change the snapline from snapping from the center of the screen to the bottom, you can change (float)(Screen.height / 2)) to (float)(Screen.height - 1)). Other than that, you can change the thickness of the Box and Line by changing the last variable which is currently at 2f.

Now we are finished with our Drawing function! Time to call it in the entity loop and we will be done!

Returning to our Entity Loop, below the w2s_footpos and w2s_headpos Vector3s, we will check that the esp box is not being drawn off screen, and then calling the DrawBoxESP() function.

if (w2s_footpos.z > 0f)
{
    DrawBoxESP(w2s_footpos, w2s_headpos, Color.red);
}

Conclusion


Finally we are finished with the ESP, build it, use your favorite mono injector (Class Name is: Universal_Unity_ESP, not Universal-Unity-ESP) and you have yourself a Universal Unity ESP.

muckESP