Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Question Error-UnauthorizedAccessException

Discussion in 'Scripting' started by Gsaelzbaer24, May 25, 2024.

  1. Gsaelzbaer24

    Gsaelzbaer24

    Joined:
    Jan 17, 2024
    Posts:
    5
    Hey guys,

    I'm currently working on a problem I get in my project.
    I want to have a method that takes a screenshot (of a specific camera in the game) and saves the screenshot in a specific folder. Problem is: Unity keeps telling me it isnt authorized to acces the path I want to save the screenshot.

    I tried it with several folders, even the application.datapath isnt working. I've also changed the folder access rights in the explorer settings of the folder, nothing changed. Apart from that other data can be saved and changed in the folder with no problem, but screenshots not. In the code I tried to change several small things but with no impact. Started unity as admin. etc.
    Apart from that it used to work and since that I havent changed anything remarkable on the script. But as I tried it a couple of days ago, it wasnt working anymore.

    Im using 2022.3.22f1 for the project. And on Windows 10.

    My question is: Is the code correct? Should it be working and therefore the problem is somewhere on my PC. Or do I need to change sth in unity/the code.

    Help is appreciated. Im really new to unity and coding overall, if the code sometimes seem a bit messy.

    Following error occurs:
    UnauthorizedAccessException: Access to the path 'C:\Users\Nutzer\Documents\BA\Versuchsperson 9' is denied.
    System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) (at <27124aa0e30a41659b903b822b959bc7>:0)
    System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) (at <27124aa0e30a41659b903b822b959bc7>:0)
    (wrapper remoting-invoke-with-check) System.IO.FileStream..ctor(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
    System.IO.File.InternalWriteAllBytes (System.String path, System.Byte[] bytes) (at <27124aa0e30a41659b903b822b959bc7>:0)
    System.IO.File.WriteAllBytes (System.String path, System.Byte[] bytes) (at <27124aa0e30a41659b903b822b959bc7>:0)
    Screenshot.CaptureScreenshot (UnityEngine.Camera cam) (at Assets/OwnScripts/Screenshot.cs:109)
    Screenshot+<<TakeOverheadShot>g__WaitThen_CaptureScreenshot|8_0>d.MoveNext () (at Assets/OwnScripts/Screenshot.cs:68)
    UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <cb81df0c49c643b1a04d9fc6ccca2433>:0)
    UnityEngine.GUIUtility:processEvent(Int32, IntPtr, Boolean&)

    The script taking the screenshot is:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.IO;
    4. using UnityEngine.SceneManagement;
    5.  
    6. public class Screenshot : MonoBehaviour
    7. {
    8.  
    9.     // Auflösung des Screenshots
    10.     public int resWidth = 2550;
    11.     public int resHeight = 3300;
    12.     // Zähler für die fortlaufende Nummerierung der Screenshots
    13.     private static int screenshotNum = 1;
    14.  
    15.     // Referenzen zu den Kameras
    16.     public Camera overheadCam;
    17.     public Camera mainCamera;
    18.  
    19.     // Flag, das anzeigt, ob ein Overhead-Screenshot angefordert wurde
    20.     private bool isOverheadShotRequested = false;
    21.  
    22.     void Start()
    23.     {
    24.         // Deaktivierung der Overhead-Kamera am Anfang
    25.         overheadCam.enabled = false;
    26.     }
    27.  
    28.     //void Update()
    29.     //{
    30.     //    // Überprüfung, ob der Screenshot-Knopf gedrückt wurde und Auslösung des Overhead-Screenshots
    31.     //    if (isOverheadShotRequested)
    32.     //    {
    33.     //        TakeOverheadShot();
    34.     //        isOverheadShotRequested = false;
    35.     //    }
    36.     //}
    37.  
    38.     // Diese Methode wird aufgerufen, um den Screenshot auszulösen
    39.     public void TakeShot()
    40.     {
    41.         CaptureScreenshot(mainCamera);
    42.         // Markierung, dass ein Overhead-Screenshot angefordert wurde
    43.         isOverheadShotRequested = true;
    44.     }
    45.  
    46.     // Diese Methode nimmt den Overhead-Screenshot auf
    47.     public void TakeOverheadShot()
    48.     {
    49.         if (GetComponent<Camera>() == mainCamera)
    50.         {
    51.             overheadCam.enabled = true;
    52.             mainCamera.enabled = false;
    53.         }
    54.         else
    55.         {
    56.             overheadCam.enabled = true;
    57.             mainCamera.enabled = false;
    58.         }
    59.         //CaptureScreenshot(overheadCam);
    60.  
    61.         //mainCamera.enabled = false;
    62.         //overheadCam.enabled = true;
    63.         StartCoroutine(WaitThen_CaptureScreenshot(overheadCam));
    64.  
    65.         IEnumerator WaitThen_CaptureScreenshot(Camera overheadCam)
    66.         {
    67.             yield return new WaitForEndOfFrame();
    68.             CaptureScreenshot(overheadCam);
    69.         }
    70.         // Erhöhung des Zählers für die fortlaufende Nummerierung der Screenshots
    71.         screenshotNum++;
    72.     }
    73.  
    74.     // Diese Methode nimmt den Screenshot auf und speichert ihn als PNG-Datei
    75.  
    76.     void CaptureScreenshot(Camera cam)
    77.     {
    78.         Debug.Log("Screenshot in Preparation");
    79.         // Erstelle ein RenderTexture mit der Bildschirmgröße
    80.         RenderTexture screenTexture = new RenderTexture(Screen.width, Screen.height, 16);
    81.  
    82.         // Setze das RenderTexture als Ziel f�r die Kamera
    83.         cam.targetTexture = screenTexture;
    84.  
    85.         // Rendere die Ansicht der Kamera auf das RenderTexture
    86.         cam.Render();
    87.  
    88.         Debug.Log("Screenshot in Preparation1");
    89.         // Erstelle eine Textur, um die gerenderte Ansicht aufzunehmen
    90.         Texture2D renderedTexture = new Texture2D(Screen.width, Screen.height);
    91.         renderedTexture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
    92.         RenderTexture.active = null;
    93.  
    94.         // Kodiere die Texture2D in ein PNG-Byte-Array
    95.         byte[] byteArray = renderedTexture.EncodeToPNG();
    96.  
    97.         Debug.Log("Screenshot in Preparation2");
    98.  
    99.         // Konstruiere den Dateinamen mit der aktuellen Systemzeit
    100.         string fileName = SceneManager.GetActiveScene().name + " " + "screenshot_" + System.DateTime.Now.ToString() + ".png";
    101.  
    102.         //string ScreenshotPath = Path.Combine(PlayerDataLogger.PlayerFolderPath, PlayerDataLogger.playerName);
    103.  
    104.         Debug.Log("Screenshot in Preparation3");
    105.         Debug.Log(PlayerDataLogger.playerFolderPath);
    106.  
    107.         // Speichere das PNG-Byte-Array als Bild mit dem neuen Dateinamen
    108.      
    109.         System.IO.File.WriteAllBytes(PlayerDataLogger.playerFolderPath, byteArray);
    110.         //System.IO.File.WriteAllBytes(fileName, byteArray);
    111.  
    112.         // Debug-Ausgabe, um zu zeigen, dass der Screenshot genommen wurde
    113.         Debug.Log(SceneManager.GetActiveScene().name + " Screenshot taken");
    114.  
    115.         // Wechsel zwischen Hauptkamera und Overhead-Kamera
    116.         if (GetComponent<Camera>() == mainCamera)
    117.         {
    118.             overheadCam.enabled = true;
    119.             mainCamera.enabled = false;
    120.         }
    121.         else
    122.         {
    123.             overheadCam.enabled = false;
    124.             mainCamera.enabled = true;
    125.         }
    126.     }
    127. }
    128.  
    For the playerFolderPath it refers to the following script:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.IO;
    3. using UnityEngine.SceneManagement;
    4.  
    5. public class PlayerDataLogger : MonoBehaviour
    6. {
    7.     private static PlayerDataLogger instance;
    8.  
    9.     public static string playerName;
    10.     public static string playerFolderPath;
    11.     public static int playerNumber;
    12.     private string currentSceneName;
    13.  
    14.     private string playerFolderDirectory = @"C:\Users\Nutzer\Documents\BA";
    15.  
    16.     public static PlayerDataLogger Instance
    17.     {
    18.         get { return instance; }
    19.     }
    20.  
    21.     void Awake()
    22.     {
    23.         if (instance != null && instance != this)
    24.         {
    25.             Destroy(gameObject);
    26.         }
    27.         else
    28.         {
    29.             instance = this;
    30.             DontDestroyOnLoad(gameObject);
    31.             InitializePlayer();
    32.         }
    33.     }
    34.  
    35.     void InitializePlayer()
    36.     {
    37.         playerNumber = GetPlayerNumber();
    38.         playerName = "Versuchsperson " + playerNumber;
    39.         playerFolderPath = Path.Combine(playerFolderDirectory, playerName);
    40.  
    41.         if (!Directory.Exists(playerFolderPath))
    42.         {
    43.             Directory.CreateDirectory(playerFolderPath);
    44.             Debug.Log("Player folder created: " + playerFolderPath);
    45.         }
    46.  
    47.         string logFilePath = Path.Combine(playerFolderPath, "PlayerLog.txt");
    48.         using (StreamWriter writer = File.AppendText(logFilePath))
    49.         {
    50.             writer.WriteLine("Player Name: " + playerName);
    51.             writer.WriteLine("Date: " + System.DateTime.Now.ToString());
    52.             writer.WriteLine("Welcome to the game!");
    53.         }
    54.     }
    55.  
    56.     private int GetPlayerNumber()
    57.     {
    58.         int number = 1;
    59.         string[] playerFolders = Directory.GetDirectories(playerFolderDirectory, "Versuchsperson*");
    60.         if (playerFolders.Length > 0)
    61.         {
    62.             foreach (string folder in playerFolders)
    63.             {
    64.                 string folderName = Path.GetFileName(folder);
    65.                 int.TryParse(folderName.Replace("Versuchsperson ", ""), out int num);
    66.                 if (num >= number)
    67.                 {
    68.                     number = num + 1;
    69.                 }
    70.             }
    71.         }
    72.         return number;
    73.     }
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,922
    Your user's name really is "Nutzer"? How very uncreative. :D
    If you're not logged in as "Nutzer" you can't access that path. This would explain the permission issue.

    Does the path exist?

    Note that you HAVE to enclose all File I/O in try/catch and handle any errors appropriately. You can't just let the app die with an exception due to file IO, especially not when the app is published. IO code will always fail for a portion of your users!


    Btw, you can replace most of your CaptureScreenshot method with, well, ScreenCapture.CaptureScreenshot. ;)
     
  3. Gsaelzbaer24

    Gsaelzbaer24

    Joined:
    Jan 17, 2024
    Posts:
    5
    I think Nutzer was the standard username back then. But I'm not 100% sure maybe younger me thought he was funny. Anyway I am logged in as Nutzer and the path exists. The PlayerDataLogger Skript creates the folder at the beginning of the first scene. But Ive tried several different paths, same output.

    I'll use the project only on my PC, its for university experiment, but I appreciate the hint. Will definetely take care of that when I have more time or I want to distribute sth.

    This was the first thing I tried, but it only takes a screenshot from the current players view. At least when I used it. But I need a "screenshot" of a static camera not from the player view.
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,922
    Check the folder / file permissions. Your user respectively the general "Users" group should have read+write permissions and given that the folder is in your user's home your user should also be the owner. If that is correct, it can only be some other application keeping a lock on that file. If you have the file open in some other program this can cause such a permission issue - although it's rare to happen with a text file.

    Did you try rebooting?
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,369
    Make sure NONE of the characters in your path are anything except A-Z and 0-9... This looks perhaps like it's German of some kind and if any of those characters are not ASCII letters, you'll often have issues.
     
  6. Gsaelzbaer24

    Gsaelzbaer24

    Joined:
    Jan 17, 2024
    Posts:
    5
    I totally forgot to give an update here, sorry. I found a solution. Apparently the path (including the file name) has very strict requirements. I tried sth like this:

    Code (CSharp):
    1. string fileName = Path.Combine(PlayerDataLogger.playerFolderPath, SceneManager.GetActiveScene().name + " " + "screenshot_" + System.DateTime.Now.ToString() + ".png";
    However the screenshot name somehow messed up with the path and it showed the error I got.

    Changed it to this and now it works like a charm:

    Code (CSharp):
    1. string fileName = Path.Combine(PlayerDataLogger.playerFolderPath, $"{SceneManager.GetActiveScene().name}_Overheadshot_{System.DateTime.Now.ToString("yyyyMMdd_HHmm")}_{screenshotNum}.png");
     
  7. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,922
    Yes, that is problematic because you have to consider that DateTime strings are formatted based on the user's locale!

    A date may be formatted like "2024/24/04" or it could be formatted as "24.4.2024". The latter would work in the file system, the former would add additional folders 2024, 24 and 04.
     
  8. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,191
    Right, apart from the date, the time usually uses a colon as separator which isn't really allowed in a path as well (besides alternative data streams in rare occations). So using the default ToString would in most cases create issues.