Edit
Okay, so I partially solved the problem by adding a rigid body component to the capsule. I read somewhere that apparently you have to have one in order to move on the server.
Problem 2
The next problem I have is that I can now move a capsule that is spawned by the client fine and the host can move it as well as many times as they like. The problem I am getting now is that when the host spawns a capsule the client cannot move it at all and I get a sort of glitch effect on the client side and the capsule still doesn't move on the host side. Is there a reason why it would only work one way and not the other way around? I thought at first it might have to do with Spawn vs SpawnWithClientAuthority but that doesn't seem to make a difference.
Project Summary
I have a pretty simple multiplayer project, all I want to do is have one player host and the other join as a client. Once they are joined together the two players can spawn a capsule and then when the user clicks on a capsule. They should be able to pick it up and move it around the scene and the other player should be able to see this action. I can get both players to connect to the server and spawn their own capsule and both players can see this. The movement script is done as well. However, it is only transmitted on the host side. When the client picks up the object it does not update on the server.
Problem
I have done a bit of debugging and have found that when I call the command on the client it is not being executed at all through line breaks and simple debug statements.
Code
public void OnInputClicked(InputClickedEventData eventData)
{
Debug.Log("clicked");
if (isLocalPlayer)
{
if (Physics.Raycast(transform.position, direction: transform.forward, hitInfo: out hit, maxDistance: range))
{
Debug.Log("Hit capsule");
objectID = GameObject.Find(hit.transform.name);
objNetId = objectID.GetComponent<NetworkIdentity>();
CmdAssignAuthority(objNetId);
Debug.Log("Cmd done");
}
else
{
//else if the player is releasing the object we want to release authority
if (objNetId != null)
{
CmdAssignAuthority(objNetId);
}
}
}
[Command]
void CmdAssignAuthority(NetworkIdentity target)
{
Debug.Log("inside cmd");
NetworkConnection current = target.clientAuthorityOwner;
if (current != null && current != connectionToClient)
{
target.RemoveClientAuthority(current);
target.AssignClientAuthority(connectionToClient);
}
else
{
if (current != null)
{
target.RemoveClientAuthority(current);
}
if (current == null)
{
target.AssignClientAuthority(connectionToClient);
}
}
}
Question
Am I calling this command correctly? The script is attached to a player prefab and the capsule prefab contains a network id and a network transform. I am pretty new to Unet and this feels like a noob mistake.
Related
I'm trying to create a weapon system. Created a new script for weapon. Everything seems to be working fine other than the bullet. It stays in the same place when I press the fire button, doesn't move at all. The bullet is a prefab.
private void Fire()
{
if (Input.GetButtonDown("Fire1"))
{
firingCoroutine = StartCoroutine(FireContinuously());
myAnimator.SetBool("Shoot", true);
}
else if (Input.GetButtonUp("Fire1"))
{
StopCoroutine(firingCoroutine);
myAnimator.SetBool("Shoot", false);
}
}
private void Pistol()
{
GameObject laser = Instantiate(bullet, firePoint.position, firePoint.rotation);
laser.GetComponent<Rigidbody2D>().velocity = new Vector2(projectileSpeed * direction, 0);
}
Sadly I cannot post comments so I'm going to have to post an answer instead, even though I'm more of asking for clarity.
You haven't really shared enough information as to where Pistol() gets executed and if you have even set up the "Fire1" button in "Edit –> Project Settings –> Input", i.e. if those if-statement bodies even get executed. From what I gather though your bullet gets spawned correctly but simply doesn't move?... if so, then you may simply have a case of your bullet Rigidbody2D being marked kinematic or static.
I'm making a game where players are put onto plates and random events happen to the plates/players. I've gone through a multitude of different networking solutions like UNET, Mirror, Mirror+Steamworks P2P but none of them really worked well (main issue being not being able to join via IP) so I settled on Photon. After Punv2 just wouldn't work on my project (an error in PhotonEditor.CS) I just used Punv1 which is working perfectly for the most part.
The issue right now is that I'm trying to spawn players on their owned plates but they only spawn on the first plate despite each plate being owned by a player (each plate has a script that specifies which player 'owns' it. This is being set correctly). This only seems to happen when I try to test with a real player/client. If I create a fake player by just spawning in the prefab and then running it, both players will be moved to their correct plate so it seems to be a networking issue.
Here's the code responsible for moving the players to their plates.
foreach (GameObject plate in spawnedPlates)
{
//Here we loop through each plate, get the player assigned to it and move the player to that plate.
GameObject player = plate.GetComponent<Plate>().assignedTo;
PlayerClientControl playerController = player.GetComponent<PlayerClientControl>(); // originally for UNET/Mirror. Left in incase I need it(had an RPC function that moved the player).
player.transform.position = plate.transform.position + new Vector3(0, 4, 0);
}
What am I doing wrong?
EDIT:
It seems they ARE being moved to the correct positions (or atleast, it's trying to move them to the correct position) via a debug print statement that prints where they are trying to be teleported to further cementing that this is a networking issue but I have no idea how to fix it.
I assume it's something to with host/client synchronization? If anyone could shed some light on this, that'd be great because I'm pulling my hair out over this.
If you inspect the player objects at runtime, it will probably give you a clue. I had the same and in my case I had InputAction attached to my players (taken from unity StarterAssets). The first player in the game was assigned keyboard and the second a controller. I solved it by disabling all the inputaction and enabling the one of the localplayer:
private void Awake()
{
photonView = GetComponent<PhotonView>();
if (photonView.IsMine)
{
// take control of the user input by disabling all and then enabling mine
var players = FindObjectsOfType<Player>();
foreach (Player player in players)
{
player.GetComponent<PlayerInput>().enabled = false;
}
GetComponent<PlayerInput>().enabled = true;
I have a simple FPS where a player can fire a gun. I want the clients to see the bullet holes. I am trying to accomplish this by invoking a server side method when the client tries to fire the gun. The server side method should then raycast from the players camera and spawn a bullet hole for everyone to see..
I can get this to work partially by passing the player as a parameter to the server method. However, since my raycasting needs to be done based off the player camera, the bullet holes end up appearing at character height, since it's using the player and not the camera.
It won't allow me to pass a camera through. I have also tried creating an empty game object called bullet spawn and passing that through but I was getting a "object reference not set to instance of an object." This same error seems to surface for any Child element of the player I attempt to pass to the server side method.
I am unsure of the right way to accomplish this.
void Update()
{
if (isLocalPlayer)
{
if (Input.GetButton("Fire1"))
{
CmdFire(BulletSpawn);
}
}
}
[Command]
void CmdFire(GameObject Player)
{
Ray shooterRay = new Ray(Player.transform.position, Player.transform.forward);
if (Physics.Raycast(shooterRay, out Hit, 10000))
{
Debug.Log("player hit");
GameObject Bullet_Hole = (GameObject)Instantiate(BulletHole_Prefab, Hit.point, Quaternion.FromToRotation(Vector3.up, Hit.point));
NetworkServer.Spawn(Bullet_Hole);
}
}
Think about it this way. What is it that you need to fire your weapon? You need the firing point and the firing direction (in your simple case). So try to pass just that information. Your CmdFire should look like void CmdFire(Vector3 firingPoint, Vector3 firingDirection). Remember that when you pass the player gameobject, it gets serialized and sent to the server which causes a lot of unneeded network traffic. Stick to value types and simple objects for commands.
This is what ultimately led me to the solution. Thank you for the advice. I simply passed two Vector3 parameters as you suggested which represent the raycast position and direction. I can now shoot from both client and server and see the bullet holes on both as well. Here is the code that fixed it in case anyone runs into this later on:
void Update() {
if (isLocalPlayer) {
if (Input.GetButton("Fire1")) {
Vector3 FiringSpot = PlayerCam.transform.position;
Vector3 FireDirection = PlayerCam.transform.forward;
CmdFire(FiringSpot, FireDirection);
}
}
}
[Command]
void CmdFire(Vector3 firingPoint, Vector3 firingDirection) {
Ray shooterRay = new Ray(firingPoint, firingDirection);
if (Physics.Raycast(shooterRay, out Hit, 10000)) {
GameObject Bullet_Hole = (GameObject)Instantiate(bullet_Hole_Prefab, Hit.point, Quaternion.FromToRotation(Vector3.up, Hit.point));
NetworkServer.Spawn(Bullet_Hole);
Destroy(Bullet_Hole, 10);
}
}
So, I'm doing an FPS game in Unity5, and some days ago I started looking at multiplayer tutorials at the official site of Unity.
However, I changed some bit of the code to fit in an FPS, but I had a problem when started doing this. The client's camera moved fine, but the host's one did not: It used the client's camera to see, but his player to move, sort of a third-person view.
All players have the same code, and the camera has a Network Identity with Local Player Authority turned on. Also, it has this C# script:
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class VisionControl : NetworkBehaviour {
void Start () {
Cursor.lockState = CursorLockMode.Locked;
}
void Update () {
if(!isLocalPlayer){
return;
}
transform.Rotate (new Vector3 (-Input.GetAxis ("Mouse Y")*5.0f,0.0f,0.0f));
}
}
Your camera should not have a network identiy.
It is used only by the local clients to get a perspective of the game world, so they do not need to be networked.
Each camera exists on the current client.for the current client only.
Each game instance should have 1 camera running, that of the Local Player.
Attach a simple non-networked camera component to your player prefab and test again.
Fixed! I removed the VisionControl script and putted this one on the player's movement script:
public override void OnStartLocalPlayer ()
{
if (isLocalPlayer) {
FindObjectOfType<Camera> ().gameObject.transform.position = this.transform.position+new Vector3(0f,0.5f,0f);
FindObjectOfType<Camera>().gameObject.transform.SetParent (this.transform);
}
}
I have a question about RPC and Photon PUN.
I have 1 GameObject in my game that calls an RPC method. This game object contains a C# script (that contains the RPC method) and the PhotonView component with/without (is should be the same) the observed script and the ObserveOption equals to Off.
I have a character which have to shoot to a cube. This cube has the previously described script and component attach to it.
The RPC is sent once (when the cube has been collided with a projectile) but in my scene I have many Cube which should receive the message because I have to decrease the health of the hit cube. The problem is that only 1 Cube receive the RPC call (The RPC is caught by the first instantiated object at the start of the game) but the RPC should be received by all the cube (is that right?) in my scene.
The cubes are exactly the same but they have a different photonView ID (rightly) so we could check whether the hit cube to which decrease the health is the right one.
This is the significant part of the code:
public static void reduceHealthRPC(float damage, int viewID)
{
photonView.RPC("reduceHealth", PhotonTargets.All, damage, viewID);
}
[RPC]
public void reduceHealth(float damage, int viewID)
{
if(this._viewID != viewID)
{
Debug.Log ("The view ID is not mine. My viewID is: " + _viewID + ", and the one which is coming form RPC is: " + viewID);
return;
}
currentHealth -= damage;
Debug.Log("My life is: " + currentHealth);
}
Please help me to unerstand what I'm doing wrong.
Thank you.
If you need call RPC for all cubes, do it for every cube.
Currently you are calling RPC only for object referenced by static 'photonView' variable. Depending on how it's initialized, RPC called on that object.
I might be late ,but try PhotonTargets.AllBuffered,that will make the RPC call run on players that join later .
Might be super late but have you tried this? cube.cs is attached to all cubes.
in main.cs
cube[] allCubes = FindObjectsOfType<cube>();
for (int x = 0; x < allCubes.length; x++)
allCubes[x].reduceHealthRPC(dam,id);
this will send the code to all cubes with one target id, if this is your goal but you are much better to just rpc on the individual cube.