jeffreylanters / react-unity-webgl

React Unity WebGL provides a modern solution for embedding Unity WebGL builds in your React Application while providing advanced APIs for two way communication and interaction between Unity and React.
https://react-unity-webgl.dev
Apache License 2.0
1.75k stars 162 forks source link

Unable to Send Message while Unity is not Instantiated. #474

Open heymangal opened 1 year ago

heymangal commented 1 year ago

Please avoid duplicates

Language and Compiler

Vanilla JavaScript

What environment are you using?

Local Development Server

When does your problem occur?

When the Unity App is running

What does your problem relate to?

The problem seems React related

React-Unity-WebGL Version

9.3.0

React Version

17.0.39

Unity Version

2021.5f1

What happened?

Hello team, I am sorry to say that I am facing runtime issues within react, I have been trying to solve it for some days but without success.

  1. Image 1 https://drive.google.com/file/d/1X51vftlknpMB-kGqxvlNWk8a5f8Sbzm4/view?usp=sharing

WebGL Warning Log : When Call Unity Function Using Bridge : use-unity-context.js:121 Unable to Send Message while Unity is not Instantiated. (anonymous) @ `use-unity-context.js:121`

  1. I call Unity React functions directly from Unity Listener. https://drive.google.com/file/d/1tttT2moMFzI8SN7M1LmG8zv4RNq7oI89/view?usp=share_link

3.And this function is called from the listener. And within it Unity communicates with SendMessage https://drive.google.com/file/d/1xc00kEi81-y-yA3bX0wnyWNL230fZYvg/view?usp=sharing

  function ClickedConnectVenly() 
  {
    sendMessage(
      "Persistent",
      "Loader", false
    );
  }

But I get This Message in WebGL Log Console and not Send Message Unity Function: (All The Parameters are Verified)

WebGL Warning Log : When Call Unity Function Using Bridge :
**use-unity-context.js:121 Unable to Send Message while Unity is not Instantiated.
(anonymous) @ `use-unity-context.js:121**`
  1. Calling Function From React Button https://drive.google.com/file/d/1pNFwVxxZq9_ELmniYFHDWUc91YuUUTWE/view?usp=sharing

    And now , if I call this function from react button then it works fine. But if I call from unity listener, it doesn't give me function call inside unity.

I don't know if this is an issue or my coding.

Help me Please !

Reproducible test case

No response

Would you be interested in contributing a fix?

stevenzipgen commented 1 year ago

I got the same issue migrating from version 8 to 9. It looks like the problem is that while you register a listener, that listener triggers SendMessage while the Unity component is still loading, I made it work by triggering SendMessage inside a useEffect that depends on an isLoaded state that becomes true once the component has been loaded, I already had that implementation with my own hook, however, I can see that UnityContextHook has the isLoaded property, that one should work

dheerajvora commented 1 year ago

@stevenzipgen can you send me the reference and code hint on how to use UnityContextHook.

stevenzipgen commented 1 year ago

//this will throw: Unable to Send Message while Unity is not Instantiated

` const unityContext = useUnityContext( { loaderUrl: renderer.loader.js, dataUrl: renderer.data.gz, frameworkUrl: renderer.framework.js.gz, codeUrl: renderer.wasm.gz, streamingAssetsUrl: debug, });

    useEffect(() => {
        unityContext.addEventListener("AppLoaded", (params: string) => {
            unityContext.sendMessage("interface", "SetStep", JSON.stringify({
                step: StateStep.BoundaryConfig
            }));
            }
        );
    }, []);`

//Storing a state to know when the app was loaded

`const [rendererLoaded, setRendererLoaded] = useState(false);

    useEffect(() => {
    unityContext.addEventListener("AppLoaded", (params: string) => {
        setRendererLoaded(true);
            }
        );
    }, []);

    useEffect(() => {
        if (rendererLoaded) {
            unityContext.sendMessage("interface", "SetStep", JSON.stringify({
                step: StateStep.BoundaryConfig
            }));
        }           
    },[rendererLoaded])`
KhoiFishGST commented 1 year ago

This may help some other people:

We had this error prop up when we disabled the splash screen and Unity logo. We re-enabled splash screen (disabled Unity logo though), and bam --- sendMessage works again.

We're on 2022.2.1f1. Hope this helps.

Joshvdw commented 1 year ago

Hi there, getting this issue too - but mine is when I try to sendMessage() or addEventListener() in a component different to the main app.tsx, where my Unity build is being rendered.

Any clue as to what I'm doing wrong?

chismer commented 1 year ago

I have the same problem. "Unable to Send Message while Unity is not Instantiated."

Unity 2021.3.23 react-unity-webgl 9.4.0

What is the correct method to call sendMessage? Is it a library error or how are we calling it? It seems that unityInstance is always null.

TheConBot commented 1 year ago

Same issue, code looks like:

var SendUnityMessage: ((arg0: string, arg1: string, arg2: string) => void) | null = null;
  function LoadUnityApp() {
    var baseUrl = "/chat/WebGL/CamillaTest"
    var buildUrl = baseUrl + "/Build";

    const { unityProvider, sendMessage } = useUnityContext({
      loaderUrl: buildUrl + "/CamillaTest.loader.js",
      dataUrl: buildUrl + "/CamillaTest.data",
      frameworkUrl: buildUrl + "/CamillaTest.framework.js",
      codeUrl: buildUrl + "/CamillaTest.wasm",
      streamingAssetsUrl: baseUrl + "/StreamingAssets",
    });

    sendMessage("BrowserPipe", "OnPacket", "test");
    if(!SendUnityMessage) {
      SendUnityMessage = sendMessage;
    }
    return <Unity unityProvider={unityProvider} />;
  }

And then elsewhere:

 onMessage: (packet: CustomPacket) => {
     if(SendUnityMessage) {
          SendUnityMessage('BrowserPipe', 'OnPacket', JSON.stringify(packet));
        }

Whenever I try to send a packet over to Unity I will get the warning, however the test call I make in the LoadUnityApp() does eventually work a couple of times. Very puzzling.

siddie commented 1 year ago

Same problem using sendMessage from the hook.

react-unity-webgl: 9.4.2 unity: 2022.3.6f1

const {unityProvider, isLoaded, loadingProgression, addEventListener, removeEventListener, sendMessage, takeScreenshot, unload, requestFullscreen} = useUnityContext({ loaderUrl: Build/${projectName}.loader.js, dataUrl: Build/${projectName}.data, frameworkUrl: Build/${projectName}.framework.js, codeUrl: Build/${projectName}.wasm, streamingAssetsUrl: "StreamingAssets", productName: "My Product", productVersion: "1.0.0", companyName: "Developer" });

pjb6510 commented 1 year ago

I got the same issue, and I fixed the issue with this code I'm using socket.io

const { unityProvider, sendMessage, isLoaded } = useUnityContext({
// ...
});

const socketIoClientRef = useRef<null | Socket>(null);

useEffect(() => {
    if (!isLoaded) {
      return;
    }

    socketIoClientRef.current = io('/');

    socketIoClientRef.current.on(
      'some-event',
      ({ messageId, value }) => {
        if (messageId === 'some-message') {
          sendMessage('something','something',value);
        }
      },
    );

    return () => {
      socketIoClientRef.current?.disconnect();
    };
}, [isLoaded]);
shubhamkes commented 8 months ago

isLoaded has to be added to the dependency of useEffect. And boom it will work

OmarBayoumy01 commented 5 months ago

i have the same issue but it works with this code

const onStop = async (recordedBlob) => {
    console.log('recordedBlob is: ', recordedBlob);
    setResult(null)
    try {
      setLoading(true);
      const formData = new FormData();
      formData.append('audioFile', recordedBlob.blob, 'audio.mp3');
      formData.append('interviewId', id);
      const response = await Api.post('ai-interview/single/talk', formData);
      setResult(response.data)
      if (isLoaded) {
        console.log("Sending");
        sendMessage("WebManager", "PlayAudio", `${VITE_API_BASE_URL}/${response?.data?.audioPath?.audioFilePath}`);
        console.log("done!");
      }
    } catch (error) {
      console.error('Error uploading audio:', error);
    } finally {
      setLoading(false);
      setChangeIcon(true)
    }
  };
  useEffect(() => {
    if (result?.audioPath?.audioFilePath && isLoaded) {
      console.log("sending");
      sendMessage("WebManager", "PlayAudio", `${VITE_API_BASE_URL}/${result?.audioPath?.audioFilePath}`);
      console.log("done!")
    }
  }, [result?.audioPath?.audioFilePath]);
rizalarsal commented 4 months ago

i have the same issue after follow the tutorial. after a little bit of frustration, i notice in tutorial use callback with empty dependencies [], after adding isLoaded dependency its solved [isLoaded] . Here is the code :

const handleUCommand = useCallback((dat:any) => {
      sendMessage("Comsys","SetName","its work !");
  }, [isLoaded]);

so i think everything is fine, just need to double check your code called on proper state.