Beginners Guide To Modding

#1



















So let's say you want to mod Besiege.
But you don't know anything about coding.

Don't worry, neither do I! :D

I am learning, and I am getting the basic, basic stuff, and to those of you out there who want to get the basics, follow this tutorial.

Setting up the workspace:
[SPOIL]
First of all you need something to code with! And no, Notepad saving as .dll won't work xD

Make sure you download Visual Studio Community 2015: https://www.visualstudio.com/

Then go here and make sure to follow all the instructions very carefully!

Workspace is done! :)
[/SPOIL]




Starting your project:
So now that you opened Visual Studio (You didn't? Do it.), go to the top left, "New", "Project", "Visual C#", "Besiege" and choose "Complete Besiege Mod" or "Minimal Besiege Mod".

It should show you this code if you choose "Complete Besiege Mods". spaar included a lot of comments for help, so thanks to him! (if it doesn't, click on Mod.cs to the right of Visual Studio):

[SPOIL]
Code:
[COLOR=#00FFFF]using System;
using spaar.ModLoader;
using UnityEngine;

namespace YourNamespace
{

    [/COLOR][COLOR=#00FF00]// If you need documentation about any of these values or the mod loader
    // in general, take a look at https://spaar.github.io/besiege-modloader.[/COLOR]

[COLOR=#00FFFF]public class YourMod : Mod
    {
        public override string Name { get; } = "<placeholder>";
        public override string DisplayName { get; } = "<placeholder>";
        public override string Author { get; } = "<placeholder>";
        public override Version Version { get; } = new Version(1, 0, 0, 0);

        [/COLOR][COLOR=#00FF00]// You don't need to override this, if you leavie it out it will default
        // to an empty string.[/COLOR]
[COLOR=#00FFFF]  public override string VersionExtra { get; } = "";

        [/COLOR][COLOR=#00FF00]// You don't need to override this, if you leave it out it will default
        // to the current version.[/COLOR]
[COLOR=#00FFFF]  public override string BesiegeVersion { get; } = "v0.11";

        [/COLOR][COLOR=#00FF00]// You don't need to override this, if you leave it out it will default
        // to false.[/COLOR]
[COLOR=#00FFFF]  public override bool CanBeUnloaded { get; } = false;

        /[/COLOR][COLOR=#00FF00]/ You don't need to override this, if you leave it out it will default
        // to false.[/COLOR]
[COLOR=#00FFFF]  public override bool Preload { get; } = false;


        public override void OnLoad()
        {
            [/COLOR][COLOR=#00FF00]// Your initialization code here[/COLOR]
[COLOR=#00FFFF]  }

        public override void OnUnload()
        {
            /[/COLOR][COLOR=#00FF00]/ Your code here
            // e.g. save configuration, destroy your objects if CanBeUnloaded is true etc[/COLOR]
[COLOR=#00FFFF]  }
    }
}[/COLOR]
After public override bool CanBeUnloaded { get { return true; } } you put public GameObject temp;


Start by putting this in OnLoad():
Code:
[COLOR=#00FFFF]GameObject temp = new GameObject();
            temp.AddComponent<YourClass>();
            GameObject.DontDestroyOnLoad(temp);[/COLOR]
And in OnUnload() you put
Code:
[COLOR=#00FFFF]GameObject.Destroy(temp);[/COLOR]
And now that's that done.

Now create a class that inherits MonoBehaviour.
Like this:

Code:
[COLOR=#00FFFF]public class YourClass : MonoBehaviour
{
}[/COLOR]
YourClass can be named what you want, as long as you also rename it in temp.AddComponent&lt;YourClass&gt;();

Now, create an Update() inside your newly-created class and that's where you are gonna put all the fun stuff!

If you followed the guide correctly, you should have this:

Code:
[COLOR=#00FFFF]using System;
using spaar.ModLoader;
using UnityEngine;

namespace ModdingGuide
{
    public class YourMod : Mod
    {
        public override string Name { get; } = "<placeholder>";
        public override string DisplayName { get; } = "<placeholder>";
        public override string Author { get; } = "<placeholder>";
        public override Version Version { get; } = new Version(1, 0, 0, 0);
        public override string VersionExtra { get; } = "";
        public override string BesiegeVersion { get; } = "v0.11";
        public override bool CanBeUnloaded { get; } = false;
        public override bool Preload { get; } = false;
        public GameObject temp;


        public override void OnLoad()
        {
            temp = new GameObject();
            temp.AddComponent<YourClass>();
            GameObject.DontDestroyOnLoad(temp);
        }

        public override void OnUnload()
        {
            GameObject.Destroy(temp);
        }
    }

    public class YourClass : MonoBehaviour
    {
        public void Update()
        {

        }
    }
}[/COLOR]
Now on to the fun stuff! :D
[/SPOIL]

Inside the Update(), the possiblities are endless:

Output text to the console (Ctrl+K).
[SPOIL]
This is definetly the easiest thing.
Code:
[COLOR=#00FFFF]Debug.Log("Your test Debug.");[/COLOR]
That would output "Your test Debug." to the console every frame, since it's in Update.
[/SPOIL]

Checking for inputs (If I press a specific key in my keyboard).
[SPOIL]
Imagine I want my code to know when I press the key "O" in my keyboard. I do
Code:
[COLOR=#00FFFF]if (Input.GetKeyDown(KeyCode.O))
{
}[/COLOR]
And if i want my code to know if i hold the "O" key in my keyboard, I do
Code:
[COLOR=#00FFFF]if (Input.GetKey(KeyCode.O))[/COLOR]
[COLOR=#00FFFF]{[/COLOR]
[COLOR=#00FFFF]}[/COLOR]
[/SPOIL]

Checking if a Starting Block is currently "there".
[SPOIL]
This is one of the first (if not the first) things I learned. I didn't understand a bit of what it did at first, don't worry.

In the Update(), do
GameObject startingBlock;

And then, to actually check if it is "there", do:
Code:
[COLOR=#00FFFF]if ((startingBlock = GameObject.Find("bgeL0")) == null)
            {
                startingBlock = GameObject.Find("StartingBlock");
            }
            if (startingBlock == null)
                return;[/COLOR]
Keep in mind this is only necessary if your mod revolves around the Starting Block (or the machine in general, but there are other ways to check for that).
This "halts" the mod while the Starting Block isnt present. As soon as the code detects it, the mod will "activate".


[/SPOIL]

Do stuff with the machine.
[SPOIL]
The machine while building is
Code:
[COLOR=#00FFFF]Game.AddPiece.machineParent[/COLOR]
And while simulating it's

Code:
[COLOR=#00FFFF]Game.AddPiece.activeInstance[/COLOR]
[/SPOIL]

Make stuff huuuuge! Or small if you want.
[SPOIL]
There's a very simple part of code that lets you resize stuff.

In my Machine Resizing Mod, i simply do this to make it bigger:

Code:
[COLOR=#00FFFF]Game.AddPiece.machineParent.localScale *= 1.05f[/COLOR]
That line of code scales the machine by 0.5 of it's current size, on every axis.
But what if you want to scale only, let's say, the "y" axis?
Simple.

Code:
[COLOR=#00FFFF]Game.AddPiece.machineParent.localScale[/COLOR][SIZE=16px][SIZE=12px][COLOR=#00FFFF].y *= 1.05f[/COLOR][/SIZE][/SIZE]
Not that hard, uh guys? :D
[/SPOIL]

Add stuff. To blocks. Sliders and stuff.
[SPOIL]
Remember my Starting Block+ mod? I changed some parameters of the Starting Block!

Personally, I changed the parameters in MyBlockInfo().
MyBlockInfo() is one of the Starting Block's components. Because GameObjects have components.

To get a component you do

Code:
[COLOR=#00FFFF]foreach (ComponentYouWant b in FindObjectsOfType<ComponentYouWant>())
{
}[/COLOR]
In my mod i cover every aspect. I hope you can understand by looking at the code!
Code:
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().twoButtons = true; [/COLOR][COLOR=#00FF00]//Makes 2 keys[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().canControl = true; [/COLOR][COLOR=#00FF00]//Allows the block to have keys[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().key1 = "a"; [/COLOR][COLOR=#00FF00]//Defines the default key1[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().key2 = "b"; [/COLOR][COLOR=#00FF00]//Defines the default key2[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().key1Name = "key1"; [/COLOR][COLOR=#00FF00]//Defines the key1's name[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().key2Name = "key2"; [/COLOR][COLOR=#00FF00]//Defines the key2's name[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().slider = true; [/COLOR][COLOR=#00FF00]//Creates a slider[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().sliderName = "YourSliderName"; [/COLOR][COLOR=#00FF00]//Defines the slider's name[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().sliderValue = 0; [/COLOR][COLOR=#00FF00]//Defines the default slider value[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().sliderMin = 0; [/COLOR][COLOR=#00FF00]//Defines the minimum slider value[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().sliderMax = 100; [/COLOR][COLOR=#00FF00]//Defines the maximum slider value[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().canToggle = true; [/COLOR][COLOR=#00FF00]//Creates a toggle[/COLOR]
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().toggleModeName = "YourToggleName"; [/COLOR][COLOR=#00FF00]//Defines the toggle's name[/COLOR]
Did you get what all of those did? Great. But what if you want something to happen when a value/state changes?
That is done by a very simple if statement.

What if I want something to happen when i enable my toggle (a toggle is, for example, "Hold To Shoot")? I do:

Code:
[COLOR=#00FFFF]if (b.GetComponent<MyBlockInfo>().toggleModeEnabled == true)
{
}  [/COLOR]
What about if I want something to happen when I press key1 or key2 (they keys you can change with the wrench menu thingy)? I use the Input checks that we covered earlier:
Code:
[COLOR=#00FFFF]if (Input.GetKeyDown(b.GetComponent<MyBlockInfo>().key1))
{
}[/COLOR]
Or:
Code:
[COLOR=#00FFFF]if (Input.GetKeyDown(b.GetComponent<MyBlockInfo>().key1))
{
}[/COLOR]
Toggles and Keys are covered. What about a slider?
The slider is a bit different. You can either use it to lower/raise the quantity/amount of something, or you can have stuff happen at specific values.

For example, the Self-Destruct radius in the SB+ mod was very simple.
I defined a GameObject temp like that:

Code:
[COLOR=#00FFFF]GameObject temp = (GameObject)GameObject.Instantiate(FindObjectOfType<AddPiece>().blockTypes[23].gameObject);[/COLOR]
That simply instantiates, or "spawns" a bomb. Bomb ID is 23, hence the [23].

Now remember that earlier we used a foreach to get the component and we assigned slider to true?
So now it's defined as b. Don't remember? Go up and look at the foreach.


To change a value, you need something that can have a value (like a bomb radius, the water force, etc.).
You can do this:

Code:
[COLOR=#00FFFF]yourGameObject.GetComponent<YourComponent>().yourSingle = 1 + b.GetComponent<MyBlockInfo>().sliderValue;[/COLOR]
Keep in mind that yourGameObject, YourComponent and yourSingle have to be actual things. They can't be just that. So if, for example, you can't modify a value from Component1 if it's only present in Component2.

Ok, that's covered. But what about something happening only when the slider has the value, for example, 20?

We have covered if statements already, and I hope you can figure this out by now.
Code:
[COLOR=#00FFFF]if ([/COLOR]
Code:
[COLOR=#00FFFF]b.GetComponent<MyBlockInfo>().sliderValue = 20[/COLOR][SIZE=16px][SIZE=12px][COLOR=#00FFFF])
{
}[/COLOR][/SIZE][/SIZE]
And there we go. Simple, right?
[/SPOIL]

Waiting.... be patient.
[SPOIL]
So, waiting is pretty boring, but it is pretty cool when modding!
And, for example, if you want a timer, you can use a coroutine, since it's probably the easiest way to make this kind of stuff.

Code:
[COLOR=#00FFFF]IEnumerator LetsWait(int seconds)
{
      yield return new WaitForSeconds(60);
}[/COLOR]
I used (60) but you would be able to change that.

When you wanted to call the coroutine (or "make it run"),
Code:
[COLOR=#00FFFF]StartCoroutine(LetsWait(60));[/COLOR]
And when you want it to end,
Code:
[COLOR=#00FFFF]StopCoroutine(LetsWait(60));[/COLOR]
[/SPOIL]

Make a cool-looking GUI!

[SPOIL]
I know you think that way. Every cool mod needs a GUI :p
And from my experience, I have learned that GUI's are not that difficult to make! They're probably one of the easiest things on this guide.

Right after the class that inherits MonoBehaviour, before
the Update(), write this:

Code:
[COLOR=#00FFFF]private int windowID = Util.GetWindowID();
private Rect windowRect = new Rect(100, 100, 175, 100);[/COLOR]
And that pretty much sets the base for the GUI. But OnGUI() and DoWindow(int id) are what actually make it possible for a GUI to look cool.

So OnGUI() makes the GUI actually visible on the screen. Do this:

Code:
[COLOR=#00FFFF]GUI.skin = ModGUI.Skin;
windowRect = GUI.Window(windowID, windowRect, DoWindow, "<GUI_Title>");[/COLOR]
Now on to DoWindow(int id):
Code:
[COLOR=#00FFFF]private void DoWindow(int id)
        {
            var textStyle = new GUIStyle(Elements.Labels.Title)
            {
                margin = { top = 10 },
                fontSize = 15
            };
            var buttonWidth = GUILayout.Width(110f);
            
                GUILayout.BeginVertical(); [/COLOR][COLOR=#00FF00]//Begins a vertical section of text and/or buttons[/COLOR]
[COLOR=#00FFFF]               GUILayout.Label("<YourText>", textStyle); [/COLOR][COLOR=#00FF00]//Makes text[/COLOR]
[COLOR=#00FFFF]               GUILayout.Label("", textStyle); [/COLOR][COLOR=#00FF00]//Makes a blank line[/COLOR]
[COLOR=#00FFFF]               GUILayout.Button("<YourButtonLabel>"); [/COLOR][COLOR=#00FF00]//Makes a button[/COLOR]
[COLOR=#00FFFF]               GUILayout.EndVertical(); [/COLOR][COLOR=#00FF00]//Ends the vertical section[/COLOR]

[COLOR=#00FFFF]           GUI.DragWindow(new Rect(0, 0, windowRect.width, GUI.skin.window.padding.top)); [/COLOR][COLOR=#00FF00]//Makes the GUI draggeable across the screen[/COLOR]
[COLOR=#00FFFF]       }[/COLOR]
That wasn't hard, was it?
But, if we have buttons, we need them to do something when we click them, right?
So, if you want a action for a button, remove the
GUILayout.Button("<YourButtonLabel>"); part and do it like this and add an if sentence for the button.
Not clear enough? Look at the example:

Code:
[COLOR=#00FFFF]private void DoWindow(int id)
        {
            var textStyle = new GUIStyle(Elements.Labels.Title)
            {
                margin = { top = 10 },
                fontSize = 15
            };
            var buttonWidth = GUILayout.Width(110f);

            if (GUILayout.Button("<YourButtonLabel>")) [/COLOR][COLOR=#00FF00]//Makes a button and you can add code inside it that executes when you click the button[/COLOR]
[COLOR=#00FFFF]           {
                
            }

                GUILayout.BeginVertical(); [/COLOR][COLOR=#00FF00]//Begins a vertical section of text and/or buttons[/COLOR]
[COLOR=#00FFFF]               GUILayout.Label("<YourText>", textStyle); [/COLOR][COLOR=#00FF00]//Makes text[/COLOR]
[COLOR=#00FFFF]               GUILayout.Label("", textStyle); [/COLOR][COLOR=#00FF00]//Makes a blank line[/COLOR]
[COLOR=#00FFFF]               GUILayout.EndVertical(); [/COLOR][COLOR=#00FF00]//Ends the vertical section[/COLOR]


[COLOR=#00FFFF]           GUI.DragWindow(new Rect(0, 0, windowRect.width, GUI.skin.window.padding.top)); //Makes the GUI draggeable across the screen
        }[/COLOR]
So you're probaly seen the Editor+ mod my TesseractCat.
He has this button that toggles the GUI between open/closed.
And that's pretty neat but how do we make one?
With our example from above, and an additional string.


Remember where you added the windowRect and the windowID thingies?
Add this there:

Code:
[COLOR=#00FFFF]private string guiText = "Open GUI";
private bool showGuide = false;[/COLOR]


So when you wanted to open the GUI by clicking the button, you would do this:

Change the windowRect to something smaller (the same windowRect you added at the beginning of this section):

Code:
[COLOR=#00FFFF]private Rect windowRect = new Rect(100, 100, 175, 100);[/COLOR]
Then you make the GUI have the label of guiText.
Code:
[COLOR=#00FFFF]if (GUILayout.Button(guiText))[/COLOR]
[SIZE=16px][SIZE=12px][COLOR=#00FFFF]{
}[/COLOR][/SIZE][/SIZE]
We want 2 things by now. A button that opens the GUI and displays "Open GUI" and when the GUI is open it displays "Close GUI" and closes the GUI on click.
So for that we use if and else, and we reassign our string when needed.

Code:
[COLOR=#00FFFF]if (GUILayout.Button(guiText))
            {
                showGuide = !showGuide;
                if (showGuide)
                {
                    guiText = "Close GUI";
                    windowRect.height = 300;
                    windowRect.width = 500;
                }
                else
                {
                    guiText = "Open GUI";
                    windowRect.height = 100;
                    windowRect.width = 175;
                }
            }[/COLOR]
And there we go!
GUI's aren't that hard, now, are they? :D


There is waaay more you can do with GUI's, I just don't know how to myself yet! :p
[/SPOIL]


Things you might find useful:
[SPOIL]
If you download the developer version of the Spaar's Modloader Beta, you can press Ctrl+O in-game to access the Object Explorer! It's very useful for modding since it lets you see a "code" perspective of stuff that's currently present in your game!
[/SPOIL]


Attached Files
 
#3
Wow! Great Job! I'm very tempted to give modding a try so this looks like the perfect intro to it. Cool! Also, I wasn't sure if it was possible on a mac but I see from vis/stu site that it is.
 

ITR

l̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ֍̫̜̥̭͖̱̟̟͉͙̜̰ͅl̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ
Staff member
#7
Voncrumb said:
Nice, but hmmm how do i make it into a .dll so that i can text it?
Ctrl+Shift+B
Then it should show something in the bottom thingy "Show output from "build"", and on the line above "========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========" it should say something like "[ProjectName] -> [Path]"
The path is were the .dll is saved
 
#9
ITR said:
Ctrl+Shift+B
Then it should show something in the bottom thingy "Show output from "build"", and on the line above "========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========" it should say something like "[ProjectName] -> [Path]"
The path is were the .dll is saved
Thanks time to create a hello world thing - baby steps
 
#11
The Gui part is a bit confusing could you make a over all example of an entire mod with out anything else expect for the Gui, because i have no idea where i am ment to put stuff
 
#16
Having problems with some of the first steps in the guide.

Here's my Mod.cs file, for line numbers.

Code:
using System;
using spaar.ModLoader;
using UnityEngine;

namespace tutorial {

  // If you need documentation about any of these values or the mod loader
  // in general, take a look at https://spaar.github.io/besiege-modloader.

  public class YourMod : Mod {
    public override string Name { get; } = "MyMod";
    public override string DisplayName { get; } = "MyMod";
    public override string Author { get; } = "K3TCHUP";
    public override Version Version { get; } = new Version(1, 0, 0);

    public override void OnLoad() {
      temp = new GameObject();
      temp.AddComponent<YourClass>();
      GameObject.DontDestroyOnLoad(temp);
    }

    public override void OnUnload() {
      GameObject.Destroy(temp);
    }

    public class YourClass : MonoBehavior {
        public void Update() {
            Debug.Log("Your test Debug.");
        }
    }
  }
}
I'm getting error's around at beginning, lines 11-14:

Code:
Invalid token '=' in class, struct, or interface member declaration
And also in the OnLoad() and OnUnload() functions about the use of the variable temp:

Code:
The name 'temp' does no exist in the current context
Also (yeah, I know, more) On line 26, it complains about "MonoBehavior" being used:

Code:
The type or namespace name 'MonoBehavior' could not be found (are you missing a using directive or an assembly reference?)
If I copy and paste the code you gave in, I get the same errors.

EDIT: Also, are all the colour codes in the guide's code snips intentional?
 
Last edited:

ITR

l̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ֍̫̜̥̭͖̱̟̟͉͙̜̰ͅl̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ
Staff member
#17
Code:
Invalid token '=' in class, struct, or interface member declaration
You're not using the newest version of VS maybe?
Code:
The type or namespace name 'MonoBehavior' could not be found (are you missing a using directive or an assembly reference?)
You have to reference UnityEngine.dll
 
#18
You have to reference UnityEngine.dll
Is that different from the third line?
Code:
using UnityEngine;
You're not using the newest version of VS maybe?
Currently using the latest stable release of VS2013 (Version 12.0.4062900 Update 5) with Microsoft .NET Framework Version 4.6.01586 .

It seems there is a Version 4.6.1 of the .NET Framework, so I'll try that.

EDIT: I have UnityEngine referenced (In the Solution Explorer window: Solution > tutorial > References > UnityEngine), with seemingly the correct file path set as the Path value:
Code:
C:\Program Files (x86)\Steam\steamapps\common\Besiege\Besiege_Data\Managed\UnityEngine.dll
EDIT 2: Google Drive of entire VS directory.
 
Last edited:

ITR

l̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ֍̫̜̥̭͖̱̟̟͉͙̜̰ͅl̺̤͈̘̰̺͉̳͉̖̝̱̻̠̦͈ͅ
Staff member
#19
Is that different from the third line?
Code:
using UnityEngine;


Currently using the latest stable release of VS2013 (Version 12.0.4062900 Update 5) with Microsoft .NET Framework Version 4.6.01586 .

It seems there is a Version 4.6.1 of the .NET Framework, so I'll try that.

EDIT: I have UnityEngine referenced (In the Solution Explorer window: Solution > tutorial > References > UnityEngine), with seemingly the correct file path set as the Path value:
Code:
C:\Program Files (x86)\Steam\steamapps\common\Besiege\Besiege_Data\Managed\UnityEngine.dll
EDIT 2: Google Drive of entire VS directory.
Nvm, it's because it's spelled MonoBehaviour, not MonoBehavior

Use VS2015
 
#20
Nvm, it's because it's spelled MonoBehaviour, not MonoBehavior
Fixed the spelling, also thanks to spaar's response in this thread, another problem was fixed, so now only the
Code:
Invalid token '=' in class, struct, or interface member declaration
error's remain.

Installing VS2015 at the moment, though it'll take a while because my connection is fairly bad.

EDIT: Using VS2015 did fix my problem, thank you very much!
 
Last edited:
Top