Ads keep us online. Without them, we wouldn't exist. We don't have paywalls or sell mods - we never will. But every month we have large bills and running ads is our only way to cover them. Please consider unblocking us. Thank you from GameBanana <3

Make your Codemod work on any platform (+Template)

A Tutorial for Baldi's Basics in Education and Learning

Members see zero ads. Membership is 100% free

Making your Codemod Cross-Compatible

Before 1.4.X, Codemods were pretty much always Cross-Compatible. However, with the introduction of Rewired in 1.4, this broke entirely. I'm going to show you, how to restore this Cross-Compatibility.

This Tutorial is long and can be quite confusing (especially due to how GameBanana messed up my formatting). I have a pre-made Cross-Compatible Template here (drive.google.com), you can use it if you want. But if you do use it, then please also credit me, because this took longer than it should've.

If you use this Tutorial for your mod, then create a backup first! This should be common knowledge by now, but i'll put this here just in case.



What you'll need

  • Baldi's Basics (Windows, Linux and macOS Version)
  • dnSpy

Preparing the files

  1. Extract the Baldi version of the system you are currently using (Windows in this example)
    (This could of course also be your prepared Mod, i'm just demonstrating this on a fresh version of Baldi's Basics)
    (Shown: Extracted files)
  2. Open the zip files of the systems that are NOT the system you are currently using and navigate to their respective Managed folder (the folder with the Assembly-CSharp.dll file in it).
    • Windows & Linux: BALDI_Data/Managed
    • macOS: BALDI.app/Contents/Resources/Data/Managed
  3. Here you will find Rewired_Windows.dll, Rewired_Linux.dll or Rewired_OSX.dll, depending on which zip you are currently in. Grab that and put it in the Managed folder of your current system, that you extracted before.
    (Shown: Result after putting all files together)

Adding Cross-Compatibility

  • Step 1: Open the Assembly-CSharp.dll file in dnSpy.
  • Step 2: Create the Cross-Compatibility library
    1. Right-Click somewhere inside the Assembly-CSharp explorer and choose Add Class (C#)...
    2. Put this CrossCompatibility Library in:
      using System;

      namespace CrossCompatibility {
      public class Cross_Windows {
      public object GetPlatformInitializer()
      {
      return Rewired.Utils.Platforms.Windows.Main.GetPlatformInitializer();
      }
      }

      public class Cross_Linux {
      public object GetPlatformInitializer()
      {
      return Rewired.Utils.Platforms.Linux.Main.GetPlatformInitializer();
      }
      }

      public class Cross_macOS {
      public object GetPlatformInitializer()
      {
      return Rewired.Utils.Platforms.OSX.Main.GetPlatformInitializer();
      }
      }
      }
      You'll see later, what these classes do.
    3. When you hit Compile now, you'll most likely see this or a similar error:

      To fix this, click on Add Assembly Reference in the bottom left of the text window

      Then select the Rewired_SystemNameHere.dll files you extracted earlier and hit Open
      (Shown: Selection in Add Assembly Window)

      Now you can hit Compile again and it should work.
    4. After compiling, just click on File -> Save Module... to save the dll file. This ensures, that we can use our new library.

  • Step 3: Adjusting Rewired for Cross-Compatibility
    1. Now we need to adjust two Rewired scripts.
      (Shown: Rewired scripts that need to be edited)

      We'll start with InputManager.
    2. In InputManager we only need to change the DetectPlatform() function. Replace it with:
      protected override void DetectPlatform()
      {
          this.scriptingBackend = ScriptingBackend.Mono;
          this.scriptingAPILevel = ScriptingAPILevel.Net20;
          this.editorPlatform = EditorPlatform.None;
          this.platform = Platform.Unknown;
          this.webplayerPlatform = WebplayerPlatform.None;
          this.isEditor = false;
          string deviceName = SystemInfo.deviceName ?? string.Empty;
          string deviceModel = SystemInfo.deviceModel ?? string.Empty;
          //### HERE STARTS THE PART WHERE THINGS ARE CHANGED
          //Am i running on Windows?
          if (Application.platform == RuntimePlatform.WindowsPlayer)
          {
              //Yes, set Platform to Windows.
              this.platform = Platform.Windows;
          }
          //Am i running on Linux?
          if (Application.platform == RuntimePlatform.LinuxPlayer)
          {
              //Yes, set Platform to Linux.
              this.platform = Platform.Linux;
          }
          //Am i running on macOS?
          if (Application.platform == RuntimePlatform.OSXPlayer)
          {
              //Yes, set Platform to macOS.
              this.platform = Platform.OSX;
          }
          //Am i running on Android?
          if (Application.platform == RuntimePlatform.Android)
          {
              //Yes, set Platform to Android.
              this.platform = Platform.Android;
              //Special Case: Is this Android device an OUYA?
              if (this.CheckDeviceName("OUYA", deviceName, deviceModel))
              {
                  //Yes, set Platform to OUYA.
                  this.platform = Platform.Ouya;
              }
              //Special Case: Is this Android device an Amazon Fire TV?
              else if (this.CheckDeviceName("Amazon AFT.*", deviceName, deviceModel))
              {
                  //Yes, set Platform to Amazon Fire TV.
                  this.platform = Platform.AmazonFireTV;
              }
              //Special Case: Is this Android device a razer Forge TV?
              else if (this.CheckDeviceName("razer Forge", deviceName, deviceModel))
              {
                  //Yes, set Platform to razer Forge TV.
                  this.platform = Platform.RazerForgeTV;
              }
          }
          //### HERE ENDS THE PART WHERE THINGS ARE CHANGED
          this.scriptingBackend = ScriptingBackend.Mono;
          this.scriptingAPILevel = ScriptingAPILevel.Net20Subset;
      }
      
      Hit Compile and that's it for InputManager.
    3. Now we can edit ExternalTools.
      First, add this to the other using directives:
      using CrossCompatibility;
    4. Add these two variables:
    5. private const int API_LEVEL_HONEYCOMB = 9;
      
      private const int API_LEVEL_KITKAT = 19;
    6. Replace the GetPlatformInitializer() function with this:
      public object GetPlatformInitializer()
      {
          //Am i running on Linux?
          if (Application.platform == RuntimePlatform.LinuxPlayer)
          {
              //Yes, return the Linux Platform Initializer
              return new Cross_Linux().GetPlatformInitializer();
          }
          //Am i running on macOS?
          if (Application.platform == RuntimePlatform.OSXPlayer)
          {
              //Yes, return the macOS Platform Initializer
              return new Cross_macOS().GetPlatformInitializer();
          }
          //Am i running on Windows?
      if (Application.platform == RuntimePlatform.WindowsPlayer) {
      //Yes, return the Windows Platform Initializer
      return new Cross_Windows().GetPlatformInitializer();
      } return null; }
    7. Replace the GetAndroidAPILevel() function with this:
    8. public int GetAndroidAPILevel()
      {
          if (Application.platform != RuntimePlatform.Android)
          {
              return -1;
          }
          int result;
          try
          {
              int num = 9;
              using (AndroidJavaClass androidJavaClass = new AndroidJavaClass("android.os.Build$VERSION"))
              {
                  num = androidJavaClass.GetStatic<int>("SDK_INT");
              }
              result = num;
          }
          catch
          {
              result = -1;
          }
          return result;
      }
    9. Replace the GetDeviceVIDPIDs(...) function with this:
    10. public void GetDeviceVIDPIDs(out List<int> vids, out List<int> pids)
      {
          vids = new List<int>();
          pids = new List<int>();
          if (Application.platform == RuntimePlatform.Android)
          {
              try
              {
                  if (this.GetAndroidAPILevel() >= 19)
                  {
                      AndroidJavaClass androidJavaClass = new AndroidJavaClass("android.view.InputDevice");
                      int[] array = null;
                      using (AndroidJavaObject androidJavaObject = androidJavaClass.CallStatic<AndroidJavaObject>("getDeviceIds", new object[0]))
                      {
                          if (androidJavaObject != null)
                          {
                              array = AndroidJNIHelper.ConvertFromJNIArray<int[]>(androidJavaObject.GetRawObject());
                          }
                      }
                      if (array != null)
                      {
                          for (int i = 0; i < array.Length; i++)
                          {
                              try
                              {
                                  using (AndroidJavaObject androidJavaObject2 = androidJavaClass.CallStatic<AndroidJavaObject>("getDevice", new object[]
                                  {
                                      array[i]
                                  }))
                                  {
                                      if (androidJavaObject2 != null)
                                      {
                                          vids.Add(androidJavaObject2.Call<int>("getVendorId", new object[0]));
                                          pids.Add(androidJavaObject2.Call<int>("getProductId", new object[0]));
                                      }
                                  }
                              }
                              catch
                              {
                              }
                          }
                      }
                  }
              }
              catch
              {
              }
          }
      }
    11. When you hit Compile now, you'll most likely see this or a similar error:

      To fix this, double-click on the error. This will bring you to the error location. Remove the text line, where the error is.
      (Shown: Line with the error, marked in red)

      Hit Compile and you're now done.
  • Step 4: Additional adjustments for Android compatibility
    1. Lastly we need to make some changes in the default (unnamed) namespace.

    2. In GameControllerScript.cs:
      • Add this function:
      • private void OnApplication_Pause/*Remove the underscore from the name, i had to add that because of GameBanana*/(bool pause)
        {
            if (!this.gamePaused)
            {
                this.PauseGame();
            }
        }
      • Replace this part of DeactivateLearningGame()
        public void DeactivateLearningGame(GameObject subject)
        {
            //Other code that doesn't need to be changed
            if (this.notebooks == 1 & !this.spoopMode)
            {
                this.quarter.SetActive(true);
                this.tutorBaldi.PlayOneShot(this.aud_Prize);
            }
            //Other code that doesn't need to be changed
        }
        
        With this:
        public void DeactivateLearningGame(GameObject subject)
        {
            //Other code that doesn't need to be changed
            if (this.notebooks == 1 & !this.spoopMode)
            {
                this.quarter.SetActive(true);
                if (InputTypeManager.usingTouch)
                {
                    this.tutorBaldi.PlayOneShot(this.aud_PrizeMobile);
                } else {
                    this.tutorBaldi.PlayOneShot(this.aud_Prize);
                }
            }
            //Other code that doesn't need to be changed
        }
        
    3. In JumpRopeScript.cs:
      • Add this to the end of the OnEnable() function:
        private void OnEnable()
        {
            //Other code that doesn't need to be changed
            if (InputTypeManager.usingTouch)
            {
                this.mobileIns.SetActive(true);
            }
            else
            {
                this.mobileIns.SetActive(false);
            }
        }
        
    4. In MathGameScript.cs:
      • Replace this part of the Start() function:
        private void Start()
        {
            //Other code that doesn't need to be changed
            if (this.gc.notebooks == 1)
            {
                this.QueueAudio(this.bal_intro);
                this.QueueAudio(this.bal_howto);
            }
            //Other code that doesn't need to be changed
        }
        
        With this:
        private void Start()
        {
            //Other code that doesn't need to be changed
            if (this.gc.notebooks == 1)
            {
                this.QueueAudio(this.bal_intro);
                if (!InputTypeManager.usingTouch)
                {
                    this.QueueAudio(this.bal_howto);
                }
            }
            //Other code that doesn't need to be changed
        }
        
    5. In MobileController.cs:
      • Replace the Start() function with this:
      • private void Start()
        {
            if (InputTypeManager.usingTouch)
            {
                this.ActivateMobileControls();
            } else {
                base.gameObject.SetActive(false);
            }
        }
        
    6. In PlatformSpecificMenu.cs:
      • Replace the Start() function with this:
      • private void Start()
        {
            if (InputTypeManager.usingTouch)
            {
                this.mobile.SetActive(true);
            } else {
                this.pC.SetActive(true);
            }
        }
        
    7. In UIController.cs:
      • Replace the OnEnable() function with this:
      • private void OnEnable()
        {
            if (InputTypeManager.usingTouch)
            {
                this.dummyButtonElse.Select();
            }
            else
            {
                this.dummyButtonPC.Select();
            }
            this.UpdateControllerType();
        }
        
      • Replace the SelectDummy() function with this:
      • private void SelectDummy()
        {
            if (InputTypeManager.usingTouch)
            {
                this.dummyButtonElse.Select();
            } else {
                this.dummyButtonPC.Select();
            }
        }
        
    8. In WarningScreenScript.cs:
      • Replace the Start() function with this:
        private void Start()
        {
            this.player = ReInput.players.GetPlayer(0);
            if (InputTypeManager.usingTouch)
            {
                Application.targetFrameRate = 60;
                Input.simulateMouseWithTouches = false;
            }
        }
        

Congratulations, now this Assembly-CSharp.dll file should work when placed in any version of the game!

Comments

Sign up to access this!

No comments yet

Embed

menu
Share banner
Image URL
HTML embed code
BB embed code
Markdown embed code

Credits

Author
Fasguy avatar 30Hz Studios Flag
Affiliation
30Hz Studios
Fasguy username pic Joined 1y ago
Offline
30Hz Studios Flag Affiliation: 30Hz Studios
2,076 points Ranked 20655th
12 medals 2 rare
  • Reached 50 subscribers Medal icon
  • Returned 1000 times Medal icon
  • Returned 100 times Medal icon
  • One month a member Medal icon
  • Reached 10 subscribers Medal icon
  • 6 months a member Medal icon

Submitter

Fasguy avatar
Fasguy username pic Joined 1y ago
Offline
30Hz Studios Flag Affiliation: 30Hz Studios
2,076 points Ranked 20655th
12 medals 2 rare
  • Reached 50 subscribers Medal icon
  • Returned 1000 times Medal icon
  • Returned 100 times Medal icon
  • One month a member Medal icon
  • Reached 10 subscribers Medal icon
  • 6 months a member Medal icon
Fasguy avatar
Fasguy
30Hz Studios Flag
Affiliation
30Hz Studios

Creator
Sign up to access this!
Sign up to access this!
Sign up to access this!

Game

Sign up to access this!

Category

Details

Difficulty Level
Advanced

Attributes

Share

  • Share on Reddit
  • Share on Twitter
  • Share on Facebook
  • favorite 3
  • remove_red_eye 730
  • access_time 28d
  • access_time 24d

More Other/Misc Tutorials