This is my entire code for the projectile now, particularly take a look at ExplodeServerRpc
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using System;
public class Fire : NetworkBehaviour
{
[SerializeField] float objectSpeed = 30f;
[SerializeField] float explosionRadius = 3f;
public float damage = 5f;
private LayerMask layer = -1;
private Camera mainCamera;
private float cameraHalfWidth;
private float cameraHalfHeight;
//public ulong id;
//public ulong ownerID;
private bool outside = false;
//public void SetID(ulong i)
//{
// id = i;
// //SetIDServerRpc(i);
// //SetIDClientRpc(i);
//}
public void ChangeOrientation(Vector3 direction, float angle)
{
// If we are the owner, then apply the change directly
if (OwnerClientId == NetworkManager.LocalClientId)
{
UpdateOrientation(direction, angle);
}
else
{
// If we are a server or host, send the change in orientation to the owner
if (NetworkManager.IsServer)
{
ServerSendUpdateOrientationToOwner(direction, angle);
}
else
{
// Otherwise, send the change in orientation to the server
// (This would only happen if the server was a host and we were targeting the host's owner objet or
// this non-owner client was trying to apply the change...not sure if your game/logic allows that or not)
ChangeOrientationServerRpc(direction, angle);
}
}
}
private void ServerSendUpdateOrientationToOwner(Vector3 direction, float angle)
{
if (!NetworkManager.IsServer)
{
Debug.LogWarning($"Client-{NetworkManager.LocalClientId} is invoking the server only change orientation method! (ignoring)");
return;
}
// Only send to the owner by setting the target client id list to only the owner's identifier
var clientRpcParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = new List<ulong>() { OwnerClientId }
}
};
// Send the message to the owner
ChangeOrientationClientRpc(direction, angle, clientRpcParams);
}
[ServerRpc(RequireOwnership = false)]
private void ChangeOrientationServerRpc(Vector3 direction, float angle, ServerRpcParams serverRpcParams = default)
{
// Just a good idea to make sure you are not receiving messages from the owner (in case any future changes introduce a bug like this)
if (serverRpcParams.Receive.SenderClientId == OwnerClientId)
{
Debug.LogWarning($"Client-{NetworkManager.LocalClientId} is also the owner but it also called {nameof(ChangeOrientationServerRpc)}! (ignoring)");
return;
}
// If the server is not the owner, then forward the message to the appropriate client.
// (This would only happen if another non-owner client was trying to apply the change...not sure if your game/logic allows that or not)
if (OwnerClientId != NetworkManager.LocalClientId)
{
ServerSendUpdateOrientationToOwner(direction, angle);
}
else
{
// Otherwise, we are the owner so apply the update to orientation
UpdateOrientation(direction, angle);
}
}
[ClientRpc]
private void ChangeOrientationClientRpc(Vector3 direction, float angle, ClientRpcParams clientRpcParams)
{
// Always have a check to assure you are sending to the right target
if (NetworkManager.LocalClientId != OwnerClientId)
{
Debug.LogWarning($"Received a change in orientation message for ownerid-{OwnerClientId} on client-{NetworkManager.LocalClientId}! (ignoring)");
return;
}
// Otherwise, we are the owner so apply the update to orientation
UpdateOrientation(direction, angle);
}
/// <summary>
/// Break out the desired action/script logic to a separate method
/// This reduces the complexity and if you need to tweak how orientation is updated you only have to change one place
/// </summary>
private void UpdateOrientation(Vector3 direction, float angle)
{
transform.rotation = Quaternion.LookRotation(Vector3.forward, direction);
transform.Rotate(0, 0, angle);
Rigidbody2D rb = GetComponent<Rigidbody2D>();
rb.velocity = transform.up * objectSpeed;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Player"))
{
if (outside && collision.GetComponent<NetworkObject>().OwnerClientId != GetComponent<NetworkObject>().OwnerClientId)
{
ExplodeServerRpc();
}
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.CompareTag("Player")) outside = true;
}
[ServerRpc(RequireOwnership = false)]
void ExplodeServerRpc()
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, explosionRadius, layer);
foreach (Collider2D hitCollider in colliders)
{
if (hitCollider.CompareTag("Player"))
{
hitCollider.GetComponent<PlayerMovement>().DealDamage(damage);
}
}
Destroy(gameObject);
}
// Start is called before the first frame update
void Start()
{
mainCamera = Camera.main;
cameraHalfWidth = mainCamera.orthographicSize * mainCamera.aspect;
cameraHalfHeight = mainCamera.orthographicSize;
}
// Update is called once per frame
void Update()
{
//delay -= Time.deltaTime;
if (transform.position.x < -cameraHalfWidth + (transform.localScale.x / 2) || transform.position.x > cameraHalfWidth - (transform.localScale.x / 2)
|| transform.position.y < -cameraHalfHeight + (transform.localScale.y) || transform.position.y > cameraHalfHeight - (transform.localScale.y))
ExplodeServerRpc();
}
}
Now seems like it’s behaving better, projectiles are no longer freezing at the last moment, but sometimes the projectiles from the non host player don’t damage the host player after being destroyed, with this error appearing
[Netcode] Deferred messages were received for a trigger of type OnSpawn with key 52, but that trigger was not received within within 1 second(s).
UnityEngine.Debug:LogWarning (object)
Unity.Netcode.NetworkLog:LogWarning (string) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.7.1/Runtime/Logging/NetworkLog.cs:28)
Unity.Netcode.DeferredMessageManager:PurgeTrigger (Unity.Netcode.IDeferredNetworkMessageManager/TriggerType,ulong,Unity.Netcode.DeferredMessageManager/TriggerInfo) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.7.1/Runtime/Messaging/DeferredMessageManager.cs:97)
Unity.Netcode.DeferredMessageManager:CleanupStaleTriggers () (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.7.1/Runtime/Messaging/DeferredMessageManager.cs:82)
Unity.Netcode.NetworkManager:NetworkUpdate (Unity.Netcode.NetworkUpdateStage) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.7.1/Runtime/Core/NetworkManager.cs:69)
Unity.Netcode.NetworkUpdateLoop:RunNetworkUpdateStage (Unity.Netcode.NetworkUpdateStage) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.7.1/Runtime/Core/NetworkUpdateLoop.cs:185)
Unity.Netcode.NetworkUpdateLoop/NetworkPostLateUpdate/<>c:<CreateLoopSystem>b__0_0 () (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.7.1/Runtime/Core/NetworkUpdateLoop.cs:268)