mirror of
https://github.com/originalnicodr/CinematicUnityExplorer.git
synced 2025-07-18 09:27:57 +08:00
Added advance setting to select target camera (#108)
* Added a dropdown to select the camera you want to target. Also improved rendering tweaks error handling. * Added settings to optionally render the target camera dropdown and to remember the selected target camera across sessions. Also renamed the CUE camera objects for standardization (and filtering) sake. * Refactored Preferred_Target_Camera into a path to the cam object to make it more robust. * Added missing config values type changes. * Refactor build guards by using reflection to cover all builds. * Replaced Array.IndexOf by a manual iteration because it wasn't working for some reason. Also polished some vertical spaces.
This commit is contained in:

committed by
GitHub

parent
388c9fbc29
commit
e3584654a6
@ -33,6 +33,7 @@ namespace UnityExplorer.Config
|
||||
public static ConfigElement<bool> Auto_Scale_UI;
|
||||
public static ConfigElement<bool> Reset_Camera_Transform;
|
||||
public static ConfigElement<float> Arrow_Size;
|
||||
public static ConfigElement<bool> Advanced_Freecam_Selection;
|
||||
|
||||
public static ConfigElement<KeyCode> Pause;
|
||||
public static ConfigElement<KeyCode> Frameskip;
|
||||
@ -63,6 +64,7 @@ namespace UnityExplorer.Config
|
||||
|
||||
public static ConfigElement<FreeCamPanel.FreeCameraType> Default_Freecam;
|
||||
public static ConfigElement<string> Custom_Components_To_Disable;
|
||||
public static ConfigElement<string> Preferred_Target_Camera;
|
||||
|
||||
// internal configs
|
||||
internal static InternalConfigHandler InternalHandler { get; private set; }
|
||||
@ -198,6 +200,10 @@ namespace UnityExplorer.Config
|
||||
"Cam Paths nodes and Lights Manager lights visualizers' arrow size (must be positive) (needs visualizer toggled to reflect changes).",
|
||||
1f);
|
||||
|
||||
Advanced_Freecam_Selection = new("Advanced Freecam Selection",
|
||||
"Enables certain advanced settings on the Freecam panel, in case the user can't get the freecam to work properly (requires game reset).",
|
||||
false);
|
||||
|
||||
Pause = new("Pause",
|
||||
"Toggle the pause of the game.",
|
||||
KeyCode.PageUp);
|
||||
@ -311,6 +317,11 @@ namespace UnityExplorer.Config
|
||||
Custom_Components_To_Disable = new("Custom components to disable",
|
||||
"List of custom components to disable when enabling the freecam (gets automatically updated when editing it from the freecam panel).",
|
||||
"");
|
||||
|
||||
Preferred_Target_Camera = new("Preferred Target Camera",
|
||||
"The camera that will be targeted by the freecam methods.\n" +
|
||||
"Only used when Advanced Freecam Selection is enabled.",
|
||||
"\\");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,9 @@ namespace UnityExplorer.Loader.Standalone
|
||||
public bool Reset_Camera_Transform;
|
||||
public FreeCamPanel.FreeCameraType Default_Freecam;
|
||||
public string Custom_Components_To_Disable;
|
||||
public string Preferred_Target_Camera;
|
||||
public float Arrow_Size = 1f;
|
||||
public bool Advanced_Freecam_Selection;
|
||||
|
||||
public KeyCode Pause;
|
||||
public KeyCode Frameskip;
|
||||
@ -90,7 +92,10 @@ namespace UnityExplorer.Loader.Standalone
|
||||
ConfigManager.Reset_Camera_Transform.Value = this.Reset_Camera_Transform;
|
||||
ConfigManager.Default_Freecam.Value = this.Default_Freecam;
|
||||
ConfigManager.Custom_Components_To_Disable.Value = this.Custom_Components_To_Disable;
|
||||
ConfigManager.Preferred_Target_Camera.Value = this.Preferred_Target_Camera;
|
||||
|
||||
ConfigManager.Arrow_Size.Value = this.Arrow_Size;
|
||||
ConfigManager.Advanced_Freecam_Selection.Value = this.Advanced_Freecam_Selection;
|
||||
|
||||
ConfigManager.Pause.Value = this.Pause;
|
||||
ConfigManager.Frameskip.Value = this.Frameskip;
|
||||
|
@ -37,7 +37,7 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
public override string Name => "Freecam";
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.Freecam;
|
||||
public override int MinWidth => 450;
|
||||
public override int MinWidth => 500;
|
||||
public override int MinHeight => 750;
|
||||
public override Vector2 DefaultAnchorMin => new(0.4f, 0.4f);
|
||||
public override Vector2 DefaultAnchorMax => new(0.6f, 0.6f);
|
||||
@ -68,6 +68,7 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
static ButtonRef startStopButton;
|
||||
public static Dropdown cameraTypeDropdown;
|
||||
internal static Dropdown targetCameraDropdown;
|
||||
internal static FreeCameraType currentCameraType;
|
||||
public static Toggle blockFreecamMovementToggle;
|
||||
public static Toggle blockGamesInputOnFreecamToggle;
|
||||
@ -103,14 +104,15 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
internal static void BeginFreecam()
|
||||
{
|
||||
inFreeCamMode = true;
|
||||
connector?.UpdateFreecamStatus(true);
|
||||
|
||||
previousMousePosition = IInputManager.MousePosition;
|
||||
|
||||
CacheMainCamera();
|
||||
SetupFreeCamera();
|
||||
|
||||
// Need to be done after CacheMainCamera to not trigger targetCameraDropdown onValueChanged
|
||||
inFreeCamMode = true;
|
||||
|
||||
inspectButton.GameObject.SetActive(true);
|
||||
|
||||
UpdateClippingPlanes();
|
||||
@ -119,9 +121,78 @@ namespace UnityExplorer.UI.Panels
|
||||
freecamCursorUnlocker.Enable();
|
||||
}
|
||||
|
||||
private static Camera[] GetAvailableCameras()
|
||||
{
|
||||
Camera[] cameras = {};
|
||||
try
|
||||
{
|
||||
cameras = Camera.allCameras;
|
||||
}
|
||||
// Some ILCPP games might not have Camera.allCameras available
|
||||
catch {
|
||||
cameras = RuntimeHelper.FindObjectsOfTypeAll<Camera>();
|
||||
}
|
||||
|
||||
return cameras.Where(c => c.name != "CUE Camera").ToArray();
|
||||
}
|
||||
|
||||
private static Camera GetTargetCamera()
|
||||
{
|
||||
if (!ConfigManager.Advanced_Freecam_Selection.Value && !targetCameraDropdown)
|
||||
{
|
||||
return Camera.main;
|
||||
}
|
||||
|
||||
Camera[] cameras = GetAvailableCameras();
|
||||
|
||||
int selectedCameraTargetIndex = -1;
|
||||
|
||||
// If the list of camera was updated since the last time we checked, update the dropdown and select the current main camera if available
|
||||
if (!cameras.Select(c => c.name).SequenceEqual(targetCameraDropdown.options.ToArray().Select(c => c.text)))
|
||||
{
|
||||
targetCameraDropdown.options.Clear();
|
||||
for (int i = 0; i < cameras.Length; i++)
|
||||
{
|
||||
Camera cam = cameras[i];
|
||||
targetCameraDropdown.options.Add(new Dropdown.OptionData(cam.name));
|
||||
|
||||
// The user selected a target camera at some point, default to that
|
||||
if (ConfigManager.Preferred_Target_Camera.Value == GetGameObjectPath(cam.gameObject)) {
|
||||
selectedCameraTargetIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// If couldn't find the user selected camera default to the main camera
|
||||
if (selectedCameraTargetIndex == -1)
|
||||
{
|
||||
for (int i = 0; i < cameras.Length; i++)
|
||||
{
|
||||
if (cameras[i] == Camera.main)
|
||||
{
|
||||
selectedCameraTargetIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetTargetDropdownValueWithoutNotify(selectedCameraTargetIndex);
|
||||
targetCameraDropdown.captionText.text = cameras[selectedCameraTargetIndex].name;
|
||||
}
|
||||
|
||||
// Fallback to the first camera
|
||||
if (targetCameraDropdown.value >= cameras.Length)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Selected camera index {targetCameraDropdown.value} is out of bounds, resetting to 0.");
|
||||
targetCameraDropdown.value = 0;
|
||||
}
|
||||
|
||||
return cameras[targetCameraDropdown.value];
|
||||
}
|
||||
|
||||
static void CacheMainCamera()
|
||||
{
|
||||
Camera currentMain = Camera.main;
|
||||
Camera currentMain = GetTargetCamera();
|
||||
|
||||
if (currentMain)
|
||||
{
|
||||
lastMainCamera = currentMain;
|
||||
@ -175,7 +246,7 @@ namespace UnityExplorer.UI.Panels
|
||||
lastMainCamera.enabled = false;
|
||||
}
|
||||
|
||||
ourCamera = new GameObject("UE_Freecam").AddComponent<Camera>();
|
||||
ourCamera = new GameObject("CUE Camera").AddComponent<Camera>();
|
||||
ourCamera.gameObject.tag = "MainCamera";
|
||||
GameObject.DontDestroyOnLoad(ourCamera.gameObject);
|
||||
ourCamera.gameObject.hideFlags = HideFlags.HideAndDontSave;
|
||||
@ -219,7 +290,7 @@ namespace UnityExplorer.UI.Panels
|
||||
MaybeToggleOrthographic(false);
|
||||
ToggleCustomComponents(false);
|
||||
|
||||
cameraMatrixOverrider = new GameObject("[CUE] Camera Matrix Overrider").AddComponent<Camera>();
|
||||
cameraMatrixOverrider = new GameObject("CUE Camera").AddComponent<Camera>();
|
||||
cameraMatrixOverrider.enabled = false;
|
||||
cameraMatrixOverrider.transform.position = lastMainCamera.transform.position;
|
||||
cameraMatrixOverrider.transform.rotation = lastMainCamera.transform.rotation;
|
||||
@ -234,7 +305,7 @@ namespace UnityExplorer.UI.Panels
|
||||
// Fallback in case we couldn't find the main camera for some reason
|
||||
if (!ourCamera)
|
||||
{
|
||||
ourCamera = new GameObject("UE_Freecam").AddComponent<Camera>();
|
||||
ourCamera = new GameObject("CUE Camera").AddComponent<Camera>();
|
||||
ourCamera.gameObject.tag = "MainCamera";
|
||||
GameObject.DontDestroyOnLoad(ourCamera.gameObject);
|
||||
ourCamera.gameObject.hideFlags = HideFlags.HideAndDontSave;
|
||||
@ -329,6 +400,49 @@ namespace UnityExplorer.UI.Panels
|
||||
freecamCursorUnlocker.Disable();
|
||||
}
|
||||
|
||||
internal static void MaybeResetFreecam()
|
||||
{
|
||||
if (inFreeCamMode) {
|
||||
EndFreecam();
|
||||
BeginFreecam();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UpdateTargetCameraAction(int newCameraIndex)
|
||||
{
|
||||
Camera[] cameras = GetAvailableCameras();
|
||||
Camera cam = cameras[newCameraIndex];
|
||||
ConfigManager.Preferred_Target_Camera.Value = GetGameObjectPath(cam.gameObject);
|
||||
MaybeResetFreecam();
|
||||
}
|
||||
|
||||
internal static void SetTargetDropdownValueWithoutNotify(int selectedCameraTargetIndex)
|
||||
{
|
||||
// Some build types don't have a reference to Dropdown.SetValueWithoutNotify
|
||||
MethodInfo SetValueWithoutNotifyMethod = targetCameraDropdown.GetType().GetMethod("SetValueWithoutNotify", new[] { typeof(int) });
|
||||
if (SetValueWithoutNotifyMethod != null)
|
||||
{
|
||||
SetValueWithoutNotifyMethod.Invoke(targetCameraDropdown, new object[] { selectedCameraTargetIndex });
|
||||
}
|
||||
else
|
||||
{
|
||||
targetCameraDropdown.onValueChanged.RemoveListener(UpdateTargetCameraAction);
|
||||
targetCameraDropdown.value = selectedCameraTargetIndex;
|
||||
targetCameraDropdown.onValueChanged.AddListener(UpdateTargetCameraAction);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetGameObjectPath(GameObject obj)
|
||||
{
|
||||
string path = "/" + obj.name;
|
||||
while (obj.transform.parent != null)
|
||||
{
|
||||
obj = obj.transform.parent.gameObject;
|
||||
path = "/" + obj.name + path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// Experimental feature to automatically disable cinemachine when turning on the gameplay freecam.
|
||||
// If it causes problems in some games we should consider removing it or making it a toggle.
|
||||
// Also, if there are more generic Unity components that control the camera we should include them here.
|
||||
@ -433,14 +547,11 @@ namespace UnityExplorer.UI.Panels
|
||||
GameObject CameraModeRow = UIFactory.CreateHorizontalGroup(ContentRoot, "CameraModeRow", false, false, true, true, 3, default, new(1, 1, 1, 0));
|
||||
|
||||
Text CameraMode = UIFactory.CreateLabel(CameraModeRow, "Camera Mode", "Camera Mode:");
|
||||
UIFactory.SetLayoutElement(CameraMode.gameObject, minWidth: 100, minHeight: 25);
|
||||
UIFactory.SetLayoutElement(CameraMode.gameObject, minWidth: 75, minHeight: 25);
|
||||
|
||||
GameObject cameraTypeDropdownObj = UIFactory.CreateDropdown(CameraModeRow, "CameraType_Dropdown", out cameraTypeDropdown, null, 14, (idx) => {
|
||||
ConfigManager.Default_Freecam.Value = (FreeCameraType)idx;
|
||||
if (inFreeCamMode) {
|
||||
EndFreecam();
|
||||
BeginFreecam();
|
||||
}
|
||||
MaybeResetFreecam();
|
||||
});
|
||||
foreach (FreeCameraType type in Enum.GetValues(typeof(FreeCameraType)).Cast<FreeCameraType>()) {
|
||||
cameraTypeDropdown.options.Add(new Dropdown.OptionData(Enum.GetName(typeof(FreeCameraType), type)));
|
||||
@ -448,6 +559,32 @@ namespace UnityExplorer.UI.Panels
|
||||
UIFactory.SetLayoutElement(cameraTypeDropdownObj, minHeight: 25, minWidth: 150);
|
||||
cameraTypeDropdown.value = (int)ConfigManager.Default_Freecam.Value;
|
||||
|
||||
if (ConfigManager.Advanced_Freecam_Selection.Value)
|
||||
{
|
||||
Text TargetCamLabel = UIFactory.CreateLabel(CameraModeRow, "Target_cam_label", " Target cam:");
|
||||
UIFactory.SetLayoutElement(TargetCamLabel.gameObject, minWidth: 75, minHeight: 25);
|
||||
|
||||
GameObject targetCameraDropdownObj = UIFactory.CreateDropdown(CameraModeRow, "TargetCamera_Dropdown", out targetCameraDropdown, null, 14, null);
|
||||
targetCameraDropdown.onValueChanged.AddListener(UpdateTargetCameraAction);
|
||||
|
||||
try {
|
||||
Camera[] cameras = GetAvailableCameras();
|
||||
foreach (Camera cam in cameras) {
|
||||
targetCameraDropdown.options.Add(new Dropdown.OptionData(cam.name));
|
||||
}
|
||||
if (Camera.main) {
|
||||
SetTargetDropdownValueWithoutNotify(Array.IndexOf(cameras, Camera.main));
|
||||
targetCameraDropdown.captionText.text = Camera.main.name;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ExplorerCore.LogWarning(ex);
|
||||
}
|
||||
|
||||
UIFactory.SetLayoutElement(targetCameraDropdownObj, minHeight: 25, minWidth: 150);
|
||||
}
|
||||
|
||||
|
||||
AddSpacer(5);
|
||||
|
||||
GameObject posRow = AddInputField("Position", "Freecam Pos:", "eg. 0 0 0", out positionInput, PositionInput_OnEndEdit);
|
||||
@ -1226,48 +1363,65 @@ namespace UnityExplorer.UI.Panels
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
// These doesn't exist for Unity <2017 nor when using HDRP
|
||||
Type renderPipelineManagerType = ReflectionUtility.GetTypeByName("RenderPipelineManager");
|
||||
if (renderPipelineManagerType != null){
|
||||
// These doesn't exist for Unity <2017 nor when using HDRP
|
||||
Type renderPipelineManagerType = ReflectionUtility.GetTypeByName("RenderPipelineManager");
|
||||
if (renderPipelineManagerType != null){
|
||||
try {
|
||||
EventInfo beginFrameRenderingEvent = renderPipelineManagerType.GetEvent("beginFrameRendering");
|
||||
if (beginFrameRenderingEvent != null) {
|
||||
beginFrameRenderingEvent.AddEventHandler(null, OnBeforeEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo endFrameRenderingEvent = renderPipelineManagerType.GetEvent("endFrameRendering");
|
||||
if (endFrameRenderingEvent != null) {
|
||||
endFrameRenderingEvent.AddEventHandler(null, OnAfterEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo beginCameraRenderingEvent = renderPipelineManagerType.GetEvent("beginCameraRendering");
|
||||
if (beginCameraRenderingEvent != null) {
|
||||
beginCameraRenderingEvent.AddEventHandler(null, OnBeforeEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo endCameraRenderingEvent = renderPipelineManagerType.GetEvent("endCameraRendering");
|
||||
if (endCameraRenderingEvent != null) {
|
||||
endCameraRenderingEvent.AddEventHandler(null, OnAfterEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo beginContextRenderingEvent = renderPipelineManagerType.GetEvent("beginContextRendering");
|
||||
if (beginContextRenderingEvent != null) {
|
||||
beginContextRenderingEvent.AddEventHandler(null, OnBeforeEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo endContextRenderingEvent = renderPipelineManagerType.GetEvent("endContextRendering");
|
||||
if (endContextRenderingEvent != null) {
|
||||
endContextRenderingEvent.AddEventHandler(null, OnAfterEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
try {
|
||||
EventInfo onBeforeRenderEvent = typeof(Application).GetEvent("onBeforeRender");
|
||||
if (onBeforeRenderEvent != null) {
|
||||
onBeforeRenderEvent.AddEventHandler(null, onBeforeRenderAction);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Failed to add event handler to rendering pipeline: {exception}");
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
@ -1283,47 +1437,61 @@ namespace UnityExplorer.UI.Panels
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
// These doesn't exist for Unity <2017 nor when using HDRP
|
||||
Type renderPipelineManagerType = ReflectionUtility.GetTypeByName("RenderPipelineManager");
|
||||
if (renderPipelineManagerType != null){
|
||||
// These doesn't exist for Unity <2017 nor when using HDRP
|
||||
Type renderPipelineManagerType = ReflectionUtility.GetTypeByName("RenderPipelineManager");
|
||||
if (renderPipelineManagerType != null){
|
||||
try {
|
||||
EventInfo beginFrameRenderingEvent = renderPipelineManagerType.GetEvent("beginFrameRendering");
|
||||
if (beginFrameRenderingEvent != null) {
|
||||
beginFrameRenderingEvent.RemoveEventHandler(null, OnBeforeEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo endFrameRenderingEvent = renderPipelineManagerType.GetEvent("endFrameRendering");
|
||||
if (endFrameRenderingEvent != null) {
|
||||
endFrameRenderingEvent.RemoveEventHandler(null, OnAfterEvent);
|
||||
}
|
||||
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo beginCameraRenderingEvent = renderPipelineManagerType.GetEvent("beginCameraRendering");
|
||||
if (beginCameraRenderingEvent != null) {
|
||||
beginCameraRenderingEvent.RemoveEventHandler(null, OnBeforeEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo endCameraRenderingEvent = renderPipelineManagerType.GetEvent("endCameraRendering");
|
||||
if (endCameraRenderingEvent != null) {
|
||||
endCameraRenderingEvent.RemoveEventHandler(null, OnAfterEvent);
|
||||
}
|
||||
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo beginContextRenderingEvent = renderPipelineManagerType.GetEvent("beginContextRendering");
|
||||
if (beginContextRenderingEvent != null) {
|
||||
beginContextRenderingEvent.RemoveEventHandler(null, OnBeforeEvent);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try {
|
||||
EventInfo endContextRenderingEvent = renderPipelineManagerType.GetEvent("endContextRendering");
|
||||
if (endContextRenderingEvent != null) {
|
||||
endContextRenderingEvent.RemoveEventHandler(null, OnAfterEvent);
|
||||
}
|
||||
}
|
||||
|
||||
EventInfo onBeforeRenderEvent = typeof(Application).GetEvent("onBeforeRender");
|
||||
if (onBeforeRenderEvent != null) {
|
||||
onBeforeRenderEvent.RemoveEventHandler(null, onBeforeRenderAction);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Failed to remove event handler from rendering pipeline: {exception}");
|
||||
|
||||
EventInfo onBeforeRenderEvent = typeof(Application).GetEvent("onBeforeRender");
|
||||
if (onBeforeRenderEvent != null) {
|
||||
onBeforeRenderEvent.RemoveEventHandler(null, onBeforeRenderAction);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user