Files
RaindropViewer/Assets/ThirdParty/NotchSolution/Editor/Simulator/GameViewResolution.cs
T

295 lines
10 KiB
C#

using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace E7.NotchSolution.Editor
{
public static class GameViewResolution
{
private const string TEMPORARY_RESOLUTION_LABEL = "Notch Simulator Device";
private const string PREVIOUS_RESOLUTION_PREF = "NotchSimPrevRes";
private static object m_customResolution;
private static int mockupRefreshTime;
private static object GameViewSizes =>
GetType("GameViewSizes").FetchProperty("instance").FetchProperty("currentGroup");
private static object FixedResolutionMode => Enum.Parse(GetType("GameViewSizeType"), "FixedResolution");
private static object AspectRatioMode => Enum.Parse(GetType("GameViewSizeType"), "AspectRatio");
private static object CustomResolution
{
get
{
if (m_customResolution != null)
{
if ((int) GameViewSizes.CallMethod("IndexOf", m_customResolution) < 0)
{
m_customResolution = null;
}
}
else
{
var totalSizeCount = (int) GameViewSizes.CallMethod("GetTotalCount");
var builtinSizeCount = (int) GameViewSizes.CallMethod("GetBuiltinCount");
for (var i = totalSizeCount - 1; i >= builtinSizeCount; i--)
{
var size = GameViewSizes.CallMethod("GetGameViewSize", i);
if ((string) size.FetchProperty("baseText") == TEMPORARY_RESOLUTION_LABEL)
{
m_customResolution = size;
break;
}
}
}
return m_customResolution;
}
set => m_customResolution = value;
}
private static int CustomResolutionIndex => m_customResolution == null
? -1
: (int) GameViewSizes.CallMethod("IndexOf", m_customResolution) +
(int) GameViewSizes.CallMethod("GetBuiltinCount");
public static void SetResolution(int width, int height, bool aspectRatioMode)
{
var gameView = GetGameView();
if (!gameView)
{
if (!NotchSolutionUtilityEditor.UnityDeviceSimulatorActive)
{
var sceneView = SceneView.lastActiveSceneView
? SceneView.lastActiveSceneView
: SceneView.currentDrawingSceneView;
if (sceneView)
{
sceneView.CallMethod("SetMainPlayModeViewSize", new Vector2(width, height));
RefreshMockups();
}
}
return;
}
var customResolution = CustomResolution;
if (customResolution != null)
{
var isModified = false;
if (customResolution.FetchProperty("sizeType").Equals(AspectRatioMode) != aspectRatioMode)
{
customResolution.ModifyProperty("sizeType",
aspectRatioMode ? AspectRatioMode : FixedResolutionMode);
isModified = true;
}
if ((int) customResolution.FetchProperty("width") != width)
{
customResolution.ModifyProperty("width", width);
isModified = true;
}
if ((int) customResolution.FetchProperty("height") != height)
{
customResolution.ModifyProperty("height", height);
isModified = true;
}
if (!isModified)
{
return;
}
if (CustomResolutionIndex == (int) gameView.FetchProperty("selectedSizeIndex"))
{
ZoomOutGameView();
RefreshMockups();
return;
}
}
else
{
CustomResolution = customResolution = GetType("GameViewSize")
.CreateInstance(aspectRatioMode ? AspectRatioMode : FixedResolutionMode, width, height,
TEMPORARY_RESOLUTION_LABEL);
GameViewSizes.CallMethod("AddCustomSize", customResolution);
}
PlayerPrefs.SetInt(PREVIOUS_RESOLUTION_PREF, (int) gameView.FetchProperty("selectedSizeIndex"));
gameView.CallMethod("SizeSelectionCallback", CustomResolutionIndex, null);
ZoomOutGameView();
RefreshMockups();
}
public static void ClearResolution()
{
if (CustomResolution != null)
{
var gameView = GetGameView();
var customResolutionActive =
gameView && CustomResolutionIndex == (int) gameView.FetchProperty("selectedSizeIndex");
GameViewSizes.CallMethod("RemoveCustomSize", CustomResolutionIndex);
CustomResolution = null;
if (customResolutionActive)
{
gameView.CallMethod("SizeSelectionCallback",
Mathf.Clamp(PlayerPrefs.GetInt(PREVIOUS_RESOLUTION_PREF), 0,
(int) GameViewSizes.CallMethod("GetTotalCount") - 1), null);
ZoomOutGameView();
RefreshMockups();
}
}
}
private static EditorWindow GetGameView()
{
var windows = Resources.FindObjectsOfTypeAll(GetType("GameView"));
return windows.Length > 0 ? (EditorWindow) windows[0] : null;
}
private static void ZoomOutGameView()
{
var gameView = GetGameView();
// Find the currently active tab on Game view's panel
var activeTab = gameView.FetchField("m_Parent")?.FetchProperty("actualView") as EditorWindow;
gameView.Focus();
gameView.CallMethod("UpdateZoomAreaAndParent");
gameView.CallMethod("SnapZoom", (float) gameView.FetchProperty("minScale"));
// Restore the active tab
if (activeTab && activeTab != gameView)
{
activeTab.Focus();
}
}
private static void RefreshMockups()
{
// Sometimes we need to respawn the mockups after a couple of frames in order to synchronize the mockups
// with the new game view resolution
if (!NotchSimulator.IsOpen)
{
mockupRefreshTime = 2;
EditorApplication.update -= RefreshMockupsInternal;
EditorApplication.update += RefreshMockupsInternal;
}
}
private static void RefreshMockupsInternal()
{
if (--mockupRefreshTime <= 0)
{
EditorApplication.update -= RefreshMockupsInternal;
NotchSimulator.RespawnMockup();
}
}
#region Reflection Functions
private static Type GetType(string type)
{
return typeof(EditorWindow).Assembly.GetType("UnityEditor." + type);
}
private static object FetchField(this Type type, string field)
{
return type.GetFieldRecursive(field, true).GetValue(null);
}
private static object FetchField(this object obj, string field)
{
return obj.GetType().GetFieldRecursive(field, false).GetValue(obj);
}
private static object FetchProperty(this Type type, string property)
{
return type.GetPropertyRecursive(property, true).GetValue(null, null);
}
private static object FetchProperty(this object obj, string property)
{
return obj.GetType().GetPropertyRecursive(property, false).GetValue(obj, null);
}
private static void ModifyProperty(this object obj, string property, object value)
{
obj.GetType().GetPropertyRecursive(property, false).SetValue(obj, value, null);
}
private static object CallMethod(this object obj, string method, params object[] parameters)
{
return obj.GetType().GetMethod(method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(obj, parameters);
}
private static object CreateInstance(this Type type, params object[] parameters)
{
Type[] parameterTypes;
if (parameters == null)
{
parameterTypes = null;
}
else
{
parameterTypes = new Type[parameters.Length];
for (var i = 0; i < parameters.Length; i++)
{
parameterTypes[i] = parameters[i].GetType();
}
}
return type.GetConstructor(parameterTypes).Invoke(parameters);
}
private static FieldInfo GetFieldRecursive(this Type type, string field, bool isStatic)
{
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly |
(isStatic ? BindingFlags.Static : BindingFlags.Instance);
do
{
var fieldInfo = type.GetField(field, flags);
if (fieldInfo != null)
{
return fieldInfo;
}
type = type.BaseType;
} while (type != null);
return null;
}
private static PropertyInfo GetPropertyRecursive(this Type type, string property, bool isStatic)
{
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly |
(isStatic ? BindingFlags.Static : BindingFlags.Instance);
do
{
var propertyInfo = type.GetProperty(property, flags);
if (propertyInfo != null)
{
return propertyInfo;
}
type = type.BaseType;
} while (type != null);
return null;
}
#endregion
}
}