Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question I made an amateur mistake of renaming a script and well, all hell broke loose.

Discussion in 'Scripting' started by Eversmann, Feb 21, 2023.

  1. Eversmann

    Eversmann

    Joined:
    May 3, 2013
    Posts:
    29
    So, I made a stupid mistake, I renamed a script cuz the name didn't fit and well, as expected all hell broke lose. I even reverted back changes to an older revision (which fixed that script issue) but now the main issue is other stuff seems to randomly not work. For example I get null reference error when I try to select an item in the inventory even though everything was exactly as before.
    Here is the whole script: https://hatebin.com/rshvjqpnwi

    Edit: It seems the only scripts that cause issues are the singletons. Like when I do Whatever.instance it breaks.

    This is what I get https://preview.redd.it/rq3dkajonij...ed&s=eedd9ea5cdae13c4909215503a6c0a170ce1cf9c
     
  2. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    You do all the .instance-calls in Awake.
    Perhaps this is a Script Execution Order-issue? (i.e. are the .instances set by the other Objects in their own Awake?)
    Try moving all the X = X.instance-lines to Start().
     
    Bunny83 likes this.
  3. Eversmann

    Eversmann

    Joined:
    May 3, 2013
    Posts:
    29
    At work at the moment but I will try it at home and report back. The weird thing is even if I type Inventory.instance.selected it still throws a null reference error.
    I’m quite confused I must admit. But I will try to refactor with what you suggested.

    I used to cache the singletons in local variables before for testing so maybe now when I did switch to caching it outside, something broke.
     
  4. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    If you're still getting it even after reverting then Script Execution Order would be my first guess (race-conditions).
    There are of course also the Unity - Manual: Script Execution Order settings (unity3d.com) -Settings and the [DefaultExecutionOrder(x)] that you can use to manually set the order, instead of using Start(). Personally, I always try to have Awake() do all the self-init, and Start() do all the init that relies on other objects.
     
  5. Eversmann

    Eversmann

    Joined:
    May 3, 2013
    Posts:
    29
    I shall try it later and report back. Cheers!
     
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,735
    This is not "all hell breaking loose". This is a simple NullReferenceException.

    Accessing other objects and references (xxx.instance) for example which are presumably set in Awake should be done in Start. Here's the initialization rule of thumb:
    1. Initialize yourself in Awake
    2. Do things that depend on other scripts being initialized in Start
     
    Eversmann likes this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,947
    You really need to be using source control or you will ceaselessly shoot yourself in the foot like this.

    Here's the full "recover lost stuff" blurb, but there is a specific section on how to safely rename a file.

    Yes, it is lame that you have to rename so carefully. No, it's not likely to change in the near future.

    Lost progress / project / work / stuff disappeared in Unity.

    This article is to help you when you have lost significant progress or work in your Unity project.

    It is designed to give you avenues of discovery and investigation.

    It is NOT a guarantee of restoring your lost work. It is NOT a substitute for proper IT / Data security procedures.

    To decide which parts are applicable to you, look for major bolded headings.

    EVERYTHING IS GONE, YOU CANNOT OPEN THE PROJECT

    Your project probably is still on your computer. Try a computer-wide search for some unique filenames that you know are in the project you think is gone.

    To start your search, one common file to all Unity projects is named
    ProjectSettings.asset


    Some things that might have happened:

    - you are not opening the project that you think you are
    - you are in the correct project but not opening the same scene you had open before
    - you dragged the project (or part of it) into the trash (intentionally or inadvertently)
    - you moved the project (or part of it) somewhere else (intentionally or inadvertently)
    - an overly-aggressive antivirus solution quarantined it because it saw code being compiled in there
    - you're using a directory sync like OneDrive or Dropbox... NEVER USE THESE SERVICES WITH UNITY!
    - something else??

    As I said, it's probably still all on your system to be found if you look in the right places.

    A typical Unity project will have at a minimum the following folders:

    Assets\
    ProjectSettings\
    Packages\


    EVERYTHING IS PRESENT BUT MY SCENE WINDOW IS BLANK

    Close Unity and make a full project backup RIGHT NOW. Do not do ANYTHING else until you back it up 100%.

    Ideally copy that backup to another computer, or back it up to another external hard drive entirely. This is just basic data processing best practices during data recovery operations.

    If you can see all the files and folders of your project, make sure you are opening the scene file you were working in.

    Once you have opened the scene, look in the hierarchy window, select an object and move the mouse over the Scene window and press F to focus that object.

    Additional notes:

    - ALWAYS use proper industrial grade source control (see below)
    - NEVER use Dropbox or any file sync mechanism in Unity.
    - NEVER move files within your project, except by doing it within Unity
    - ALWAYS be sure you are fully backed up before upgrading Unity

    SCRIPTS OR ASSETS ARE MISSING OR BLANK

    Some info about Missing script warnings, broken prefabs, GUIDs, renaming GUIDs, etc:

    https://forum.unity.com/threads/problem-with-git-and-missing-scripts.1090876/#post-7024801
    https://forum.unity.com/threads/scr...ead-after-loading-editor.998413/#post-6487297
    https://forum.unity.com/threads/scr...ead-after-loading-editor.998413/#post-6488230

    EVERYTHING in Unity is connected to the above GUID, which is stored ONLY in the metafile, and hence why the metafiles ALWAYS MUST be source-controlled.

    When Renaming: It is super-easy to inadvertently change the GUID by renaming outside of Unity. Don't do that. Instead:

    - close Visual Studio (important!)
    - rename the file(s) in Unity
    - in Unity do Assets -> Open C# Project to reopen Visual Studio
    - now rename the actual classes, and MAKE SURE THE FILE NAMES DO NOT CHANGE!

    If you are NOT using source control while you do this, renaming files is an EXTREMELY dangerous process. Use source control at all times so that you can trivially revert if you miss a critical step and damage your project.

    UNITY CRASHES / FREEZES WHEN I OPEN MY PROJECT

    You must isolate if there is something wrong with your Unity installation, something wrong with your project, or perhaps just a corrupted import or asset database.

    First, ALWAYS back your project up. Then try deleting the
    Library/
    and
    Temp/
    folders that are within your project, the directories that are peers to the
    Assets
    and
    ProjectSettings
    folders.

    If that doesn't work it is time to bisect. Make a new empty project and get Unity to open that. If you cannot then it is time to fix your Unity installation, either by fully reinstalling or verifying it with the hub.

    Once you have an empty project open, begin copying over your project. Try the entire thing. If it crashes, try half of the project, then the other half, etc.

    As always, if you're using Windows, another "first thing to try" is to simply reboot the system. This often fixes typical Windows issues related to locked files and locked directories.

    ISSUES RELATED TO UPGRADING PROJECTS (eg, changing to a higher Unity version)

    Upgrading to a later version of Unity is a one-way process. Any project that has been updated should NEVER be reverted to an earlier version of Unity because this is expressly not supported by Unity. Doing so exposes your project to internal inconsistencies and breakage that may actually be impossible to repair.

    If you want to upgrade to a newer version of Unity, do not even consider it until you have placed your project fully under proper source control. This goes double or triple for non-LTS (Tech Stream) versions of Unity3D, which can be extremely unstable compared with LTS.

    Once you have source-controlled your project then you may attempt a Unity upgrade. Immediately after any attempted upgrade you should try to view as much of your project as possible, with a mind to looking for broken animations or materials or any other scripting errors or runtime issues.

    After an upgrade you should ALWAYS build to all targets you contemplate supporting: iOS and Android can be particularly finicky, and of course any third party libraries you use must also "play nice" with the new version of Unity. Since you didn't write the third party library, it is up to you to vet it against the new version to make sure it still works.

    If there are issues in your testing after upgrading Unity, ABANDON the upgrade, revert your project in source control and be back where you were pre-upgrade with the earlier version of Unity.

    Obviously the less you test after the upgrade the more chance you will have of an undiscovered critical issue.

    This risk of upgrading is entirely on you and must be considered whenever you contemplate a Unity version upgrade.

    Do not upgrade "just for fun" or you may become very unhappy.

    PROPERLY CONFIGURING AND USING ENTERPRISE SOURCE CONTROL

    Please consider using proper industrial-grade enterprise-qualified source control in order to guard and protect your hard-earned work.

    Personally I use git (completely outside of Unity) because it is free and there are tons of tutorials out there to help you set it up as well as free places to host your repo (BitBucket, Github, Gitlab, etc.).

    You can also push git repositories to other drives: thumb drives, USB drives, network drives, etc., effectively putting a complete copy of the repository there.

    As far as configuring Unity to play nice with git, keep this in mind:

    https://forum.unity.com/threads/prefab-links-keep-getting-dumped-on-git-pull.646600/#post-7142306

    I usually make a separate repository for each game, but I have some repositories with a bunch of smaller test games.

    Here is how I use git in one of my games, Jetpack Kurt:

    https://forum.unity.com/threads/2-steps-backwards.965048/#post-6282497

    Using fine-grained source control as you work to refine your engineering:

    https://forum.unity.com/threads/whe...grammer-example-in-text.1048739/#post-6783740

    Share/Sharing source code between projects:

    https://forum.unity.com/threads/your-techniques-to-share-code-between-projects.575959/#post-3835837

    Setting up an appropriate .gitignore file for Unity3D:

    https://forum.unity.com/threads/removing-il2cpp_cache-from-project.1084607/#post-6997067

    Generally setting Unity up (includes above .gitignore concepts):

    https://thoughtbot.com/blog/how-to-git-with-unity

    It is only simple economics that you must expend as much effort into backing it up as you feel the work is worth in the first place. Digital storage is so unbelievably cheap today that you can buy gigabytes of flash drive storage for about the price of a cup of coffee. It's simply ridiculous not to back up.

    If you plan on joining the software industry, you will be required and expected to know how to use source control.

    "Use source control or you will be really sad sooner or later." - StarManta on the Unity3D forum boards
     
    Eversmann likes this.
  8. Eversmann

    Eversmann

    Joined:
    May 3, 2013
    Posts:
    29
    Cheers. Will try as soon as I get home.
     
  9. Eversmann

    Eversmann

    Joined:
    May 3, 2013
    Posts:
    29
    Very detailed post thank you! Normally I don’t rename but alas something made me do it this time against my better judgement. Very detailed post about all of it I will save it for future reference.
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,947
    Make sure you're doing these correctly. There are a ton of degenerate examples out there.

    Most important is to NEVER require placing one of them in the scene. Disasters always follow.

    Here is the approach(es) I use 100% of the time for these sorts of things:

    Simple Singleton (UnitySingleton):

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance!

    The above solutions can be modified to additively load a scene instead, BUT scenes do not load until end of frame, which means your static factory cannot return the instance that will be in the to-be-loaded scene. This is a minor limitation that is simple to work around.

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
    There are also lots of Youtube tutorials on the concepts involved in making a suitable GameManager, which obviously depends a lot on what your game might need.

    OR just make a custom ScriptableObject that has the shared fields you want for the duration of many scenes, and drag references to that one ScriptableObject instance into everything that needs it. It scales up to a certain point.

    And finally there's always just a simple "static locator" pattern you can use on MonoBehaviour-derived classes, just to give global access to them during their lifecycle.

    WARNING: this does NOT control their uniqueness.

    WARNING: this does NOT control their lifecycle.

    Code (csharp):
    1. public static MyClass Instance { get; private set; }
    2.  
    3. void OnEnable()
    4. {
    5.   Instance = this;
    6. }
    7. void OnDisable()
    8. {
    9.   Instance = null;     // keep everybody honest when we're not around
    10. }
    Anyone can get at it via
    MyClass.Instance.
    , but only while it exists.
     
    Eversmann likes this.
  11. Eversmann

    Eversmann

    Joined:
    May 3, 2013
    Posts:
    29
    To update back it was indeed the case of using Awake() instead of Start(). However, the interesting thing is I have 6 inventory slots and only on the first one, when I debug.log it, it returns as true when checking if null. On the other 5 slots, they return as false.

    Edit: I figured it out. It's with how I handle inventory initialization. All good now. Thanks everyone for the help!
     
    Last edited: Feb 22, 2023
  12. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,571
    May I ask why you "cache" a singleton in field variables of another class? Singletons in Unity already do not really follow the actual design pattern as that's not possible with a MonoBehaviour derived class. Though one of the remaining points of a singleton is that it is accessed through a single point of reference. That's your static "instance" (field or property). What benefit you expect from storing the reference in a field of that class? To read a class field you still need to grab the class reference (this) and do a memory lookup to read the value from the field.

    We don't know what kind of singleton you may have implemented, but reading a static field or calling a static method that reads a static field is not really more expensive.

    You generally should not "cache" a singleton anywhere else than in the singleton itself :)
     
    Kurt-Dekker likes this.
  13. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,947
    Caching implies "keep this on hand because getting it was expensive" but as bunny points out, cost won't change (much), plus now you open yourself up to a HUGE class of bugs you never even had to consider before.
     
  14. SF_FrankvHoof

    SF_FrankvHoof

    Joined:
    Apr 1, 2022
    Posts:
    780
    And in local (method-scoped) variables.

    Code (CSharp):
    1. void MyMethod()
    2. {
    3.     MySingleton inst = MySingleton.instance;
    4.     inst.a();
    5.     inst.b();
    6.     inst.c();
    7. }
    vs

    Code (CSharp):
    1. void MyMethod()
    2. {
    3.     MySingleton.instance.a();
    4.     MySingleton.instance.b();
    5.     MySingleton.instance.c();
    6. }
     
  15. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,571
    Well, yes, that's fine :)
     
  16. dlorre

    dlorre

    Joined:
    Apr 12, 2020
    Posts:
    700
    Next time you want to rename something, right click and use the special menu for it, either Rename or Refactorization. If you just rename the script itself then it will offer the option to rename the class as well and accept it.
     
    Eversmann likes this.
  17. Eversmann

    Eversmann

    Joined:
    May 3, 2013
    Posts:
    29
    That is a fair point. I don't have too many of them so I don't think memory would be an issue even if they have to be accessed more often.
    Also, caching it in local variables is okay?
     
  18. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,947
    Don't try to engineer by ritual. If someone says "ALWAYS CACHE ALL THE THINGS!" ignore them because they are being brainlessly dogmatic.

    Ask yourself WHY you want to make a local variable cache and what benefit it brings you, and ESPECIALLY ask if it is worth the new class of bugs you expose yourself to (eg, the original variable changing without your realizing it).

    Some possible reasons to cache things:

    - performance (did it cost you a lot of performance to get this value)
    - reduce repetition
    - makes the code read better by reducing visual noise
    - reduce the surface of concern (see interfaces for more of this)
     
    Eversmann likes this.
  19. Eversmann

    Eversmann

    Joined:
    May 3, 2013
    Posts:
    29
    Cheers Kurt! And what are your thoughts on the so called Master Singleton?
     
  20. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,947
    As I said, I use the above pattern always, and I do it precisely the way a particular class needs. Link:

    https://forum.unity.com/threads/i-m...ll-all-hell-broke-loose.1402789/#post-8824030

    Having a single UnitySingleton<T> class to derive from does not fix or improve the problem space in any measurable way that I have seen.

    Having a single UnitySingleton<T> class to start from always:

    - hides important lifecycle information that I want displayed prominently at the top of my class

    - hides actual lifecycle functionality that may not be intuitively correct

    - introduces more dependencies and code I must copy
     
    Eversmann likes this.