Owner of the fired missile question

I am firing a missile on key down using:

networkView.RPC("SpawnMissileRequest", RPCMode.Server, transform.position + transform.forward * 0.7f,  transform.rotation, transform.forward * speed);

The server then sends an RPC to all clients to instantiate this missile:

[RPC]
void SpawnMissileRequest(Vector3 position, Quaternion rotation, Vector3 force)
{
	NetworkViewID nView = Network.AllocateViewID();
	networkView.RPC("SpawnMissile", RPCMode.All, position, rotation, force, nView);
}

The clients then create the missile:

[RPC]
void SpawnMissile(Vector3 position, Quaternion rotation, Vector3 force, NetworkViewID nVid)
{
		
	Rigidbody instantiatedProjectile = (Rigidbody)Instantiate(projectile, position, rotation);
		
	NetworkView nView = (NetworkView)instantiatedProjectile.GetComponent(typeof(NetworkView));
	nView.viewID = nVid;
		
	if (Network.isServer){
		instantiatedProjectile.AddForce(force, ForceMode.Impulse);	
	}
		
	CapsuleCollider parentCollider = (CapsuleCollider)playerBody.GetComponent(typeof(CapsuleCollider));
	BoxCollider missileCollider = (BoxCollider)instantiatedProjectile.GetComponent(typeof(BoxCollider));
	Physics.IgnoreCollision(parentCollider, missileCollider);
		
}

And here is how I am handling the damage when it collides and the “DestroyRocket” RPC is called from the server side to all clients, therefore the clients are calculating the damage for themselves:

[RPC]
void DestroyRocket(Vector3 explosionPosition, Quaternion rotation){
		
	GameObject instantiatedExplosion = (GameObject)Instantiate (explosion, explosionPosition, rotation);
		
        Collider[] colliders = Physics.OverlapSphere (explosionPosition, explosionRadius);
		
	foreach (Collider hit in colliders) {
		if (hit.rigidbody) {
			hit.rigidbody.AddExplosionForce (explosionPower, explosionPosition, explosionRadius, 3.0f);
		}	
			
		Vector3 closestPoint = hit.ClosestPointOnBounds (explosionPosition);
		float distance = Vector3.Distance (closestPoint, explosionPosition);
			
		float damage = 0;
		if (distance < explosionRadius) {
				
			if (distance == 0)
				distance = 1;
				
			damage = Mathf.Floor(explosionDamage / Mathf.Ceil (distance));
		}
			
		if (hit.collider.gameObject.tag == "Player"  hit.collider.gameObject.networkView.isMine) {
			Player playerHealth = (Player)hit.GetComponent("Player");
			
			playerHealth.SendMessage("ApplyDamageToPlayer", damage, SendMessageOptions.DontRequireReceiver);

		}
			
	}


	Destroy(gameObject);
		
}

My question is, when the missile collides with a player, how can I get a reference to the “shooter” of the missile so that I can add a certain amount of points to the player that fired the missile?

Well I ended up passing the reference of the player that fires (transform.root.networkView.viewID) within the “SpawnMissleRequest”.

Then when the missile gets instantiated in the “SpawnMissile” function, I did this:

instantiatedProjectile.transform.GetComponent<Rocket>().rocketOwner = owner;

the “owner” being the “transform.root.networkView.viewID” value.

The Rocket script had a public variable that I set to the owner, then when it explodes I just refer to that value that was saved.

If this is the incorrect way of doing it, or if there is an easier way, let me know.

Here’s the problem with this solution: even though you’re sending the explosion position, you cannot with 100% certainty guarantee that all player/enemy objects are going to be in the exact same place in every client simulation at the time DestroyRocket() is received and executed. If that damage radius calculation is even a point off, it could create a slew of discrepancies down the road to the point where some people are alive in some client’s simulations and dead in others.

If I were you, I would piggyback health updates on your main player serializer component (whatever one does pos/rot/firing and all that junk) but only when it changes, as to not add any unnecessary bytes to your updates. Unfortunately you can’t write your own bitstreams with the built-in networking, though. (Hello, uLink!)

OIh sorry, I probably should of mentioned that when I calculate my damage on my local, I update all clients with my new calculated health using an RPC within my “ApplyDamageToPlayer” function.

networkView.RPC("updateHealth", RPCMode.All, currentHealth);

But yes, I did run into that issue, and this fixed it. Thanks for your input regardless!

I’m actually having some issues with my previous problem about who owns a missile etc. This is what I have for my “ApplyDamageToPlayer” function (the relevant portion at least):

public void ApplyDamageToPlayer(int damage, NetworkViewID enemyMissile){
	currentHealth -= damage;
		
	if (Network.isClient){
		networkView.RPC ("RequestAddCash", RPCMode.Server, 10.0f, enemyMissile);
	}else{
		RequestAddCash(10.0f, enemyMissile);
	}
}

Here is the RequestAddCash function:

[RPC]
void RequestAddCash(float amount, NetworkViewID enemyMissile){

	networkView.RPC ("AddCash", enemyMissile.owner, 10.0f);

}

And the AddCash function:

[RPC]
void AddCash(float amount){
	myCash += amount;
}

Basically what it’s supposed to do is, everytime a missile hits another player, the player that send the missle gets “10 points”. But the client that gets hit, is the one requesting from the server to add ‘10 points’ to the specified player.

Now the problem I run into is, if the “RequestAddCash” function is called by the server, it will error out, because the server from what I can tell, can’t send an RPC to itself. I’m having wayy to much trouble with this. Any ideas how I’m supposed to go about doing this?

I’m starting to get really confused on what’s going on here, for example, like I mentioned before, I’m assigning a networkView,viewID to the missile that’s being launched, so that when it hit’s someone, that someone can send an RPC call back to the player that launched it to add 10 points to themselves.

After having no success in getting this to work I tried somehting a little bit more simple. On my “ApplyDamageToPlayer” funciton I’m sending the RPC to everyone, so I have:

public void ApplyDamageToPlayer(int damage, NetworkViewID fromPlayer){
	currentHealth -= damage;
        
        //here fromPlayer equals the networkView.viewID that has been passed via the missile object
	networkView.RPC ("AddCash", RPCMode.All, 10.0f, fromPlayer);
}

And on the RPC that I called, I’m going…:

[RPC]
void AddCash(float amount, NetworkViewID fromPlayer){
	if (fromPlayer == transform.root.networkView.viewID)
		myCash += amount;
}

Therefore, if my networkView.viewID is equal to the “fromPlayer”, that means I shot the missile, logically that would make sense and it should work… which it does… kind of

So here is what happens:

If I’m the server, I fire the missile, the missile stores my networkView.viewID into a variable called “rocketOwner” which “fromPlayer” ends up inheriting. Now, when I fire the missle, and it hits myself, it gets to the “AddCash” function where:

fromPlayer = 1
transform.root.networkView.viewID = 1

Looks good, but! if I fire the missile and I hit the client, the client does the same and calls the RPC “AddCash” along with the “fromPlayer” value, which should be 1, and it is. So then the client does a RPC call with RPCMode.All (therefore everyone gets that call), except this time within the “AddCash” function for the server, the values are:

fromPlayer = 1
transform.root.networkView.viewID = 150

How is it that my networkView.viewID changed to 150?? Therefore, I get no cash added to my player (the server). This is insanely confusing!!

Ok so I figured it out…:

public void ApplyDamageToPlayer(int damage, NetworkViewID fromPlayer){
	currentHealth -= damage;
		
		
	if (Network.isClient){
		networkView.RPC ("AddCashRequest", RPCMode.Server, 10.0f, fromPlayer);
	}else{
		AddCashRequest(10.0f, fromPlayer);
	}
}
[RPC]
void AddCashRequest(float amount, NetworkViewID player){
	if (player.owner.ToString() != "0"){
		networkView.RPC("AddCash", player.owner, amount, player);
	}else{
		AddCash(10.0f, player);
	}
}
[RPC]
void AddCash(float amount, NetworkViewID fromPlayer){
	Transform myTransform = NetworkView.Find(fromPlayer).transform;
	myTransform.GetComponent<Player>().myCash += amount;
		
}

I give up with this forum.