Unity Netcode's ClientRpc is not being sent across the network - unity3d

I copy and pasted Unity Netcode's example code from https://docs-multiplayer.unity3d.com/docs/advanced-topics/message-system/clientrpc to test it out. This is my exact code:
public class Test : MonoBehaviour
{
public TMP_Text text;
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
PongClientRpc(Time.frameCount, "hello, world"); // Server -> Client
}
}
[ClientRpc]
void PongClientRpc(int somenumber, string sometext)
{
text.text = $"{somenumber} : {sometext}";
Debug.Log(text.text);
}
}
What I've found is that the function just acts as a normal function whether it's called on the host application or client application, and it is never transmitted across the network. My expectation is that when it is called on the host application, the RPC would be transmitted to the client application and executed there as well, thus reflecting a change in the TMP_Text object, but clearly this is not the case.
Just to check all the boxes, this script is attached to a GameObject that also has a NetworkObject component. For good measure, I tested the TMP_Text object both with and without a NetworkObject component attached. In all cases, any object with a NetworkObject component was properly added to the NetworkManager's network prefabs list.
I'm starting to question if I even understand what an RPC is or how it's supposed to work. Any insights would be greatly appreciated!

This class needs to be derived from NetworkBehavior not MonoBehaviour else it won't be networked.
Make sure to add using Unity.Netcode; at the top of the class.

Related

How to disable the Tracked Pose Driver in a Unity VR Application?

I need to write a VR application that disables HMD positional tracking for a specific situation and then reenable it again.
In the UI it is a simple as ticking and unticking the TrackedPoseDriver shown in the picture below.
How can I do that via Scripting?
I assume I need to use the enabled property of a game object. But I don't know how to grab a hold of this GameObject (or Component).
EDIT: In case this was clear this is GameObject/Component associated to the main camera.
Ok. So I was able to do It.
What I did is I search MonoBehaviour Based Components on the camera and then cast it to a MonoBehaviour once I found the right one. And then used the enabled property. Like this:
Component[] components = Camera.main.GetComponents(typeof(MonoBehaviour));
bool found = false;
foreach(Component component in components) {
string name = component.ToString();
MonoBehaviour mb = (MonoBehaviour) component;
if (name.Contains(TRACK_POSE_DRIVER_NAME)){
mbTrackingPose = mb;
found = true;
break;
}
}
The unique string that the toString() method provided was somethign like (I don't have it on hand) "Main Camera (Unity.XR.TrackedPoseDriver)". So I just made sure that the string had the "TrackedPoseDriver" and stored that as a MonoBehaviour.
I hope this helps someone else.

Found no receiver for incoming ClientRpc on Player(Clone), the server and client should have the same NetworkBehaviour instances [netId=9]

I am using Mirror SDK to implement multiplayer
when I test locally, one instance of build and one instance in unity editor, it works fine.
but If I test by running two builds on separate machines, it gives me this error.
I searched alot, haven't found any solution yet.
any help will be appreciated.
below is my code to use Client RPC
public void CmdSpawn(Vector3 position)
{
ComponentInstance = Instantiate(prefabToSpawn ,position,Quaternion.identity);
NetworkServer.Spawn(ComponentInstance,connectionToClient);
RpcAssignRefrence(ComponentInstance);
}
[ClientRpc]
public void RpcAssignRefrence(GameObject spawnedObject)
{
m_tempObject = spawnedObject.transform;
}

Missing something important with ClientRpc (Unity Mirror)

I'm having an issue with ClientRpc never being called any client objects. I've trolled the internet for hours, but I can't find any clues as to why my implementation isn't working.
I'm following an order of events like so:
Add players in a lobby
Switch scene to the gameplay scene
Generate random tiles on the server
Send tile data to the clients using Rpc for rendering
However, the rendering function never gets called.
NetworkManager.cs
public override void OnServerReady(NetworkConnection conn)
{
base.OnServerReady(conn);
//Make sure they're all ready
for (int i = RoomPlayers.Count - 1; i >= 0; i--)
{
if (!RoomPlayers[i].IsReady)
{
return;
}
}
//Previously add SpawnTiles to OnServerReadied
OnServerReadied?.Invoke(conn);
}
GameManager.cs
private void SpawnTiles(NetworkConnection conn)
{
//Generate rawTiles beforehand
Debug.Log(conn.isReady);
Debug.Log("Entered spawn tiles");
RpcSpawnTiles(rawTiles);
}
[ClientRpc]
public void RpcSpawnTiles(short[] rawTiles)
{
Debug.Log("Client spawning tiles");
}
And this is my output when run on a host:
True
Entered spawn tiles
It appears to never enter the Rpc function :(
Is there something super obvious that I'm missing? My GameManager does have a NetworkID attached to it
There seemed to be a combination of things that I had to do to get it to work- I'm not entirely sure which one worked, but if you are having these problems, these are some of the things I had to check-
Just basic code. Make sure that the appropriate things are being created on the client, host, or server
Make sure that there aren't any race conditions, especially when working with changing scenes. You can call stuff from OnClientSceneChanged and OnServerSceneChanged
As derHugo pointed out, I was not checking to see if my package could even be sent. It turns out that the maximum size that can be sent is 1200 bytes, while I was trying to send 100x100x4 bytes. This error didn't occur when I was testing on the host, only when there was an external client

Best practice to to access components using scripts in Unity?

I am new to Unity so go easy on me. :)
I added an game object with a text field component (via TextMeshProUGUI) to my heads up display in my scene. I want to use this to display various statistics on it for debugging purposes during game play.
I then created a script which I added as a component to the same game object that holds my text component. Is this the best practice? Not sure how else I would get the script to execute.
Once I had my script created, I needed to find the text component as well as some other components in my scene so I could display the debug information. Below you can see how I did it... it feels a little dirty to be searching the entire scene to find these things. Would love some insight on how long-time Unity programmers go about this!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class PlayerDebugStatistics:MonoBehaviour {
TextMeshProUGUI playerDebugStatisticsText;
PlayerCharacterController playerCharacterController;
Health playerHealth;
private void Start() {
// First find the object in the scene named "PlayerDebugStatisticsText" and then get it's TextMeshProUGUI component
this.playerDebugStatisticsText = GameObject.Find("PlayerDebugStatisticsText").GetComponent<TextMeshProUGUI>();
// Get the player character controller
this.playerCharacterController = GameObject.FindObjectOfType<PlayerCharacterController>();
// Get the player health from the player character controller
this.playerHealth = playerCharacterController.GetComponent<Health>();
}
void Update() {
// Update the text every frame
this.playerDebugStatisticsText.SetText(string.Format("{0:N2}", this.playerHealth.currentHealth));
}
}
3 ways
Create an inspector reference to the other object and access it from your script - a public or private (with [SerializeField]) attribute in your script - and drag the component in like in this video: https://youtu.be/dMgQOP7kdxg?t=425
Use the singleton pattern: https://www.youtube.com/watch?v=5p2JlI7PV1w
Use dependency injection - https://github.com/modesttree/Zenject
Your way isn't terrible if you don't do it in the Update() loop, and cache your objects (like it appears you are doing), but if you need that performance in Start(), the above options can help.

Unity3D Text not changing after being set in Start()

I have a Canvas (World Space Render mode) with a Text and a Button component displayed in a tridimensional space (it's a VR app). The canvas instantiated at runtime using a prefab.
I get a reference to the Text object using:
_codeTextLabel = canvasPrefab.transform.Find("CodeTextLabel").gameObject.GetComponent<Text>();
I want to update the text at run-time using:
void Update()
{
_codeTextLabel.text = _codeText;
}
where _codeText is just a variable I update based on specific events.
The problem is that the Text gets updated only the first time, but if I try to change the variable nothing happens. I have tried several combinations and also the method _codeTextLabel.SetAllDirty() but it doesn't work.
The only way to update the text is to re-instantiate the prefab.
Are you instantiating your prefab before setting the values. If you are storing the _codeTextLabel reference before instantiating then your reference will point to the prefab not the runtime object. I can't see the rest of your code, so I can't say for sure. (I would have asked as a comment, but as I'm new I don't have the reputation to do so)
edit: I did a test to try and recreate your problem. I made the following script and it appears to work as expected. CanvasPrefab is a worldspace canvas with a UnityEngine.UI.Text component attached. (The script is attached on an empty game object in the scene btw)
public class ChangeText : MonoBehaviour
{
public GameObject CanvasPrefab;
private GameObject runtimeCanvas;
public string runtimeText = "something";
private Text textRef;
// Start is called before the first frame update
void Start()
{
runtimeCanvas = GameObject.Instantiate(CanvasPrefab);
textRef = runtimeCanvas.GetComponentInChildren<Text>();
}
// Update is called once per frame
void Update()
{
textRef.text = runtimeText;
}
}
as long as you did something wrong, It works absolutely so I guess there are several cases
Failed to do "_codeTextLabel = canvasPrefab.transform.Find("CodeTextLabel").gameObject.GetComponent();"
'_codeTextLabel' lost reference from 'GameObject.
Doesn't change runtimeText' change at all
Subscription of events failed I mean, your updating scripts doesn't get proper event to update that text.
Without codes, this is only thing I can guess for yours so please check above I hope there is case among above.