Add and Select Game View Resolution Programatically

How can I add and select resolution programmatically in Game View without Free Aspect. (I Need editor Script )

1-) I want to add new resolution

2-) Select this resolution

There you go, pretty straight forward :slight_smile:

using System;
using UnityEditor;
using UnityEngine;

public static class Utils
{
    public enum GameViewSizeType
    {
        AspectRatio, FixedResolution
    }

    [MenuItem("Test/AddSize")]
    public static void AddTestSize()
    {
        AddCustomSize(GameViewSizeType.AspectRatio, GameViewSizeGroupType.Standalone, 123, 456, "Test size");
    }

    public static void AddCustomSize(GameViewSizeType viewSizeType, GameViewSizeGroupType sizeGroupType, int width, int height, string text)
    {
        // goal:
        // var group = ScriptableSingleton<GameViewSizes>.instance.GetGroup(sizeGroupType);
        // group.AddCustomSize(new GameViewSize(viewSizeType, width, height, text);

        var asm = typeof(Editor).Assembly;
        var sizesType = asm.GetType("UnityEditor.GameViewSizes");
        var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
        var instanceProp = singleType.GetProperty("instance");
        var getGroup = sizesType.GetMethod("GetGroup");
        var instance = instanceProp.GetValue(null, null);
        var group = getGroup.Invoke(instance, new object[] { (int)sizeGroupType });
        var addCustomSize = getGroup.ReturnType.GetMethod("AddCustomSize"); // or group.GetType().
        var gvsType = asm.GetType("UnityEditor.GameViewSize");
        var ctor = gvsType.GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(string) });
        var newSize = ctor.Invoke(new object[] { (int)viewSizeType, width, height, text });
        addCustomSize.Invoke(group, new object[] { newSize });
    }
}

[EDIT] Here’s a version that performing size queries and setting the current size as per Mr Naphier request in the comments.

 using System;
 using System.Reflection;
 using UnityEditor;
 using UnityEngine;

 public static class GameViewUtils
 {
     static object gameViewSizesInstance;
     static MethodInfo getGroup;

     static GameViewUtils()
     {
         // gameViewSizesInstance  = ScriptableSingleton<GameViewSizes>.instance;
         var sizesType = typeof(Editor).Assembly.GetType("UnityEditor.GameViewSizes");
         var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
         var instanceProp = singleType.GetProperty("instance");
         getGroup = sizesType.GetMethod("GetGroup");
         gameViewSizesInstance = instanceProp.GetValue(null, null);
     }

     public enum GameViewSizeType
     {
         AspectRatio, FixedResolution
     }

     [MenuItem("Test/AddSize")]
     public static void AddTestSize()
     {
         AddCustomSize(GameViewSizeType.AspectRatio, GameViewSizeGroupType.Standalone, 123, 456, "Test size");
     }

     [MenuItem("Test/SizeTextQuery")]
     public static void SizeTextQueryTest()
     {
         Debug.Log(SizeExists(GameViewSizeGroupType.Standalone, "Test size"));
     }

     [MenuItem("Test/Query16:9Test")]
     public static void WidescreenQueryTest()
     {
         Debug.Log(SizeExists(GameViewSizeGroupType.Standalone, "16:9"));
     }

     [MenuItem("Test/Set16:9")]
     public static void SetWidescreenTest()
     {
         SetSize(FindSize(GameViewSizeGroupType.Standalone, "16:9"));
     }

     [MenuItem("Test/SetTestSize")]
     public static void SetTestSize()
     {
         int idx = FindSize(GameViewSizeGroupType.Standalone, 123, 456);
         if (idx != -1)
             SetSize(idx);
     }

     public static void SetSize(int index)
     {
         var gvWndType = typeof(Editor).Assembly.GetType("UnityEditor.GameView");
         var selectedSizeIndexProp = gvWndType.GetProperty("selectedSizeIndex",
                 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
         var gvWnd = EditorWindow.GetWindow(gvWndType);
         selectedSizeIndexProp.SetValue(gvWnd, index, null);
     }

     [MenuItem("Test/SizeDimensionsQuery")]
     public static void SizeDimensionsQueryTest()
     {
         Debug.Log(SizeExists(GameViewSizeGroupType.Standalone, 123, 456));
     }

     public static void AddCustomSize(GameViewSizeType viewSizeType, GameViewSizeGroupType sizeGroupType, int width, int height, string text)
     {
         // GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupTyge);
         // group.AddCustomSize(new GameViewSize(viewSizeType, width, height, text);

         var group = GetGroup(sizeGroupType);
         var addCustomSize = getGroup.ReturnType.GetMethod("AddCustomSize"); // or group.GetType().
         var gvsType = typeof(Editor).Assembly.GetType("UnityEditor.GameViewSize");
         var ctor = gvsType.GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(string) });
         var newSize = ctor.Invoke(new object[] { (int)viewSizeType, width, height, text });
         addCustomSize.Invoke(group, new object[] { newSize });
     }

     public static bool SizeExists(GameViewSizeGroupType sizeGroupType, string text)
     {
         return FindSize(sizeGroupType, text) != -1;
     }

     public static int FindSize(GameViewSizeGroupType sizeGroupType, string text)
     {
         // GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupType);
         // string[] texts = group.GetDisplayTexts();
         // for loop...

         var group = GetGroup(sizeGroupType);
         var getDisplayTexts = group.GetType().GetMethod("GetDisplayTexts");
         var displayTexts = getDisplayTexts.Invoke(group, null) as string[];
         for(int i = 0; i < displayTexts.Length; i++)
         {
             string display = displayTexts*;*

// the text we get is “Name (W:H)” if the size has a name, or just “W:H” e.g. 16:9
// so if we’re querying a custom size text we substring to only get the name
// You could see the outputs by just logging
// Debug.Log(display);
int pren = display.IndexOf(‘(’);
if (pren != -1)
display = display.Substring(0, pren-1); // -1 to remove the space that’s before the prens. This is very implementation-depdenent
if (display == text)
return i;
}
return -1;
}

public static bool SizeExists(GameViewSizeGroupType sizeGroupType, int width, int height)
{
return FindSize(sizeGroupType, width, height) != -1;
}

public static int FindSize(GameViewSizeGroupType sizeGroupType, int width, int height)
{
// goal:
// GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupType);
// int sizesCount = group.GetBuiltinCount() + group.GetCustomCount();
// iterate through the sizes via group.GetGameViewSize(int index)

var group = GetGroup(sizeGroupType);
var groupType = group.GetType();
var getBuiltinCount = groupType.GetMethod(“GetBuiltinCount”);
var getCustomCount = groupType.GetMethod(“GetCustomCount”);
int sizesCount = (int)getBuiltinCount.Invoke(group, null) + (int)getCustomCount.Invoke(group, null);
var getGameViewSize = groupType.GetMethod(“GetGameViewSize”);
var gvsType = getGameViewSize.ReturnType;
var widthProp = gvsType.GetProperty(“width”);
var heightProp = gvsType.GetProperty(“height”);
var indexValue = new object[1];
for(int i = 0; i < sizesCount; i++)
{
indexValue[0] = i;
var size = getGameViewSize.Invoke(group, indexValue);
int sizeWidth = (int)widthProp.GetValue(size, null);
int sizeHeight = (int)heightProp.GetValue(size, null);
if (sizeWidth == width && sizeHeight == height)
return i;
}
return -1;
}

static object GetGroup(GameViewSizeGroupType type)
{
return getGroup.Invoke(gameViewSizesInstance, new object[] { (int)type });
}
}
[MenuItem(“Test/LogCurrentGroupType”)]
public static void LogCurrentGroupType()
{
Debug.Log(GetCurrentGroupType());
}
public static GameViewSizeGroupType GetCurrentGroupType()
{
var getCurrentGroupTypeProp = gameViewSizesInstance.GetType().GetProperty(“currentGroupType”);
return (GameViewSizeGroupType)(int)getCurrentGroupTypeProp.GetValue(gameViewSizesInstance, null);
}

After v5.4 (zoom added) you will have issues with Canvas size scaler.
To do it propperly you must call other method attached on every element from size dropdown list called “SizeSelectionCallback”


public static void SetSize(int index)
{
     var gvWndType = typeof(Editor).Assembly.GetType("UnityEditor.GameView");
                 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
     var gvWnd = EditorWindow.GetWindow(gvWndType);
     var SizeSelectionCallback = gvWndType.GetMethod("SizeSelectionCallback",
                 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
      SizeSelectionCallback.Invoke(gvWnd, new object[] {index,null});
}

Just call that method from your editor script and give proper index.
(Sorry about my bad english).

just find this post…
first of all realy good script, but i’ve discovered a problem. adding new resolutions works just fine but when i close the project and open it up again the added resolutions are gone :frowning:
what am i doing wrong?

Hi the AddCustomSize method did not work (anymore) in Unity 2019.4. I had to change it to the following method taken from https://forum.unity.com/threads/add-game-view-resolution-programatically-old-solution-doesnt-work.860563/

    public static void AddCustomSize(GameViewSizeType viewSizeType, GameViewSizeGroupType sizeGroupType, int width, int height, string text)
    {
        var group = GetGroup(sizeGroupType);
        var addCustomSize = getGroup.ReturnType.GetMethod("AddCustomSize"); // or group.GetType().
        var gvsType = typeof(Editor).Assembly.GetType("UnityEditor.GameViewSize");
        string assemblyName = "UnityEditor.dll";
        Assembly assembly = Assembly.Load(assemblyName);
        Type gameViewSize = assembly.GetType("UnityEditor.GameViewSize");
        Type gameViewSizeType = assembly.GetType("UnityEditor.GameViewSizeType");
        ConstructorInfo ctor = gameViewSize.GetConstructor(new Type[]
        {
gameViewSizeType,
typeof(int),
typeof(int),
typeof(string)
        });
        var newSize = ctor.Invoke(new object[] { (int)viewSizeType, width, height, text });
        addCustomSize.Invoke(group, new object[] { newSize });
    }

I’m making this into keyboard shortcut version.

But without the adding custom resolution part. Because why bother do it via script while you can do it easily on GUI.

ALT+1 = 1280x720 (not added by default, you have to add it manually to work)
ALT+2 = 1920x1080
ALT+3 = 2560x1440

alt text

It is global shortcut key, and will be shown in “Edit > Shortcuts” menu.

To change the resolution the key is taking, you must modify the hard code.