Prefab's original text being passed to variables rather than the actual text set during runtime

Hi, I have a weird problem that only happens once I’ve built my project. I have been working on this issue for a couple of days and I can’t seem to find anything similar anywhere else on the internet. My code works exactly the way I want it to in the unity editor however things go astray when I build my project.

In the ContactsList scene I have a list of buttons that are automatically generated on start. Each button has a text object, which is set to the contact’s name, and an image object, which is set to the contact’s avatar. Up to this point everything works fine in the build. The names are generated correctly and the sprites appear fine.

When you click on one of the buttons you are taken to the Messenger scene where you can message a contact. In the messenger scene the contact’s avatar image and name are displayed. The name and the image should match the corresponding information on the button you clicked. The avatar image passes through correctly and matches the image on the button.

However the contact name does not pass through correctly. Instead of setting the name to the contact button name, it sets it to the original name of the button prefab’s text component. I know this because I have tried changing the button prefab’s name text and it always matches the name set in the Messenger scene.

What my code also does is store a text file of messages. The text file’s name consists of the name of the contact, which is extracted from the avatar game object in the messenger screen. This avatar object is also a prefab and I have checked what the text file is called under the _data folder in my build folder and it comes out as the original avatar prefab’s name rather than the one I set at runtime using script.

Because of these two things I believe that my game is passing text from the original prefabs rather than the values assigned to the instantiated prefabs during runtime. However strangely this is only happening when I have built the project and is only happening to text components attached to prefabs and not for example Image components, which work fine.

I have tried using PlayerPrefs to pass the name variables between scenes instead and I get the same problem either way. It’s been a bit tricky to debug as the problem only occurs once I’ve built my project. Any ideas as to what might be going on would be appreciated, thank you.

Note: Here CustomiseMessengerInfo.contactName is being set to the button’s original prefab text, not the actual text.

/*
* LoadMessenger is attached to a button and passes the contact's name and avatar to the CustomiseMessengerInfo script
* It then loads the messenger scene
*/
public class LoadMessenger : MonoBehaviour
{
    public TextMeshProUGUI contact;
    public Image contactAvatar;
    public void LoadMessengerScreen()
    {
        //this is getting original prefab text not actual text but don't know why
        CustomiseMessengerInfo.contactName = contact.text.ToString();
        CustomiseMessengerInfo.avatar = contactAvatar.sprite;
        //get list of message objects and populate list view content with them
        SceneManager.LoadScene("Messenger");
    }
}
/*
* CustomiseMessengerInfo customises the components of a messenger scene to a specific person
*/
public class CustomiseMessengerInfo : MonoBehaviour
{
    public static string contactName;
    public static string contactBio;
    public static Sprite avatar;
    public GameObject placeholderAvatar;
    public TextMeshProUGUI placeholderName;
    // Start is called before the first frame update
    void Start()
    {
        SetAvatarInfo();
    }
   
    public void SetAvatarInfo() {
        placeholderAvatar.GetComponent<Image>().sprite = avatar;
        placeholderName.SetText(contactName);
    }
}

Note: All the logic in the SaveAndUpdateMessages class works ok, I’ve just included it because of this line: string localPath = Application.dataPath + “/”+ avatarName.text.ToString() + “MsgContainer.txt”; as avatarName.text.ToString() is also passing in the original prefab text, not the actual text.

/*
* I need in this class:
* A method that saves each message to a file containing messages
* The file will contain information in the format: messageContent | messageType \n
* Every time the messenger screen is loaded the file content will be loaded and processed into text to display in game objects
*/
public class SaveAndUpdateMessages : MonoBehaviour
{


    GameObject msgContainer;//the content message container
    public TextMeshProUGUI avatarName;//the avatar name
    public GameObject received;//received text object
    public GameObject sent;//sent text object


    //Called when a message is posted
    public void SaveMessageToFile(string messageContent, string messageType) {
        string localPath = Application.dataPath + "/"+ avatarName.text.ToString() + "MsgContainer.txt";

        if (!File.Exists(localPath)) {
            File.Create(localPath).Dispose();
        }
        using (StreamWriter sw = File.AppendText(localPath))
        {
            sw.WriteLine(messageContent + "|" + messageType);
            sw.Flush();
            sw.Close();
        }

    }

    //Called when the messenger screen is opened
    public void LoadMessagesFromFile() {
        string localPath = Application.dataPath + "/" + avatarName.text.ToString() + "MsgContainer.txt";
        if (!File.Exists(localPath))
        {
            File.Create(localPath).Dispose();
            return;
        }

        StreamReader inp_stm = new StreamReader(localPath);

        while (!inp_stm.EndOfStream)
        {
            string inp_ln = inp_stm.ReadLine();
            string[] message = inp_ln.Split('|');
            if (message[1] == "Received")
            {
               
                gameObject.GetComponent<GenerateMessage>().CreateMessage(received,message[0]);
            }
            else
            {
               
                gameObject.GetComponent<GenerateMessage>().CreateMessage(sent, message[0]);
            }
        }
        inp_stm.Close();
    }



    void Start()
    {
        LoadMessagesFromFile();
       
    }


}

5083085--500192--contacts.PNG 5083085--500195--contacts2.PNG
5083085--500219--contacts3.PNG

It looks to me like those two public properties in LoadMesseger are probably prefab references. So, why do you expect that they wouldn’t be getting the text from the prefabs? Where are you instantiating these things, and assigning references here to something other than the prefabs?

I suspect it only appears to work in the editor because you are, in fact, changing the text of the prefabs. That can be done when running in the editor, but probably not in a build because prefabs get compiled out into the project binary data.

1 Like

Thank you for your reply.
Sorry, I don’t think I provided enough information about the set up. Those public properties in LoadMessenger are references to objects attached to the instantiated prefab, i.e. the game object. I’m not trying to change the text of the original prefabs saved in resources. When I instantiate a prefab as a game object in a scene I am changing the text attached to the game object, and that works fine both in editor and build.

The problem occurs when I try to get a reference to this text from the game object.

The set up of a ContactButton is below:

I have set the Text and Image objects attached to the prefab as references to the public variables in LoadMessenger. Then I instantiate a ContactButton into my scene and give it a name and an avatar.

5084357--500453--contact button2.PNG

My problem is that, once the project is built, variables seem to be passing text from the original ContactButton prefab, not the values I set to the instantiated game objects of ContactButton that I set in the scene. For example those buttons that say ‘John’ and ‘Helen’, I assigned those names to the instantiated button game objects through script.

Now the contact button has the LoadMessenger script attached to it taking in the text and image properties. So I would expect the scenes as I showed in my original post to say John and Helen like this:

5084357--500447--contact3.PNG
5084357--500450--contact4.PNG
Instead as shown in the previous post both scenes show ‘Contact’, the same text as the original prefab ContactButton, not the values ‘John’ and ‘Helen’ I set in script on the game objects.

Bizarrely I can get references to Sprites from Image objects attached to game objects absolutely fine, and those are set up during runtime too. It just seems to have a problem with text.

Well we know that somewhere, you are making an assumption that isn’t true. So I’m trying to probe where that might be. You wrote

but are you 100% certain? We can’t tell from the screen shot you posted. Click on Text (TextMeshProUGUI) in the Contact property of the instance in the hierarchy, and see what it highlights. Does it highlight the one in the hierarchy, or the one in the project?

Though now that I look at your setup: the references are assigned in the prefab, and then you instantiate the prefab, so that ought to properly hook up the references to the new instanced subparts. Still, just to be sure, I’d like to see the code where you do that Instantiate call.

The other thing you can do is, add a Debug.Log call near where you’re getting the unexpected text:

//this is getting original prefab text not actual text but don't know why
CustomiseMessengerInfo.contactName = contact.text.ToString();
Debug.Log("Set contact name to " + contact.text, contact.text.gameObject);

When you run this within the IDE, you can then click on that Debug.Log statement and it will highlight the object it’s getting the text from. I know you say it works fine in the IDE, but I still suspect this is not because it’s using the right object, but because you’re able to change prefabs in the IDE but not at runtime (or something like that). So check it and see if it really is pulling from the object you think it is.

Another trick: where you are assigning the .text of this contact object, also assign to its .gameObject.name. And again, look in the inspector to see if the objects you expect to get renamed, are getting renamed. Or is it renaming your prefab instead?

Or it could be I’m barking up entirely the wrong tree. But somewhere is a false assumption, so you have to just keep checking and rechecking everything, including the “couldn’t possibly be wrong” stuff, until you find it.

1 Like

I tried the debugging techniques you suggested without any luck. I was about to post the script where I instantiate the prefab, and then I had another look at it. I was setting the button text using SetText from the TextMeshPro package, like this:

contact.transform.GetChild(0).gameObject.GetComponent<TextMeshProUGUI>().SetText(name);

I tried changing it to this: contact.transform.GetChild(0).gameObject.GetComponent<TextMeshProUGUI>().text = name;

I built my game and the correct names loaded up!

I also realised I was using SetText in the CustomiseMessgengerInfo script, so I changed it there and that also fixed a similar issue I had where I wasn’t getting text from another game object properly. I made sure to double check by swapping out the both of the lines of code I changed separately with the old code, and rebuilt the project and I’m pretty sure SetText was the culprit.

I’m happy it works, but I’m not too sure why using SetText was causing that problem.

Thank you for all your help!

1 Like

Ah! The problem wasn’t that it was setting it to the wrong text… it was that SetText wasn’t actually rebuilding the text mesh. I ran into this issue once too. SetText sounds like the right thing to call, but nope: the right thing to do is to assign to the .text property, as you discovered.

I’m sorry I didn’t think of this earlier. Great job figuring it out!