I have a sync var health. if one player is in the server and he takes damage and then some one joines it still shows the other person to have full health how do i do this? Confused tbh
The connecting Player should be getting the latest state of the SyncVar on connect. Can you post your code?
yes sure
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;
public class Health : NetworkBehaviour
{
public const int maxHealth = 100;
public bool destroyOnDeath;
//UI
public GameObject HealthText;
public GameObject DamgeImage;
private Shooting ShootingScript;
[SyncVar(hook = "OnChangeHealth")] <------------------- the sync var i use fpr health
public int currentHealth = maxHealth;
public RectTransform healthBar;
//creates an array of all the spawn points
private NetworkStartPosition[] spawnPoints;
private Camera_Script cameraScript;
private Vector3 DeathPoint;
void Start()
{
DeathPoint = new Vector3(0f, -150f, 0f);
if (isLocalPlayer)
{
cameraScript = gameObject.GetComponent<Camera_Script>();
spawnPoints = FindObjectsOfType<NetworkStartPosition>();
ShootingScript = GetComponent<Shooting>();
}
}
void Update()
{
if (!isLocalPlayer)
{
return;
}
if (isLocalPlayer)
{
//calls a respawn buy setting there health to zero by calling it to the server;
if (Input.GetKeyDown(KeyCode.Y))
{
CmdRespawn();
}
}
}
//Shoud ONLY be called by server!
public bool TakeDamage(int amount)
{
if (!isServer)
return false;
//takes the input amount from the shooting script and deducts the damage
currentHealth -= amount;
//Handels Death
if (currentHealth <= 0)
{
Death();
if (destroyOnDeath)
{
return false;
}
return true;
}
return false;
}
public void Death()
{
if (!isServer)
return;
//If the gameobject has destroy on death checks then dont respawn it!
if (destroyOnDeath)
{
Destroy(gameObject);
}
else
{
transform.position = DeathPoint;
StartCoroutine(WaitForRespawn());
// CanvasScript.canvas.WriteGameStatusText("Resapawning");
//Sets the max health to 100 maybe need to change later on when comes to respawning for rounds
// currentHealth = maxHealth;
// called on the Server, invoked on the Clients
// RpcRespawn();
}
}
// called when the varable health is changed
void OnChangeHealth(int currentHealth)
{
if(isLocalPlayer)
{
CanvasScript.canvas.SetHealth(currentHealth);
if (currentHealth == 0)
{
CanvasScript.canvas.WriteGameStatusText("You ARE DEAD!!!!!!!");
cameraScript.UpdateCamerasTo(false);
gameObject.GetComponent<PlayerController>().enabled = false;
gameObject.GetComponent<SwitchGuns>().enabled = false;
}
if (currentHealth == 100)
{
CanvasScript.canvas.WriteGameStatusText("");
cameraScript.UpdateCamerasTo(true);
gameObject.GetComponent<PlayerController>().enabled = true;
gameObject.GetComponent<SwitchGuns>().enabled = true;
}
}
healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
if (!isClient)
{
HealthText.GetComponent<Text>().text = currentHealth.ToString();
}
}
[ClientRpc]
void RpcRespawn()
{
if (isLocalPlayer)
{
// Set the spawn point to origin as a default value
Vector3 spawnPoint = Vector3.zero;
// If there is a spawn point array and the array is not empty, pick one at random
if (spawnPoints != null && spawnPoints.Length > 0)
{
spawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)].transform.position;
}
// Set the player’s position to the chosen spawn point
//!!!!! Change this later for when there dead display ui and make invisiable or add to spectators teamf or example
transform.position = spawnPoint;
}
}
[Command]
public void CmdRespawn()
{
TakeDamage(1000);
}
IEnumerator WaitForRespawn()
{
yield return new WaitForSeconds(3f);
//Sets the max health to 100 maybe need to change later on when comes to respawning for rounds
currentHealth = maxHealth;
if (isLocalPlayer)
// called on the Server, invoked on the Clients
RpcRespawn();
}
//IEnumerator WaitForRespawnClient()
//{
// yield return new WaitForSeconds(3f);
// CanvasScript.canvas.WriteGameStatusText("");
// cameraScript.UpdateCamerasTo(true);
// gameObject.GetComponent<PlayerController>().enabled = true;
// gameObject.GetComponent<SwitchGuns>().enabled = true;
// }
}
forgot to put in comments didnt know if you would get a notifation
Is the actual variable inaccurate or does your UI simply not update? Looks like you’re only updating the UI when it uses the hook, and it wouldn’t be used unless the health changed.
How would u recommended i update the UI? I mad a gif of what happens not very clear but i think your get it
https://gyazo.com/923a16e22809c2e906327fa98f9ed480
Move your UI updates to a separate method, call it from the hook and also call it from OnStartClient().
When OnStartClient() fires, it is guaranteed to have the SyncVars ready and correct, so just tell the UI to update and voila.
so make a method like UpdateUI() and in that move the stuff that handels the ui think and then in the network manager add something to call updateui() when they connect?
i moved the stuff out the rpc but now what do i put here
public override void OnStartClient(NetworkClient client)
{
base.OnStartClient(client);
something .getgameobject etc
}
shall i use a loop and get every gameobejct with tag or is there someway to use the client in the overirde method.
Basically, something like this.
[SyncVar(hook = "OnHealthChange")]
public float Health;
public Text MyHealthUi;
public void OnStartClient()
{
// syncvar is already updated and ready at this point.
UpdateUi();
}
public void OnHealthChange()
{
if (Health <= 0) Debug.Log("Im dead.");
UpdateUi();
}
public void UpdateUi()
{
// use the syncvar
MyHealthUi.text = Health.ToString();
}
OnStartClient reference.
Ahh so its in the same script not the network manager ok ill give
I did this however it doesnt update at all
}
UpdateHealthBar();
//healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
// if (!isClient)
//{
// HealthText.GetComponent().text = currentHealth.ToString();
//}
}
void UpdateHealthBar()
{
healthBar.sizeDelta = new Vector2(currentHealth, healthBar.sizeDelta.y);
if (!isClient)
{
HealthText.GetComponent().text = currentHealth.ToString();
}
}
public override void OnStartClient()
{
base.OnStartClient();
UpdateHealthBar();
}
Looks like you already understand, but for anyone else reading this thread that is not understanding the issue, syncvars themselves should have the correct value when the new player joins, but syncvar hooks are not called. They are only called when the value changes, but a new player joining and getting the latest value is not considered a syncvar value change. So you have to do whatever you need to ensure things that use the syncvar are setup correctly yourself.
Yer i understand the logic now the sync var just stores the value but you need to disaply it, but its now only updating on the server and not on any clients do i need it in a clientRpc?
Haven’t saw it in a spaghetti code, but make sure that you’re actually applying value inside SyncVar hook method to the SyncVar itself. Otherwise it won’t work.