Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

(Solved) Can I set values in the editor with Buildpipeline?

Discussion in 'Scripting' started by munkbusiness, Jul 4, 2019.

  1. munkbusiness

    munkbusiness

    Joined:
    Aug 22, 2017
    Posts:
    46
    I have just gotten in to using buildpipeline to simplify my build process. But I am needing one more step to have it done.

    When I build I, depending on whether I build for example steam or itch.io I need to change a few boolean and strings in some gameobjects on my first scene. Is there a way in my builder to toggle serializeFields or do I have to do a roundabout way where I define some values in a static class, that my game then reads from on startup?
     
  2. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,384
    Load that scene using EditorSceneManager, do required manipulations, save scene and then run the build process.
     
    munkbusiness likes this.
  3. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    2,013
  4. munkbusiness

    munkbusiness

    Joined:
    Aug 22, 2017
    Posts:
    46
    EDIT: Turns out this solution didn't work for prefab objects in the scene. The TRUE solution is further down this topic. I left in what I initially though was working, so that the posts makes sense.

    Just wanted to thank you for helping me out.

    For future searchers here is what I ended up doing:

    Code (CSharp):
    1.  
    2. static void SetupForBuild(int levels, bool steam, bool demo) {
    3.  
    4.         var currentScene = EditorSceneManager.OpenScene("Assets/Scenes/IntroMenu.unity");
    5.  
    6.         GameObject[] allObjects = currentScene.GetRootGameObjects();
    7.  
    8.         if (currentScene.isLoaded) {
    9.             for (int i = 0; i < allObjects.Length; i++) {
    10.  
    11.                 switch (allObjects[i].name) {
    12.                     case "SteamManager":
    13.                         Debug.Log(allObjects[i].name);
    14.                         allObjects[i].GetComponent<SteamManager>().steamEnabled = steam;
    15.                         allObjects[i].GetComponent<SteamManager>().isDemo = demo;
    16.                         break;
    17.                     case "CarryoverController":
    18.                         Debug.Log(allObjects[i].name);
    19.                         allObjects[i].GetComponent<CarryoverInfo>().maxLevel = levels;
    20.                         allObjects[i].GetComponent<CarryoverInfo>().devFeatures = false;
    21.                         break;
    22.                     case "MainMenuCanvas":
    23.                         Debug.Log(allObjects[i].name);
    24.                         allObjects[i].transform.Find("HighscorePanel").Find("highscoreScripts").GetComponent<SteamHighscores>().leaderBoardName = demo ? "Demo" : "Speedrun";
    25.                         break;
    26.                 }
    27.  
    28.             }
    29.         }
    30.  
    31.         EditorSceneManager.SaveScene(currentScene);
    32.  
    33.         EditorSceneManager.CloseScene(currentScene, true);
    34. }
    35.  
    After that just the typical BuildPipeline doing its thing.
     
    Last edited: Sep 25, 2019
    palex-nx likes this.
  5. munkbusiness

    munkbusiness

    Joined:
    Aug 22, 2017
    Posts:
    46
    Actually it doesn't seem like this was completely solved just yet.

    It works for everything except for the component "CarryoverInfo" which seems to either ignore it or overwrite it.

    The only difference I can come up with is that "CarryoverInfo" is a prefab, so IDK if when building that the prefab overwrites the values back or something. If I change the values in the editor without changing the prefab values, it still works, so it seems really wierd.
     
  6. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    2,013
    It could be that some kind of call back is executed inside that script. Or somewhere else.

    I'd suggest checking source. Specifically for something like .OnValidate() calls.
     
  7. munkbusiness

    munkbusiness

    Joined:
    Aug 22, 2017
    Posts:
    46
    I searched my code, but nowhere do I set those two values, I use them exclusively for reading flags.

    I am not using OnValidate at all either.

    I do have this in OnAwake
    Code (CSharp):
    1. //Make static reference so that other objects can get it.
    2.         if (instance == null) {
    3.             instance = this;
    4.         }
    5.         else if (instance != this) {
    6.             Destroy(gameObject);
    7.             return;
    8.         }
    9.  
    10.         //GameServer will live forever across multiple dimensions and scenes
    11.         DontDestroyOnLoad(this);
    And I have this prefab in every scene as it makes testing faster. I though maybe those were somehow changing the value of the first one, but that doesn't seem to be the case.
     
  8. munkbusiness

    munkbusiness

    Joined:
    Aug 22, 2017
    Posts:
    46
    Bumb. still an issue.
     
  9. Adrian

    Adrian

    Joined:
    Apr 5, 2008
    Posts:
    378
    I suspect Unity doesn't realize the object has been changed and doesn't properly re-serialize it. When you're editing an object in the editor, you're not actually editing the object instance but the serialized data instead. When you go and change objects directly, Unity might just discard it and use its old serialized data.

    Try calling EditorUtility.SetDirty on the object to let Unity know it was changed. Alternatively, use the SerializedObject API to edit the object, which is what the inspector is using.

    Instead of opening and saving the scene, you can also try the PostProcessSceneAttribute. This allows you to edit the level during build and is potentially much more efficient, since the original scene asset doesn't need to be changed. I also suspect Unity is better at handling changes done during this callback, I personally never had issues with direct changes not sticking using this.
     
    munkbusiness likes this.
  10. munkbusiness

    munkbusiness

    Joined:
    Aug 22, 2017
    Posts:
    46
    Thanks a lot, a bunch of material to work with. I could proably just have set is as dirty, but the SerializedObject API was what I really needed, as now I don't have to expose all the variables anymore either.

    If I get extra time I might look into PostProcessSceneAttribute later.

    For future searchers here is the solution that actually works, entirely.

    Code (CSharp):
    1. static void SetupForBuild(int levels, bool steam, bool demo) {
    2.         var currentScene = EditorSceneManager.OpenScene("Assets/Scenes/IntroMenu.unity");
    3.  
    4.         GameObject[] allObjects = currentScene.GetRootGameObjects();
    5.  
    6.         SerializedObject serializedObject;
    7.  
    8.         if (currentScene.isLoaded) {
    9.             for (int i = 0; i < allObjects.Length; i++) {
    10.  
    11.                 switch (allObjects[i].name) {
    12.                     case "SteamManager":
    13.                         serializedObject = new SerializedObject(allObjects[i].GetComponent<SteamManager>());
    14.  
    15.                         serializedObject.FindProperty("steamEnabled").boolValue = steam;
    16.                         serializedObject.FindProperty("isDemo").boolValue = demo;
    17.                         serializedObject.ApplyModifiedPropertiesWithoutUndo();
    18.                         break;
    19.                     case "CarryoverController":
    20.                         serializedObject = new SerializedObject(allObjects[i].GetComponent<CarryoverInfo>());
    21.  
    22.                         serializedObject.FindProperty("maxLevel").intValue = levels;
    23.                         serializedObject.FindProperty("devFeatures").boolValue = false;
    24.                         serializedObject.FindProperty("ppVignette").boolValue = true;
    25.                         serializedObject.FindProperty("ppDepthOfField").boolValue = true;
    26.                         serializedObject.FindProperty("ppColorGrading").boolValue = true;
    27.                         serializedObject.ApplyModifiedPropertiesWithoutUndo();
    28.                         break;
    29.                     case "MainMenuCanvas":
    30.  
    31.                         serializedObject = new SerializedObject(allObjects[i].transform.Find("HighscorePanel").Find("highscoreScripts").GetComponent<SteamHighscores>());
    32.                         serializedObject.FindProperty("leaderBoardName").stringValue = demo ? "Demo" : "Speedrun";
    33.                         serializedObject.ApplyModifiedPropertiesWithoutUndo();
    34.  
    35.                         serializedObject = new SerializedObject(allObjects[i].transform.Find("versionNum").GetComponent<Text>());
    36.                         serializedObject.FindProperty("m_Text").stringValue = "VERSION " + DateTime.Now.ToString("dd.MM.yyyy") + (demo ? " DEMO" : "");
    37.                         serializedObject.ApplyModifiedPropertiesWithoutUndo();
    38.                         break;
    39.                 }
    40.             }
    41.         }
    42.         EditorSceneManager.SaveScene(currentScene);
    43.         EditorSceneManager.CloseScene(currentScene, true);
    44.  
    45.     }